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,