diff --git a/packages/client-runtime/src/state/subagentRuntime.test.ts b/packages/client-runtime/src/state/subagentRuntime.test.ts index d366d7f0d4ee..cf65cc4385fa 100644 --- a/packages/client-runtime/src/state/subagentRuntime.test.ts +++ b/packages/client-runtime/src/state/subagentRuntime.test.ts @@ -181,6 +181,38 @@ describe("foldSubagentActivities", () => { expect(agents[0]!.completedAt).toBe("2026-08-01T11:00:00.000Z"); }); + it("maps cancelled status to a terminal cancelled state", () => { + const agents = fold([ + activity("task.started", { taskId: "task-cancelled", taskType: "local_agent" }), + activity("task.completed", { + taskId: "task-cancelled", + status: "cancelled", + summary: "user cancelled", + }), + ]); + expect(agents).toHaveLength(1); + const agent = agents[0]!; + expect(agent.status).toBe("cancelled"); + expect(agent.result).toBe("user cancelled"); + expect(agent.completedAt).not.toBeNull(); + }); + + it("maps interrupted status to a terminal interrupted state", () => { + const agents = fold([ + activity("task.started", { taskId: "task-interrupted", taskType: "local_agent" }), + activity("task.completed", { + taskId: "task-interrupted", + status: "interrupted", + summary: "context window exceeded", + }), + ]); + expect(agents).toHaveLength(1); + const agent = agents[0]!; + expect(agent.status).toBe("interrupted"); + expect(agent.result).toBe("context window exceeded"); + expect(agent.completedAt).not.toBeNull(); + }); + it("reactivation increments the run count and clears result/error", () => { const agents = fold([ activity("task.started", { taskId: "task-4", taskType: "local_agent" }), diff --git a/packages/client-runtime/src/state/subagentRuntime.ts b/packages/client-runtime/src/state/subagentRuntime.ts index e441de32db48..962d74d003ca 100644 --- a/packages/client-runtime/src/state/subagentRuntime.ts +++ b/packages/client-runtime/src/state/subagentRuntime.ts @@ -430,6 +430,8 @@ const TASK_COMPLETED_STATUS: ReadonlyMap = new Ma ["completed", "completed"], ["failed", "failed"], ["stopped", "interrupted"], + ["cancelled", "cancelled"], + ["interrupted", "interrupted"], ]); const KNOWN_STATUSES: ReadonlySet = new Set([ diff --git a/packages/contracts/src/providerRuntime.ts b/packages/contracts/src/providerRuntime.ts index 01a8f9ad8f83..773fb6641da2 100644 --- a/packages/contracts/src/providerRuntime.ts +++ b/packages/contracts/src/providerRuntime.ts @@ -670,7 +670,7 @@ export type TaskUpdatedPayload = typeof TaskUpdatedPayload.Type; const TaskCompletedPayload = Schema.Struct({ taskId: RuntimeTaskId, - status: Schema.Literals(["completed", "failed", "stopped"]), + status: Schema.Literals(["completed", "failed", "stopped", "cancelled", "interrupted"]), summary: Schema.optional(TrimmedNonEmptyStringSchema), usage: Schema.optional(Schema.Unknown), typedUsage: Schema.optional(RuntimeTaskUsage),