From 3f30ef5b47e2c1e9b5e5324bd62973853cb57cd1 Mon Sep 17 00:00:00 2001 From: Matthew Wright Date: Sat, 4 Jul 2026 17:28:30 -0500 Subject: [PATCH] persist sessionId on failure so a failed run stays resumable runTaskAgent persisted the engine sessionId only after the success/failure branch, so a failed run lost its session and a retry had to rebuild context from scratch. Persist it before the branch, and return telemetry on the failure path too. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../agent-3-task/src/run-task-agent.spec.ts | 9 +++++++++ .../packages/agent-3-task/src/run-task-agent.ts | 17 ++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/orchestrator-v2/packages/agent-3-task/src/run-task-agent.spec.ts b/orchestrator-v2/packages/agent-3-task/src/run-task-agent.spec.ts index d6c4725..a166584 100644 --- a/orchestrator-v2/packages/agent-3-task/src/run-task-agent.spec.ts +++ b/orchestrator-v2/packages/agent-3-task/src/run-task-agent.spec.ts @@ -132,6 +132,15 @@ describe("runTaskAgent", () => { then: { engine_failure_returned }, }); + test("persists sessionId and returns telemetry when the engine fails (resumable retry)", { + given: { failing_engine, valid_state_context }, + when: { task_agent_run }, + then: { + session_id_is_persisted, + telemetry_is_returned, + }, + }); + test("fails when engine throws", { given: { throwing_engine, valid_state_context }, when: { task_agent_run }, diff --git a/orchestrator-v2/packages/agent-3-task/src/run-task-agent.ts b/orchestrator-v2/packages/agent-3-task/src/run-task-agent.ts index 58e5de3..41e0e25 100644 --- a/orchestrator-v2/packages/agent-3-task/src/run-task-agent.ts +++ b/orchestrator-v2/packages/agent-3-task/src/run-task-agent.ts @@ -48,13 +48,8 @@ export async function runTaskAgent( return { outcome: "failed", message }; } - if (!engineResult.success) { - return { - outcome: "failed", - message: engineResult.lastMessage ?? "Engine execution failed", - }; - } - + // Persist the sessionId before branching on the outcome, so a failed run stays + // resumable — a retry can --resume instead of rebuilding context from scratch. if (engineResult.sessionId !== undefined) { await ctx.setState({ ...workItem.state, @@ -62,6 +57,14 @@ export async function runTaskAgent( }); } + if (!engineResult.success) { + return { + outcome: "failed", + message: engineResult.lastMessage ?? "Engine execution failed", + telemetry: engineResult.stats ?? undefined, + }; + } + return { outcome: "completed", message: engineResult.lastMessage ?? undefined,