From 694925c0e502207f9396bffa2ced361845260151 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 07:33:35 +0000 Subject: [PATCH 1/2] test(server): a failed delegated task keeps its child's final report Reproduces #23412: subagentResultForRun returns only the failure message when a run fails after its final assistant message. AI-assisted; verified with the tests and tools listed above. --- .../SubagentProjection.test.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/apps/server/src/orchestration-v2/SubagentProjection.test.ts b/apps/server/src/orchestration-v2/SubagentProjection.test.ts index 9b3ebfc02f62..4964c916d30a 100644 --- a/apps/server/src/orchestration-v2/SubagentProjection.test.ts +++ b/apps/server/src/orchestration-v2/SubagentProjection.test.ts @@ -393,6 +393,50 @@ it("exposes the provider failure rather than a progress message from the failed assert.isNull(result.messageId); }); +it("keeps the final report of a run that failed after its turn ended", () => { + const { projection, run } = taskFixture(); + const failedRun = { ...run, status: "failed" as const }; + const artifacts = makeSubagentConversationArtifacts({ + messageId: MessageId.make("report"), + turnItemId: TurnItemId.make("report"), + threadId: parentThreadId, + rootNodeId: NodeId.make("root"), + providerThreadId: null, + providerTurnId: null, + nativeItemRef: null, + role: "assistant", + text: "Review complete: no blocking issues.", + ordinal: 1, + now: childCreatedAt, + }); + const failure = { + class: "unknown" as const, + message: "Connection failed repeatedly", + code: null, + retryable: false, + }; + const result = subagentResultForRun( + { + ...projection, + messages: [{ ...artifacts.message, runId: run.id }], + turnItems: [ + { ...artifacts.turnItem, runId: run.id }, + { + ...artifacts.turnItem, + id: TurnItemId.make("error"), + ordinal: 2, + type: "error", + runId: run.id, + failure, + }, + ], + }, + failedRun, + ); + assert.include(result.text, failure.message); + assert.include(result.text, "Review complete: no blocking issues."); +}); + it("orders a task's assistant messages by turn item, not by timestamps", () => { const { projection, run } = taskFixture(); const at = DateTime.makeUnsafe("2026-07-24T10:05:00.000Z"); From 99cbad42822146d899271313aa5f4901c388c19c Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 07:37:22 +0000 Subject: [PATCH 2/2] fix(server): a failed delegated task keeps its child's final report A delegated task that failed after its child wrote its final assistant message reported only the error, so task_status and the completion notice dropped the report. Failed runs now return the error followed by the last assistant message written before it, labelled as coming from the failed run. Fixes pingdotgg/t3code#23412 AI-assisted; verified with the tests and tools listed above. --- .../src/orchestration-v2/SubagentProjection.test.ts | 1 + .../provider-core/src/server/subagentProjection.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/server/src/orchestration-v2/SubagentProjection.test.ts b/apps/server/src/orchestration-v2/SubagentProjection.test.ts index 4964c916d30a..29deb33a3ae6 100644 --- a/apps/server/src/orchestration-v2/SubagentProjection.test.ts +++ b/apps/server/src/orchestration-v2/SubagentProjection.test.ts @@ -409,6 +409,7 @@ it("keeps the final report of a run that failed after its turn ended", () => { ordinal: 1, now: childCreatedAt, }); + if (artifacts.turnItem.type !== "assistant_message") throw new Error("Expected assistant item"); const failure = { class: "unknown" as const, message: "Connection failed repeatedly", diff --git a/packages/provider-core/src/server/subagentProjection.ts b/packages/provider-core/src/server/subagentProjection.ts index 62145567f665..699067abb3e6 100644 --- a/packages/provider-core/src/server/subagentProjection.ts +++ b/packages/provider-core/src/server/subagentProjection.ts @@ -227,8 +227,16 @@ export function subagentResultForRun( .filter((item) => item.runId === run.id && item.type === "error") .toSorted((left, right) => right.ordinal - left.ordinal)[0] : undefined; + const reportBeforeFailure = + failure !== undefined && turnItem !== null && turnItem.ordinal < failure.ordinal + ? (message?.text ?? turnItem.text) + : undefined; const text = - (failure?.type === "error" ? failure.failure.message : undefined) ?? + (failure?.type === "error" + ? reportBeforeFailure === undefined + ? failure.failure.message + : `${failure.failure.message}\n\nLast assistant message before the run failed:\n\n${reportBeforeFailure}` + : undefined) ?? message?.text ?? turnItem?.text ?? (run.status === "completed"