@@ -447,6 +447,11 @@ export class CodexAppServerEventProjector {
|
447 | 447 | if (!delta) { |
448 | 448 | return; |
449 | 449 | } |
| 450 | +this.rememberAssistantPhase(readItem(params.item)); |
| 451 | +const phase = readString(params, "phase"); |
| 452 | +if (phase) { |
| 453 | +this.assistantPhaseByItem.set(itemId, phase); |
| 454 | +} |
450 | 455 | if (!this.assistantStarted) { |
451 | 456 | this.assistantStarted = true; |
452 | 457 | await this.params.onAssistantMessageStart?.(); |
@@ -456,10 +461,13 @@ export class CodexAppServerEventProjector {
|
456 | 461 | this.assistantTextByItem.set(itemId, text); |
457 | 462 | if (this.isCommentaryAssistantItem(itemId)) { |
458 | 463 | this.emitCommentaryProgress({ itemId, text }); |
| 464 | +} else if (this.shouldStreamAssistantPartial(itemId)) { |
| 465 | +await this.params.onPartialReply?.({ text, delta }); |
459 | 466 | } |
460 | 467 | // Codex app-server can emit multiple agentMessage items per turn, including |
461 | 468 | // intermediate coordination/progress prose. Keep those deltas internal until |
462 | | -// turn completion chooses the last assistant item as the user-visible reply. |
| 469 | +// their phase identifies terminal answer text or turn completion chooses the |
| 470 | +// last assistant item as the user-visible reply. |
463 | 471 | } |
464 | 472 | |
465 | 473 | private async handleReasoningDelta( |
@@ -970,6 +978,10 @@ export class CodexAppServerEventProjector {
|
970 | 978 | return this.assistantPhaseByItem.get(itemId) === "commentary"; |
971 | 979 | } |
972 | 980 | |
| 981 | +private shouldStreamAssistantPartial(itemId: string): boolean { |
| 982 | +return this.assistantPhaseByItem.get(itemId) === "final_answer"; |
| 983 | +} |
| 984 | + |
973 | 985 | private emitCommentaryProgress(params: { itemId: string; text: string }): void { |
974 | 986 | const progressText = params.text.replace(/\s+/g, " ").trim(); |
975 | 987 | if ( |
|