stitchkit 0.85.2 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +243 -0
  2. package/README.md +3 -0
  3. package/dist/agent-runtime/agent-tool.d.ts +25 -0
  4. package/dist/agent-runtime/agent-tool.d.ts.map +1 -0
  5. package/dist/agent-runtime/child-tools.d.ts +69 -0
  6. package/dist/agent-runtime/child-tools.d.ts.map +1 -0
  7. package/dist/agent-runtime/children.d.ts +113 -0
  8. package/dist/agent-runtime/children.d.ts.map +1 -0
  9. package/dist/agent-runtime/coding-tool-contract.d.ts +29 -0
  10. package/dist/agent-runtime/coding-tool-contract.d.ts.map +1 -1
  11. package/dist/agent-runtime/coding-tool-refusals.d.ts +2 -0
  12. package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
  13. package/dist/agent-runtime/coding-tool-shell.d.ts.map +1 -1
  14. package/dist/agent-runtime/coding-tools.d.ts +1 -0
  15. package/dist/agent-runtime/coding-tools.d.ts.map +1 -1
  16. package/dist/agent-runtime/control-schema.d.ts +17 -0
  17. package/dist/agent-runtime/control-schema.d.ts.map +1 -1
  18. package/dist/agent-runtime/conversations.d.ts +11 -0
  19. package/dist/agent-runtime/conversations.d.ts.map +1 -1
  20. package/dist/agent-runtime/event-schema.d.ts +34 -0
  21. package/dist/agent-runtime/event-schema.d.ts.map +1 -1
  22. package/dist/agent-runtime/event-search-tools.d.ts +53 -0
  23. package/dist/agent-runtime/event-search-tools.d.ts.map +1 -0
  24. package/dist/agent-runtime/event-search.d.ts +23 -0
  25. package/dist/agent-runtime/event-search.d.ts.map +1 -0
  26. package/dist/agent-runtime/fault-bench.d.ts +45 -0
  27. package/dist/agent-runtime/fault-bench.d.ts.map +1 -0
  28. package/dist/agent-runtime/observability.d.ts +6 -0
  29. package/dist/agent-runtime/observability.d.ts.map +1 -1
  30. package/dist/agent-runtime/projections.d.ts +69 -0
  31. package/dist/agent-runtime/projections.d.ts.map +1 -0
  32. package/dist/agent-runtime/provider-failure.d.ts +5 -1
  33. package/dist/agent-runtime/provider-failure.d.ts.map +1 -1
  34. package/dist/agent-runtime/provider-origin.d.ts +12 -0
  35. package/dist/agent-runtime/provider-origin.d.ts.map +1 -0
  36. package/dist/agent-runtime/retry-policy.d.ts +27 -0
  37. package/dist/agent-runtime/retry-policy.d.ts.map +1 -0
  38. package/dist/agent-runtime/run-execution.d.ts +0 -9
  39. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  40. package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -1
  41. package/dist/agent-runtime/runtime.d.ts +15 -0
  42. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  43. package/dist/agent-runtime/sandbox.d.ts +66 -0
  44. package/dist/agent-runtime/sandbox.d.ts.map +1 -0
  45. package/dist/agent-runtime/schedule-tools.d.ts +35 -0
  46. package/dist/agent-runtime/schedule-tools.d.ts.map +1 -0
  47. package/dist/agent-runtime/schedules.d.ts +63 -0
  48. package/dist/agent-runtime/schedules.d.ts.map +1 -0
  49. package/dist/agent-runtime/schemas.d.ts +9 -0
  50. package/dist/agent-runtime/schemas.d.ts.map +1 -1
  51. package/dist/agent-runtime/spill.d.ts +24 -0
  52. package/dist/agent-runtime/spill.d.ts.map +1 -0
  53. package/dist/agent-runtime/sqlite-purge.d.ts.map +1 -1
  54. package/dist/agent-runtime/sqlite.d.ts +26 -0
  55. package/dist/agent-runtime/sqlite.d.ts.map +1 -1
  56. package/dist/agent-runtime/state-slots.d.ts +48 -0
  57. package/dist/agent-runtime/state-slots.d.ts.map +1 -0
  58. package/dist/agent-runtime/state-tools.d.ts +58 -0
  59. package/dist/agent-runtime/state-tools.d.ts.map +1 -0
  60. package/dist/agent-runtime/store-driver.d.ts +13 -0
  61. package/dist/agent-runtime/store-driver.d.ts.map +1 -1
  62. package/dist/agent-runtime/store-events.d.ts +829 -0
  63. package/dist/agent-runtime/store-events.d.ts.map +1 -0
  64. package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts +6 -0
  65. package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts.map +1 -0
  66. package/dist/agent-runtime/store.d.ts +45 -0
  67. package/dist/agent-runtime/store.d.ts.map +1 -1
  68. package/dist/agent-runtime/terminal-commit.d.ts +1 -1
  69. package/dist/agent-runtime-browser.js +5 -3
  70. package/dist/agent-runtime-coding-tools.js +144 -15
  71. package/dist/agent-runtime-harness.js +12 -11
  72. package/dist/agent-runtime-sqlite-bun.d.ts +1 -1
  73. package/dist/agent-runtime-sqlite-bun.d.ts.map +1 -1
  74. package/dist/agent-runtime-sqlite-bun.js +5 -4
  75. package/dist/agent-runtime-sqlite-node.d.ts +1 -1
  76. package/dist/agent-runtime-sqlite-node.d.ts.map +1 -1
  77. package/dist/agent-runtime-sqlite-node.js +5 -4
  78. package/dist/agent-runtime-testing.d.ts +3 -0
  79. package/dist/agent-runtime-testing.d.ts.map +1 -0
  80. package/dist/agent-runtime-testing.js +156 -0
  81. package/dist/agent-runtime.d.ts +16 -2
  82. package/dist/agent-runtime.d.ts.map +1 -1
  83. package/dist/agent-runtime.js +1632 -156
  84. package/dist/application.js +14 -14
  85. package/dist/cli.js +6 -6
  86. package/dist/{index-fwbkp2jn.js → index-0vfdh685.js} +2 -2
  87. package/dist/{index-5z8tezpx.js → index-0ydchz76.js} +3 -3
  88. package/dist/{index-3ds42w1w.js → index-1szetq6f.js} +33 -4
  89. package/dist/{index-2jg7b11j.js → index-35aefxby.js} +879 -424
  90. package/dist/index-3yrqvza8.js +964 -0
  91. package/dist/{index-fq492hg0.js → index-5wezxcxx.js} +238 -161
  92. package/dist/index-9553432s.js +26 -0
  93. package/dist/{index-27487ay5.js → index-9hw9eq48.js} +4 -4
  94. package/dist/index-cnyk6te3.js +77 -0
  95. package/dist/index-gskm1k5a.js +50 -0
  96. package/dist/{index-4hk633vz.js → index-hkm6wysp.js} +9 -2
  97. package/dist/{index-dx9xehwt.js → index-kc6h6hg0.js} +1 -1
  98. package/dist/{index-x15ss2dx.js → index-p1b1y93x.js} +3 -0
  99. package/dist/{index-mgtxfe6b.js → index-r159gjwy.js} +8 -1
  100. package/dist/{index-s4ckmrac.js → index-rcgsnrr6.js} +3 -3
  101. package/dist/{index-dggwnnjv.js → index-wn9cb82y.js} +1 -1
  102. package/dist/index-z1m86vc8.js +334 -0
  103. package/dist/{index-ff0kcqvp.js → index-z2452tsw.js} +3 -3
  104. package/dist/internal/sqlite.d.ts +13 -0
  105. package/dist/internal/sqlite.d.ts.map +1 -1
  106. package/dist/testing/agent-store-conformance.d.ts.map +1 -1
  107. package/dist/testing.js +89 -80
  108. package/dist/tool-invoker.js +4 -4
  109. package/dist/tools/internal/surface-projector.d.ts.map +1 -1
  110. package/dist/tools/manifest.d.ts +16 -0
  111. package/dist/tools/manifest.d.ts.map +1 -1
  112. package/dist/tools.d.ts +1 -1
  113. package/dist/tools.d.ts.map +1 -1
  114. package/dist/tools.js +10 -8
  115. package/llms-full.txt +373 -16
  116. package/package.json +6 -1
  117. package/dist/index-66nxrgy0.js +0 -554
  118. package/dist/index-y2s6h5bf.js +0 -83
@@ -1,18 +1,19 @@
1
+ import {
2
+ messageOf
3
+ } from "./index-p13mwz16.js";
4
+ import {
5
+ AgentRuntimeEventSchema,
6
+ agentDurableEventId
7
+ } from "./index-hkm6wysp.js";
1
8
  import {
2
9
  advanceToolChronology,
3
10
  assistantStatus,
4
11
  canProjectToolChronology,
12
+ canonicalAgentJson,
5
13
  createToolChronology,
6
14
  isAssistantHistoryEvidence,
7
15
  isCompleteAgentHistoryTurn
8
- } from "./index-y2s6h5bf.js";
9
- import {
10
- createBoundedSinkManager
11
- } from "./index-wnfk50r0.js";
12
- import {
13
- AgentRuntimeEventSchema,
14
- agentDurableEventId
15
- } from "./index-4hk633vz.js";
16
+ } from "./index-z1m86vc8.js";
16
17
  import {
17
18
  AgentAssistantPlaceholderSchema,
18
19
  AgentJsonObjectSchema,
@@ -23,19 +24,145 @@ import {
23
24
  AgentRunSchema,
24
25
  AgentSnapshotSchema,
25
26
  runStateForTerminalReason
26
- } from "./index-x15ss2dx.js";
27
+ } from "./index-p1b1y93x.js";
28
+ import {
29
+ createBoundedSinkManager
30
+ } from "./index-wnfk50r0.js";
27
31
  import {
28
32
  isAgentToolError
29
33
  } from "./index-3xnq72rz.js";
30
34
  import {
31
35
  ToolExecutionControlError,
32
36
  isToolExecutionControlError
33
- } from "./index-dggwnnjv.js";
37
+ } from "./index-wn9cb82y.js";
34
38
  import {
35
39
  isRecord,
36
40
  transportResult
37
41
  } from "./index-77fekveh.js";
38
42
 
43
+ // src/agent-runtime/terminal-commit.ts
44
+ class AgentRuntimeConflictError extends Error {
45
+ constructor(operation) {
46
+ super(`Agent runtime store conflict during ${operation}`);
47
+ this.name = "AgentRuntimeConflictError";
48
+ }
49
+ }
50
+ function appliedSnapshot(result, operation) {
51
+ if (result.outcome === "applied" || result.outcome === "duplicate")
52
+ return result.snapshot;
53
+ throw new AgentRuntimeConflictError(operation);
54
+ }
55
+ function viewOfSnapshot(snapshot, runId, retainedAssistant) {
56
+ const run = snapshot.runs.find((candidate) => candidate.id === runId);
57
+ const assistant = snapshot.messages.find((message) => message.id === run?.assistantMessageId) ?? retainedAssistant;
58
+ return {
59
+ snapshotVersion: snapshot.version,
60
+ conversationId: snapshot.conversationId,
61
+ ...run && { run },
62
+ ...assistant && { assistant }
63
+ };
64
+ }
65
+ function viewOfRun(view, conversationId) {
66
+ return {
67
+ snapshotVersion: view.snapshotVersion,
68
+ conversationId,
69
+ run: view.run,
70
+ ...view.assistant && { assistant: view.assistant }
71
+ };
72
+ }
73
+ function canonicalTerminal(view) {
74
+ const { run, assistant } = view;
75
+ if (!run?.terminalReason)
76
+ return;
77
+ if (view.conversationId !== run.conversationId || !assistant || assistant.id !== run.assistantMessageId || assistant.conversationId !== run.conversationId || assistant.runId !== run.id || assistant.role !== "assistant" || assistant.status !== assistantStatus(run.terminalReason)) {
78
+ throw new AgentRuntimeConflictError("terminal result projection");
79
+ }
80
+ return {
81
+ snapshotVersion: view.snapshotVersion,
82
+ run,
83
+ assistant,
84
+ reason: run.terminalReason,
85
+ committedByCaller: false,
86
+ ...run.terminalPolicyName && { policyName: run.terminalPolicyName },
87
+ ...run.usage && { usage: run.usage }
88
+ };
89
+ }
90
+ function interruptedCandidate(candidate, run, now) {
91
+ const reason = candidate.reason === "superseded" ? "superseded" : "interrupted";
92
+ const hasInterruptControl = candidate.assistant.parts.some((part) => part.type === "control" && part.reason === "run-interrupted");
93
+ const parts = hasInterruptControl ? candidate.assistant.parts : [
94
+ ...candidate.assistant.parts,
95
+ AgentMessagePartSchema.parse({ type: "control", reason: "run-interrupted" })
96
+ ];
97
+ return {
98
+ ...candidate.usage && { usage: candidate.usage },
99
+ run,
100
+ assistant: AgentMessageSchema.parse({
101
+ ...candidate.assistant,
102
+ status: assistantStatus(reason),
103
+ parts,
104
+ updatedAt: now().toISOString()
105
+ }),
106
+ reason
107
+ };
108
+ }
109
+ function canRetryTerminal(current, previous, runtimeEpoch) {
110
+ return (current.state === "running" || current.state === "interrupt_requested") && current.ownerId === runtimeEpoch && current.fencingToken === previous.fencingToken;
111
+ }
112
+ var TERMINAL_COMMIT_ATTEMPTS = 32;
113
+ async function commitAgentRunTerminal(input) {
114
+ let candidate = input.candidate;
115
+ for (let attempt = 0;attempt < TERMINAL_COMMIT_ATTEMPTS; attempt += 1) {
116
+ const committed = await input.store.commitRunTerminal({
117
+ conversationId: candidate.run.conversationId,
118
+ runId: candidate.run.id,
119
+ expectedRevision: candidate.run.revision,
120
+ ownerId: input.runtimeEpoch,
121
+ ...candidate.run.fencingToken !== undefined && {
122
+ fencingToken: candidate.run.fencingToken
123
+ },
124
+ assistant: candidate.assistant,
125
+ reason: candidate.reason,
126
+ ...candidate.policyName && { policyName: candidate.policyName },
127
+ ...candidate.usage && { usage: candidate.usage },
128
+ ...candidate.absorb?.length && { absorb: candidate.absorb }
129
+ });
130
+ if (committed.outcome === "applied") {
131
+ const terminal2 = canonicalTerminal(viewOfSnapshot(committed.snapshot, candidate.run.id));
132
+ if (!terminal2)
133
+ throw new AgentRuntimeConflictError("terminal result projection");
134
+ const absorbed = committed.snapshot.runs.filter((run) => run.absorbedIntoRunId === candidate.run.id);
135
+ return {
136
+ ...terminal2,
137
+ committedByCaller: true,
138
+ ...absorbed.length > 0 && { absorbed }
139
+ };
140
+ }
141
+ if (committed.outcome === "duplicate") {
142
+ const terminal2 = canonicalTerminal(viewOfSnapshot(committed.snapshot, candidate.run.id, committed.assistant));
143
+ if (!terminal2)
144
+ throw new AgentRuntimeConflictError("terminal result projection");
145
+ return terminal2;
146
+ }
147
+ if (committed.outcome !== "conflict") {
148
+ throw new AgentRuntimeConflictError("terminal commit");
149
+ }
150
+ const latest = await input.store.loadRun({
151
+ conversationId: candidate.run.conversationId,
152
+ runId: candidate.run.id
153
+ });
154
+ const terminal = latest ? canonicalTerminal(viewOfRun(latest, candidate.run.conversationId)) : undefined;
155
+ if (terminal)
156
+ return terminal;
157
+ const current = latest?.run;
158
+ if (!current || !canRetryTerminal(current, candidate.run, input.runtimeEpoch)) {
159
+ throw new AgentRuntimeConflictError("terminal commit");
160
+ }
161
+ candidate = current.state === "interrupt_requested" ? interruptedCandidate(candidate, current, input.now) : { ...candidate, run: current };
162
+ }
163
+ throw new AgentRuntimeConflictError("terminal commit");
164
+ }
165
+
39
166
  // src/agent-runtime/context-refusal.ts
40
167
  class AgentContextOverflowError extends Error {
41
168
  name = "AgentContextOverflowError";
@@ -686,128 +813,232 @@ function composeAgentPrompt(sections) {
686
813
  };
687
814
  }
688
815
 
689
- // src/agent-runtime/terminal-commit.ts
690
- class AgentRuntimeConflictError extends Error {
691
- constructor(operation) {
692
- super(`Agent runtime store conflict during ${operation}`);
693
- this.name = "AgentRuntimeConflictError";
816
+ // src/agent-runtime/provider-failure.ts
817
+ var BY_STATUS = {
818
+ 402: "insufficient-credits",
819
+ 404: "model-unavailable",
820
+ 408: "timeout",
821
+ 413: "context-overflow",
822
+ 429: "rate-limited"
823
+ };
824
+ var BY_MESSAGE = [
825
+ [/insufficient|not enough credit|payment required|quota exceeded/i, "insufficient-credits"],
826
+ [/rate.?limit|too many requests|slow down/i, "rate-limited"],
827
+ [
828
+ /no endpoints found|model not found|unknown model|no allowed providers/i,
829
+ "model-unavailable"
830
+ ],
831
+ [/context length|maximum context|too many tokens|prompt is too long/i, "context-overflow"],
832
+ [/timed? ?out|deadline exceeded|etimedout/i, "timeout"],
833
+ [/abort|cancell?ed/i, "cancelled"]
834
+ ];
835
+ var RETRYABLE = new Set([
836
+ "rate-limited",
837
+ "timeout",
838
+ "insufficient-credits",
839
+ "stream-cut"
840
+ ]);
841
+
842
+ class AgentProviderStreamCutError extends Error {
843
+ reason = "stream-cut";
844
+ constructor(message = "Provider stream ended before a terminal part") {
845
+ super(message);
846
+ this.name = "AgentProviderStreamCutError";
694
847
  }
695
848
  }
696
- function appliedSnapshot(result, operation) {
697
- if (result.outcome === "applied" || result.outcome === "duplicate")
698
- return result.snapshot;
699
- throw new AgentRuntimeConflictError(operation);
849
+ function statusOf(value) {
850
+ if (!isRecord(value))
851
+ return;
852
+ for (const key of ["statusCode", "status", "code"]) {
853
+ const candidate = value[key];
854
+ if (typeof candidate === "number" && candidate >= 400 && candidate < 600)
855
+ return candidate;
856
+ }
857
+ const nested = value.cause ?? value.response ?? value.error;
858
+ return nested === value ? undefined : statusOf(nested);
700
859
  }
701
- function viewOfSnapshot(snapshot, runId, retainedAssistant) {
702
- const run = snapshot.runs.find((candidate) => candidate.id === runId);
703
- const assistant = snapshot.messages.find((message) => message.id === run?.assistantMessageId) ?? retainedAssistant;
860
+ function classifyProviderFailure(error) {
861
+ if (error instanceof AgentProviderStreamCutError) {
862
+ return { reason: "stream-cut", retryable: true, evidence: "none" };
863
+ }
864
+ const status = statusOf(error);
865
+ const byStatus = status === undefined ? undefined : BY_STATUS[status];
866
+ if (byStatus) {
867
+ return {
868
+ reason: byStatus,
869
+ status,
870
+ retryable: RETRYABLE.has(byStatus),
871
+ evidence: "status"
872
+ };
873
+ }
874
+ const message = messageOf(error);
875
+ for (const [pattern, reason] of BY_MESSAGE) {
876
+ if (pattern.test(message)) {
877
+ return {
878
+ reason,
879
+ ...status !== undefined && { status },
880
+ retryable: RETRYABLE.has(reason),
881
+ evidence: "message"
882
+ };
883
+ }
884
+ }
704
885
  return {
705
- snapshotVersion: snapshot.version,
706
- conversationId: snapshot.conversationId,
707
- ...run && { run },
708
- ...assistant && { assistant }
886
+ reason: "unknown",
887
+ ...status !== undefined && { status },
888
+ retryable: false,
889
+ evidence: "none"
709
890
  };
710
891
  }
711
- function viewOfRun(view, conversationId) {
712
- return {
713
- snapshotVersion: view.snapshotVersion,
714
- conversationId,
715
- run: view.run,
716
- ...view.assistant && { assistant: view.assistant }
717
- };
892
+ function isToolResultFailure(output) {
893
+ const parsed = typeof output === "string" ? parseJson(output) : output;
894
+ if (!isRecord(parsed))
895
+ return false;
896
+ if ("error" in parsed)
897
+ return true;
898
+ return isRecord(parsed.value) && "error" in parsed.value;
718
899
  }
719
- function canonicalTerminal(view) {
720
- const { run, assistant } = view;
721
- if (!run?.terminalReason)
900
+ function parseJson(value) {
901
+ try {
902
+ return JSON.parse(value);
903
+ } catch {
722
904
  return;
723
- if (view.conversationId !== run.conversationId || !assistant || assistant.id !== run.assistantMessageId || assistant.conversationId !== run.conversationId || assistant.runId !== run.id || assistant.role !== "assistant" || assistant.status !== assistantStatus(run.terminalReason)) {
724
- throw new AgentRuntimeConflictError("terminal result projection");
725
905
  }
726
- return {
727
- snapshotVersion: view.snapshotVersion,
728
- run,
729
- assistant,
730
- reason: run.terminalReason,
731
- committedByCaller: false,
732
- ...run.terminalPolicyName && { policyName: run.terminalPolicyName },
733
- ...run.usage && { usage: run.usage }
734
- };
735
906
  }
736
- function interruptedCandidate(candidate, run, now) {
737
- const reason = candidate.reason === "superseded" ? "superseded" : "interrupted";
738
- const hasInterruptControl = candidate.assistant.parts.some((part) => part.type === "control" && part.reason === "run-interrupted");
739
- const parts = hasInterruptControl ? candidate.assistant.parts : [
740
- ...candidate.assistant.parts,
741
- AgentMessagePartSchema.parse({ type: "control", reason: "run-interrupted" })
742
- ];
907
+
908
+ // src/agent-runtime/retry-policy.ts
909
+ async function recordAgentRetryDecision(input) {
910
+ const retry = input.failure.retryable && input.attempt < input.policy.maxAttempts;
911
+ const delayMs = retry ? input.policy.delayMs({ attempt: input.attempt, failure: input.failure }) : 0;
912
+ if (!Number.isInteger(delayMs) || delayMs < 0) {
913
+ throw new TypeError("Retry delay must be a non-negative integer");
914
+ }
915
+ if (retry) {
916
+ await input.store.appendEvent({
917
+ conversationId: input.conversationId,
918
+ kind: "retry/scheduled",
919
+ payload: { attempt: input.attempt + 1, delayMs, reason: input.failure.reason }
920
+ });
921
+ }
922
+ return { retry, delayMs };
923
+ }
924
+
925
+ // src/agent-runtime/state-slots.ts
926
+ import { z as z2 } from "zod";
927
+ function defineStateSlot(input) {
928
+ if (input.name.length === 0)
929
+ throw new TypeError("State slot name must not be empty");
930
+ const version = input.version ?? 1;
931
+ if (!Number.isInteger(version) || version < 1) {
932
+ throw new TypeError("State slot version must be a positive integer");
933
+ }
743
934
  return {
744
- ...candidate.usage && { usage: candidate.usage },
745
- run,
746
- assistant: AgentMessageSchema.parse({
747
- ...candidate.assistant,
748
- status: assistantStatus(reason),
749
- parts,
750
- updatedAt: now().toISOString()
751
- }),
752
- reason
935
+ name: input.name,
936
+ version,
937
+ schema: input.schema,
938
+ ...input.description && { description: input.description }
753
939
  };
754
940
  }
755
- function canRetryTerminal(current, previous, runtimeEpoch) {
756
- return (current.state === "running" || current.state === "interrupt_requested") && current.ownerId === runtimeEpoch && current.fencingToken === previous.fencingToken;
941
+ var StateSetPayloadSchema = z2.object({
942
+ name: z2.string().min(1),
943
+ version: z2.int().positive(),
944
+ value: z2.json(),
945
+ actor: z2.enum(["agent", "human", "system"])
946
+ }).strict();
947
+ function slotRegistry(definitions) {
948
+ const result = new Map;
949
+ for (const definition of definitions) {
950
+ if (result.has(definition.name))
951
+ throw new TypeError(`Duplicate state slot: ${definition.name}`);
952
+ result.set(definition.name, definition);
953
+ }
954
+ return result;
757
955
  }
758
- var TERMINAL_COMMIT_ATTEMPTS = 32;
759
- async function commitAgentRunTerminal(input) {
760
- let candidate = input.candidate;
761
- for (let attempt = 0;attempt < TERMINAL_COMMIT_ATTEMPTS; attempt += 1) {
762
- const committed = await input.store.commitRunTerminal({
763
- conversationId: candidate.run.conversationId,
764
- runId: candidate.run.id,
765
- expectedRevision: candidate.run.revision,
766
- ownerId: input.runtimeEpoch,
767
- ...candidate.run.fencingToken !== undefined && {
768
- fencingToken: candidate.run.fencingToken
769
- },
770
- assistant: candidate.assistant,
771
- reason: candidate.reason,
772
- ...candidate.policyName && { policyName: candidate.policyName },
773
- ...candidate.usage && { usage: candidate.usage },
774
- ...candidate.absorb?.length && { absorb: candidate.absorb }
956
+ function createAgentStateSlotStore(input) {
957
+ const definitions = slotRegistry(input.definitions);
958
+ const set = async (request) => {
959
+ const definition = definitions.get(request.name);
960
+ if (!definition)
961
+ throw new TypeError(`Unknown state slot: ${request.name}`);
962
+ const value = definition.schema.parse(request.value);
963
+ const payload = StateSetPayloadSchema.parse({
964
+ name: definition.name,
965
+ version: definition.version,
966
+ value,
967
+ actor: request.actor
775
968
  });
776
- if (committed.outcome === "applied") {
777
- const terminal2 = canonicalTerminal(viewOfSnapshot(committed.snapshot, candidate.run.id));
778
- if (!terminal2)
779
- throw new AgentRuntimeConflictError("terminal result projection");
780
- const absorbed = committed.snapshot.runs.filter((run) => run.absorbedIntoRunId === candidate.run.id);
781
- return {
782
- ...terminal2,
783
- committedByCaller: true,
784
- ...absorbed.length > 0 && { absorbed }
785
- };
786
- }
787
- if (committed.outcome === "duplicate") {
788
- const terminal2 = canonicalTerminal(viewOfSnapshot(committed.snapshot, candidate.run.id, committed.assistant));
789
- if (!terminal2)
790
- throw new AgentRuntimeConflictError("terminal result projection");
791
- return terminal2;
792
- }
793
- if (committed.outcome !== "conflict") {
794
- throw new AgentRuntimeConflictError("terminal commit");
795
- }
796
- const latest = await input.store.loadRun({
797
- conversationId: candidate.run.conversationId,
798
- runId: candidate.run.id
969
+ const event = await input.store.appendEvent({
970
+ conversationId: request.conversationId,
971
+ kind: "state/set",
972
+ payload
799
973
  });
800
- const terminal = latest ? canonicalTerminal(viewOfRun(latest, candidate.run.conversationId)) : undefined;
801
- if (terminal)
802
- return terminal;
803
- const current = latest?.run;
804
- if (!current || !canRetryTerminal(current, candidate.run, input.runtimeEpoch)) {
805
- throw new AgentRuntimeConflictError("terminal commit");
974
+ return {
975
+ name: definition.name,
976
+ version: definition.version,
977
+ value,
978
+ updatedAt: event.occurredAt,
979
+ seq: event.seq
980
+ };
981
+ };
982
+ const list = async (conversationId) => {
983
+ const values = new Map;
984
+ let cursor = 1;
985
+ for (;; ) {
986
+ const page = await input.store.readEvents({
987
+ conversationId,
988
+ fromSeq: cursor,
989
+ limit: 1000
990
+ });
991
+ for (const event of page.items) {
992
+ if (event.kind !== "state/set")
993
+ continue;
994
+ const payload = StateSetPayloadSchema.parse(event.payload);
995
+ const definition = definitions.get(payload.name);
996
+ if (!definition || definition.version !== payload.version)
997
+ continue;
998
+ values.set(payload.name, {
999
+ name: payload.name,
1000
+ version: payload.version,
1001
+ value: definition.schema.parse(payload.value),
1002
+ updatedAt: event.occurredAt,
1003
+ seq: event.seq
1004
+ });
1005
+ }
1006
+ if (page.nextSeq === undefined)
1007
+ break;
1008
+ cursor = page.nextSeq;
806
1009
  }
807
- candidate = current.state === "interrupt_requested" ? interruptedCandidate(candidate, current, input.now) : { ...candidate, run: current };
808
- }
809
- throw new AgentRuntimeConflictError("terminal commit");
1010
+ return [...values.values()].sort((left, right) => left.name.localeCompare(right.name));
1011
+ };
1012
+ const get = async (conversationId, name) => (await list(conversationId)).find((value) => value.name === name);
1013
+ return { set, get, list };
1014
+ }
1015
+ function renderAgentStateSlots(values) {
1016
+ if (values.length === 0)
1017
+ return;
1018
+ return [
1019
+ "Durable conversation state (authoritative; newer than compacted history):",
1020
+ ...values.map((slot) => `${slot.name}: ${JSON.stringify(slot.value)}`)
1021
+ ].join(`
1022
+ `);
810
1023
  }
1024
+ var agentGoalStateSlot = defineStateSlot({
1025
+ name: "goal",
1026
+ description: "The durable objective and lifecycle of this conversation.",
1027
+ schema: z2.object({
1028
+ objective: z2.string().min(1),
1029
+ status: z2.enum(["active", "complete", "blocked"])
1030
+ }).strict()
1031
+ });
1032
+ var agentTodoStateSlot = defineStateSlot({
1033
+ name: "todo",
1034
+ description: "The durable ordered work plan for this conversation.",
1035
+ schema: z2.object({
1036
+ items: z2.array(z2.object({
1037
+ step: z2.string().min(1),
1038
+ status: z2.enum(["pending", "in_progress", "completed"])
1039
+ }).strict())
1040
+ }).strict()
1041
+ });
811
1042
 
812
1043
  // src/agent-runtime/admission-lanes.ts
813
1044
  function createRuntimeAdmissionLanes() {
@@ -904,6 +1135,8 @@ function createAgentInjectionRegistry() {
904
1135
  }
905
1136
 
906
1137
  // src/agent-runtime/run-execution.ts
1138
+ import { createHash } from "node:crypto";
1139
+ import { setTimeout as delay } from "node:timers/promises";
907
1140
  import {
908
1141
  stepCountIs
909
1142
  } from "ai";
@@ -934,6 +1167,25 @@ function repairedSearchCall(toolCall, searchName) {
934
1167
  };
935
1168
  }
936
1169
 
1170
+ // src/agent-runtime/provider-origin.ts
1171
+ import {
1172
+ InvalidToolApprovalError,
1173
+ InvalidToolApprovalSignatureError,
1174
+ ToolCallNotFoundForApprovalError
1175
+ } from "ai";
1176
+ var providerOrigin = new WeakSet;
1177
+ function isOwnInputRefusal(error) {
1178
+ return InvalidToolApprovalSignatureError.isInstance(error) || InvalidToolApprovalError.isInstance(error) || ToolCallNotFoundForApprovalError.isInstance(error);
1179
+ }
1180
+ function markProviderOrigin(error) {
1181
+ if (typeof error === "object" && error !== null)
1182
+ providerOrigin.add(error);
1183
+ return error;
1184
+ }
1185
+ function hasProviderOrigin(error) {
1186
+ return typeof error === "object" && error !== null && providerOrigin.has(error);
1187
+ }
1188
+
937
1189
  // src/agent-runtime/run-mutation-queue.ts
938
1190
  function createRunMutationQueue() {
939
1191
  let tail = Promise.resolve();
@@ -952,7 +1204,7 @@ function createRunMutationQueue() {
952
1204
  import { wrapLanguageModel } from "ai";
953
1205
 
954
1206
  // src/agent-runtime/runtime-internals.ts
955
- import { z as z2 } from "zod";
1207
+ import { z as z3 } from "zod";
956
1208
  function findRun(runs, runId) {
957
1209
  const run = runs.find((candidate) => candidate.id === runId);
958
1210
  if (!run)
@@ -960,7 +1212,7 @@ function findRun(runs, runId) {
960
1212
  return run;
961
1213
  }
962
1214
  function jsonValue(value) {
963
- const parsed = z2.json().safeParse(value);
1215
+ const parsed = z3.json().safeParse(value);
964
1216
  return parsed.success ? parsed.data : { message: "Non-JSON tool output omitted" };
965
1217
  }
966
1218
  function providerEnvelope(value) {
@@ -1121,13 +1373,15 @@ function createAgentRunOperationLifecycle(config) {
1121
1373
  emittedAt: config.now().toISOString()
1122
1374
  });
1123
1375
  });
1124
- const startModelRequest = (callId, step) => record(AgentRunOperationSchema.parse({
1125
- operationId: `${callId}:${step}`,
1126
- kind: "model-request",
1127
- phase: "started",
1128
- step,
1129
- startedAt: config.now().toISOString()
1130
- }));
1376
+ const startModelRequest = async (callId, step) => {
1377
+ await record(AgentRunOperationSchema.parse({
1378
+ operationId: `${callId}:${step}`,
1379
+ kind: "model-request",
1380
+ phase: "started",
1381
+ step,
1382
+ startedAt: config.now().toISOString()
1383
+ }));
1384
+ };
1131
1385
  return {
1132
1386
  noteProviderCall(callId) {
1133
1387
  providerCallId = callId;
@@ -1153,7 +1407,11 @@ function createAgentRunOperationLifecycle(config) {
1153
1407
  throw new Error("AgentRuntime model call reached the provider without lifecycle identity");
1154
1408
  }
1155
1409
  await startModelRequest(callId, step);
1156
- return doStream();
1410
+ try {
1411
+ return await doStream();
1412
+ } catch (error) {
1413
+ throw isOwnInputRefusal(error) ? error : markProviderOrigin(error);
1414
+ }
1157
1415
  }
1158
1416
  }
1159
1417
  });
@@ -1218,6 +1476,39 @@ function snapshotForRunPrompt(snapshot, runId) {
1218
1476
  messages: snapshot.messages.filter((message) => !ownedIds.has(message.id) || eligibleIds.has(message.id))
1219
1477
  });
1220
1478
  }
1479
+ function failureThisRuntimeOwns(error) {
1480
+ if (error instanceof AgentContextOverflowError)
1481
+ return "context_overflow";
1482
+ if (error instanceof AgentRuntimeConflictError)
1483
+ return "storage_conflict";
1484
+ if (isOwnInputRefusal(error))
1485
+ return "runtime_failure";
1486
+ return;
1487
+ }
1488
+ function withoutBinaryParts(message) {
1489
+ const reference = (value) => {
1490
+ if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
1491
+ const bytes = value instanceof ArrayBuffer ? new Uint8Array(value) : value;
1492
+ return {
1493
+ binary: true,
1494
+ sha256: createHash("sha256").update(bytes).digest("hex"),
1495
+ bytes: bytes.byteLength
1496
+ };
1497
+ }
1498
+ if (value instanceof URL)
1499
+ return value.toString();
1500
+ if (Array.isArray(value))
1501
+ return value.map(reference);
1502
+ if (value && typeof value === "object") {
1503
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
1504
+ key,
1505
+ reference(entry)
1506
+ ]));
1507
+ }
1508
+ return value;
1509
+ };
1510
+ return reference(message);
1511
+ }
1221
1512
  function createRunExecutor(dependencies) {
1222
1513
  const {
1223
1514
  config,
@@ -1315,9 +1606,15 @@ function createRunExecutor(dependencies) {
1315
1606
  const absorbed = new Map;
1316
1607
  let eventsSinceCheckpoint = 0;
1317
1608
  let sequence = 0;
1609
+ const transientSequence = () => {
1610
+ sequence += 1;
1611
+ return sequence;
1612
+ };
1318
1613
  let terminalReason = "success";
1319
1614
  let nonModelUsage = input.acceptedRun.usage;
1320
1615
  let modelUsage;
1616
+ let abandonedUsage;
1617
+ const billedUsage = () => abandonedUsage && modelUsage ? addUsage(abandonedUsage, modelUsage) : abandonedUsage ?? modelUsage;
1321
1618
  let usage = nonModelUsage;
1322
1619
  let sawProviderFinish = false;
1323
1620
  let step = 0;
@@ -1425,7 +1722,8 @@ function createRunExecutor(dependencies) {
1425
1722
  }
1426
1723
  if (compacted.usage) {
1427
1724
  nonModelUsage = addUsage(nonModelUsage, compacted.usage);
1428
- usage = modelUsage ? addUsage(nonModelUsage, modelUsage) : nonModelUsage;
1725
+ const billed = billedUsage();
1726
+ usage = billed ? addUsage(nonModelUsage, billed) : nonModelUsage;
1429
1727
  }
1430
1728
  }
1431
1729
  const assertCurrent = async () => {
@@ -1489,6 +1787,18 @@ function createRunExecutor(dependencies) {
1489
1787
  throw new AgentContextOverflowError("Agent context still exceeds the model budget after compaction");
1490
1788
  }
1491
1789
  let carriedSystem = [];
1790
+ let durableSystem = [];
1791
+ if (config.stateSlots && config.stateSlots.length > 0) {
1792
+ const slotValues = await createAgentStateSlotStore({
1793
+ store: config.store,
1794
+ definitions: config.stateSlots
1795
+ }).list(run.conversationId);
1796
+ const renderedSlots = renderAgentStateSlots(slotValues);
1797
+ if (renderedSlots) {
1798
+ durableSystem = [renderedSlots];
1799
+ carriedSystem = durableSystem;
1800
+ }
1801
+ }
1492
1802
  const projectHistory = async (source) => {
1493
1803
  if (config.history?.project)
1494
1804
  return config.history.project(source.messages);
@@ -1509,7 +1819,7 @@ function createRunExecutor(dependencies) {
1509
1819
  throw new Error(`Invalid approval continuation ${decision.messageId}: ${decision.reason}`);
1510
1820
  }
1511
1821
  }
1512
- carriedSystem = detailed.system;
1822
+ carriedSystem = [...durableSystem, ...detailed.system];
1513
1823
  return [...detailed.messages];
1514
1824
  };
1515
1825
  const projectInputs = async (source) => {
@@ -1556,10 +1866,12 @@ function createRunExecutor(dependencies) {
1556
1866
  return stopped;
1557
1867
  });
1558
1868
  }
1869
+ let takenThisAttempt = [];
1559
1870
  const takeInjectedMessages = async () => {
1560
1871
  const taken = injection?.take(input.key, run.id) ?? [];
1561
1872
  if (taken.length === 0)
1562
1873
  return [];
1874
+ takenThisAttempt.push(...taken);
1563
1875
  const messages = [];
1564
1876
  for (const entry of taken) {
1565
1877
  messages.push(...await projectInputs([entry.input]));
@@ -1570,324 +1882,456 @@ function createRunExecutor(dependencies) {
1570
1882
  return messages;
1571
1883
  };
1572
1884
  const fallbackModel = selectedModel.model;
1573
- const result = streamAgentTextBoundary({
1574
- model: fallbackModel,
1575
- tools,
1576
- instructions: withCarriedSystem(prompt.instructions),
1577
- messages: history,
1578
- abortSignal: executionSignal,
1579
- maxRetries: 0,
1580
- stopWhen: stopConditions,
1581
- onLanguageModelCallStart: (event) => {
1582
- operationLifecycle.noteProviderCall(event.callId);
1583
- },
1584
- repairToolCall: deferredToolRepair(config.loop?.prepareStep),
1585
- ...config.loop?.toolApproval && {
1586
- toolApproval: config.loop.toolApproval,
1587
- runtimeContext: input.context
1588
- },
1589
- ...config.loop?.toolApprovalSecret && {
1590
- experimental_toolApprovalSecret: config.loop.toolApprovalSecret
1591
- },
1592
- prepareStep: async (options) => {
1593
- const previousStep = options.steps.at(-1);
1594
- if (previousStep) {
1595
- lastPromptTokens = selectedModel?.normalizeUsage?.({
1596
- usage: previousStep.usage,
1597
- providerMetadata: previousStep.providerMetadata
1598
- })?.inputTokens ?? normalizeSdkUsage(previousStep.usage).inputTokens;
1599
- }
1600
- const prepared = await config.loop?.prepareStep?.({
1601
- ...options,
1602
- ...runtimeContext
1603
- });
1604
- const injected = await takeInjectedMessages();
1605
- const preparedStep = injected.length === 0 ? prepared : {
1606
- ...prepared,
1607
- messages: [...prepared?.messages ?? options.messages, ...injected]
1608
- };
1609
- return {
1610
- ...preparedStep,
1611
- model: await operationLifecycle.prepareModel(preparedStep?.model ?? fallbackModel, options.stepNumber, generateId())
1612
- };
1613
- }
1614
- });
1615
- for await (const part of result.stream) {
1616
- idleDeadline.touch();
1617
- eventsSinceCheckpoint += 1;
1618
- sequence += 1;
1619
- if (firstOutputAt === undefined && (part.type === "text-delta" && part.text.length > 0 || part.type === "reasoning-delta" && part.text.length > 0 || part.type === "tool-input-delta" && part.delta.length > 0 || part.type === "tool-call")) {
1620
- firstOutputAt = performance.now();
1621
- }
1622
- if (part.type === "text-delta" && part.text.length > 0 || part.type === "reasoning-delta" && part.text.length > 0 || part.type === "tool-input-delta" && part.delta.length > 0 || part.type === "tool-call") {
1623
- await operationLifecycle.firstOutput();
1624
- }
1625
- if (part.type === "text-delta") {
1626
- appendText(parts, part.text);
1627
- await publish({
1628
- type: "assistant-delta",
1629
- conversationId: run.conversationId,
1630
- runId: run.id,
1631
- runtimeEpoch,
1632
- sequence,
1633
- textDelta: part.text,
1634
- emittedAt: now().toISOString()
1635
- });
1636
- } else if (part.type === "reasoning-start") {
1637
- reasoningPartIndex = undefined;
1638
- updateReasoning("", part.providerMetadata);
1639
- const provider = providerEnvelope(part.providerMetadata);
1640
- await publish({
1641
- type: "reasoning-start",
1885
+ const requestModelId = selectedModel.descriptor.modelId;
1886
+ let retryAttempt = 1;
1887
+ let instructionsOverride;
1888
+ const knownMessageShas = new Set;
1889
+ {
1890
+ let fromSeq;
1891
+ do {
1892
+ const page = await config.store.readEvents({
1642
1893
  conversationId: run.conversationId,
1643
- runId: run.id,
1644
- runtimeEpoch,
1645
- sequence,
1646
- ...provider && { provider },
1647
- emittedAt: now().toISOString()
1894
+ ...fromSeq && { fromSeq },
1895
+ limit: 1e4
1648
1896
  });
1649
- } else if (part.type === "reasoning-delta") {
1650
- updateReasoning(part.text, part.providerMetadata);
1651
- const provider = providerEnvelope(part.providerMetadata);
1652
- await publish({
1653
- type: "reasoning-delta",
1654
- conversationId: run.conversationId,
1655
- runId: run.id,
1656
- runtimeEpoch,
1657
- sequence,
1658
- textDelta: part.text,
1659
- ...provider && { provider },
1660
- emittedAt: now().toISOString()
1661
- });
1662
- } else if (part.type === "reasoning-end") {
1663
- updateReasoning("", part.providerMetadata);
1664
- reasoningPartIndex = undefined;
1665
- const provider = providerEnvelope(part.providerMetadata);
1666
- await publish({
1667
- type: "reasoning-end",
1668
- conversationId: run.conversationId,
1669
- runId: run.id,
1670
- runtimeEpoch,
1671
- sequence,
1672
- ...provider && { provider },
1673
- emittedAt: now().toISOString()
1674
- });
1675
- } else if (part.type === "tool-call") {
1676
- const provider = providerEnvelope(part.providerMetadata);
1677
- parts.push(AgentMessagePartSchema.parse({
1678
- type: "tool-call",
1679
- callId: part.toolCallId,
1680
- toolName: part.toolName,
1681
- input: jsonValue(part.input),
1682
- ...provider && { provider }
1683
- }));
1684
- await publish({
1685
- type: "tool-status",
1897
+ for (const event of page.items) {
1898
+ if (event.kind !== "provider/message")
1899
+ continue;
1900
+ const sha = event.payload?.sha256;
1901
+ if (typeof sha === "string")
1902
+ knownMessageShas.add(sha);
1903
+ }
1904
+ fromSeq = page.nextSeq;
1905
+ } while (fromSeq !== undefined);
1906
+ }
1907
+ const recordProviderRequest = async (request) => {
1908
+ const messageShas = [];
1909
+ for (const message of request.messages) {
1910
+ const body = canonicalAgentJson(JSON.parse(JSON.stringify(withoutBinaryParts(message))));
1911
+ const sha256 = createHash("sha256").update(body).digest("hex");
1912
+ messageShas.push(sha256);
1913
+ if (knownMessageShas.has(sha256))
1914
+ continue;
1915
+ await config.store.appendEvent({
1686
1916
  conversationId: run.conversationId,
1687
- runId: run.id,
1688
- runtimeEpoch,
1689
- sequence,
1690
- callId: part.toolCallId,
1691
- toolName: part.toolName,
1692
- status: "started",
1693
- input: jsonValue(part.input),
1694
- emittedAt: now().toISOString()
1917
+ kind: "provider/message",
1918
+ payload: { sha256, message: JSON.parse(body) }
1695
1919
  });
1696
- } else if (part.type === "tool-result") {
1697
- parts.push(AgentMessagePartSchema.parse({
1698
- type: "tool-result",
1699
- callId: part.toolCallId,
1700
- toolName: part.toolName,
1701
- outcome: "success",
1702
- output: jsonValue(part.output)
1703
- }));
1704
- await publish({
1705
- type: "tool-status",
1706
- conversationId: run.conversationId,
1920
+ knownMessageShas.add(sha256);
1921
+ }
1922
+ const instructionsSha256 = createHash("sha256").update(typeof request.instructions === "string" ? request.instructions : canonicalAgentJson(JSON.parse(JSON.stringify(withoutBinaryParts(request.instructions))))).digest("hex");
1923
+ const bodySha256 = createHash("sha256").update(instructionsSha256).update(messageShas.join(",")).digest("hex");
1924
+ await config.store.appendEvent({
1925
+ conversationId: run.conversationId,
1926
+ kind: "provider/request",
1927
+ payload: {
1707
1928
  runId: run.id,
1708
- runtimeEpoch,
1709
- sequence,
1710
- callId: part.toolCallId,
1711
- toolName: part.toolName,
1712
- status: "completed",
1713
- output: jsonValue(part.output),
1714
- emittedAt: now().toISOString()
1715
- });
1716
- } else if (part.type === "tool-error") {
1717
- internalCause = part.error;
1718
- if (isToolExecutionControlError(part.error)) {
1929
+ attempt: request.attempt,
1930
+ stepNumber: request.stepNumber,
1931
+ modelId: requestModelId,
1932
+ instructionsSha256,
1933
+ messageShas,
1934
+ bodySha256
1935
+ }
1936
+ });
1937
+ };
1938
+ for (;; ) {
1939
+ const attemptPartStart = parts.length;
1940
+ let retrying = false;
1941
+ let draining = false;
1942
+ const result = streamAgentTextBoundary({
1943
+ model: fallbackModel,
1944
+ tools,
1945
+ instructions: withCarriedSystem(prompt.instructions),
1946
+ messages: history,
1947
+ abortSignal: executionSignal,
1948
+ maxRetries: 0,
1949
+ stopWhen: stopConditions,
1950
+ onLanguageModelCallStart: (event) => {
1951
+ operationLifecycle.noteProviderCall(event.callId);
1952
+ },
1953
+ repairToolCall: deferredToolRepair(config.loop?.prepareStep),
1954
+ ...config.loop?.toolApproval && {
1955
+ toolApproval: config.loop.toolApproval,
1956
+ runtimeContext: input.context
1957
+ },
1958
+ ...config.loop?.toolApprovalSecret && {
1959
+ experimental_toolApprovalSecret: config.loop.toolApprovalSecret
1960
+ },
1961
+ prepareStep: async (options) => {
1962
+ const previousStep = options.steps.at(-1);
1963
+ if (previousStep) {
1964
+ lastPromptTokens = selectedModel?.normalizeUsage?.({
1965
+ usage: previousStep.usage,
1966
+ providerMetadata: previousStep.providerMetadata
1967
+ })?.inputTokens ?? normalizeSdkUsage(previousStep.usage).inputTokens;
1968
+ }
1969
+ const prepared = await config.loop?.prepareStep?.({
1970
+ ...options,
1971
+ ...runtimeContext
1972
+ });
1973
+ const injected = await takeInjectedMessages();
1974
+ const preparedStep = injected.length === 0 ? prepared : {
1975
+ ...prepared,
1976
+ messages: [...prepared?.messages ?? options.messages, ...injected]
1977
+ };
1978
+ const providerMessages = preparedStep?.messages ?? options.messages;
1979
+ const model = await operationLifecycle.prepareModel(preparedStep?.model ?? fallbackModel, options.stepNumber, generateId());
1980
+ const override = preparedStep;
1981
+ if (override?.instructions !== undefined)
1982
+ instructionsOverride = override.instructions;
1983
+ else if (override?.system !== undefined)
1984
+ instructionsOverride = override.system;
1985
+ await recordProviderRequest({
1986
+ stepNumber: options.stepNumber,
1987
+ attempt: retryAttempt,
1988
+ instructions: instructionsOverride ?? withCarriedSystem(prompt.instructions),
1989
+ messages: providerMessages
1990
+ });
1991
+ return { ...preparedStep, model };
1992
+ }
1993
+ });
1994
+ for await (const part of result.stream) {
1995
+ idleDeadline.touch();
1996
+ if (draining) {
1997
+ if (part.type === "finish-step") {
1998
+ const failedStepUsage = selectedModel.normalizeUsage?.({
1999
+ usage: part.usage,
2000
+ providerMetadata: part.providerMetadata
2001
+ }) ?? normalizeSdkUsage(part.usage);
2002
+ abandonedUsage = abandonedUsage ? addUsage(abandonedUsage, failedStepUsage) : failedStepUsage;
2003
+ const billed = billedUsage();
2004
+ usage = nonModelUsage && billed ? addUsage(nonModelUsage, billed) : billed ?? nonModelUsage;
2005
+ }
2006
+ continue;
2007
+ }
2008
+ eventsSinceCheckpoint += 1;
2009
+ if (part.type === "error" && config.loop?.retry && failureThisRuntimeOwns(part.error) === undefined) {
2010
+ const invokedTool = parts.slice(attemptPartStart).some((candidate) => candidate.type === "tool-call");
2011
+ const decision = invokedTool ? { retry: false, delayMs: 0 } : await recordAgentRetryDecision({
2012
+ store: config.store,
2013
+ conversationId: run.conversationId,
2014
+ attempt: retryAttempt,
2015
+ failure: classifyProviderFailure(part.error),
2016
+ policy: config.loop.retry
2017
+ });
2018
+ if (decision.retry) {
2019
+ await operationLifecycle.finish("failed");
2020
+ parts.splice(attemptPartStart);
2021
+ for (const entry of takenThisAttempt) {
2022
+ injection?.offer(input.key, entry);
2023
+ const ids = absorbed.get(entry.runId);
2024
+ if (ids) {
2025
+ const kept = ids.filter((id) => id !== entry.input.id);
2026
+ if (kept.length === 0)
2027
+ absorbed.delete(entry.runId);
2028
+ else
2029
+ absorbed.set(entry.runId, kept);
2030
+ }
2031
+ }
2032
+ takenThisAttempt = [];
2033
+ await checkpoint();
2034
+ eventsSinceCheckpoint = 0;
2035
+ if (decision.delayMs > 0) {
2036
+ await delay(decision.delayMs, undefined, { signal: executionSignal });
2037
+ }
2038
+ retryAttempt += 1;
2039
+ await config.store.appendEvent({
2040
+ conversationId: run.conversationId,
2041
+ kind: "retry/started",
2042
+ payload: { attempt: retryAttempt }
2043
+ });
2044
+ retrying = true;
2045
+ draining = true;
2046
+ continue;
2047
+ }
2048
+ }
2049
+ if (firstOutputAt === undefined && (part.type === "text-delta" && part.text.length > 0 || part.type === "reasoning-delta" && part.text.length > 0 || part.type === "tool-input-delta" && part.delta.length > 0 || part.type === "tool-call")) {
2050
+ firstOutputAt = performance.now();
2051
+ }
2052
+ if (part.type === "text-delta" && part.text.length > 0 || part.type === "reasoning-delta" && part.text.length > 0 || part.type === "tool-input-delta" && part.delta.length > 0 || part.type === "tool-call") {
2053
+ await operationLifecycle.firstOutput();
2054
+ }
2055
+ if (part.type === "text-delta") {
2056
+ appendText(parts, part.text);
2057
+ await publish({
2058
+ type: "assistant-delta",
2059
+ conversationId: run.conversationId,
2060
+ runId: run.id,
2061
+ runtimeEpoch,
2062
+ sequence: transientSequence(),
2063
+ textDelta: part.text,
2064
+ emittedAt: now().toISOString()
2065
+ });
2066
+ } else if (part.type === "reasoning-start") {
2067
+ reasoningPartIndex = undefined;
2068
+ updateReasoning("", part.providerMetadata);
2069
+ const provider = providerEnvelope(part.providerMetadata);
2070
+ await publish({
2071
+ type: "reasoning-start",
2072
+ conversationId: run.conversationId,
2073
+ runId: run.id,
2074
+ runtimeEpoch,
2075
+ sequence: transientSequence(),
2076
+ ...provider && { provider },
2077
+ emittedAt: now().toISOString()
2078
+ });
2079
+ } else if (part.type === "reasoning-delta") {
2080
+ updateReasoning(part.text, part.providerMetadata);
2081
+ const provider = providerEnvelope(part.providerMetadata);
2082
+ await publish({
2083
+ type: "reasoning-delta",
2084
+ conversationId: run.conversationId,
2085
+ runId: run.id,
2086
+ runtimeEpoch,
2087
+ sequence: transientSequence(),
2088
+ textDelta: part.text,
2089
+ ...provider && { provider },
2090
+ emittedAt: now().toISOString()
2091
+ });
2092
+ } else if (part.type === "reasoning-end") {
2093
+ updateReasoning("", part.providerMetadata);
2094
+ reasoningPartIndex = undefined;
2095
+ const provider = providerEnvelope(part.providerMetadata);
2096
+ await publish({
2097
+ type: "reasoning-end",
2098
+ conversationId: run.conversationId,
2099
+ runId: run.id,
2100
+ runtimeEpoch,
2101
+ sequence: transientSequence(),
2102
+ ...provider && { provider },
2103
+ emittedAt: now().toISOString()
2104
+ });
2105
+ } else if (part.type === "tool-call") {
2106
+ const provider = providerEnvelope(part.providerMetadata);
2107
+ parts.push(AgentMessagePartSchema.parse({
2108
+ type: "tool-call",
2109
+ callId: part.toolCallId,
2110
+ toolName: part.toolName,
2111
+ input: jsonValue(part.input),
2112
+ ...provider && { provider }
2113
+ }));
2114
+ await publish({
2115
+ type: "tool-status",
2116
+ conversationId: run.conversationId,
2117
+ runId: run.id,
2118
+ runtimeEpoch,
2119
+ sequence: transientSequence(),
2120
+ callId: part.toolCallId,
2121
+ toolName: part.toolName,
2122
+ status: "started",
2123
+ input: jsonValue(part.input),
2124
+ emittedAt: now().toISOString()
2125
+ });
2126
+ } else if (part.type === "tool-result") {
2127
+ parts.push(AgentMessagePartSchema.parse({
2128
+ type: "tool-result",
2129
+ callId: part.toolCallId,
2130
+ toolName: part.toolName,
2131
+ outcome: "success",
2132
+ output: jsonValue(part.output)
2133
+ }));
1719
2134
  await publish({
1720
2135
  type: "tool-status",
1721
2136
  conversationId: run.conversationId,
1722
2137
  runId: run.id,
1723
2138
  runtimeEpoch,
1724
- sequence,
2139
+ sequence: transientSequence(),
1725
2140
  callId: part.toolCallId,
1726
2141
  toolName: part.toolName,
1727
- status: "interrupted",
2142
+ status: "completed",
2143
+ output: jsonValue(part.output),
1728
2144
  emittedAt: now().toISOString()
1729
2145
  });
2146
+ } else if (part.type === "tool-error") {
2147
+ internalCause = part.error;
2148
+ if (isToolExecutionControlError(part.error)) {
2149
+ await publish({
2150
+ type: "tool-status",
2151
+ conversationId: run.conversationId,
2152
+ runId: run.id,
2153
+ runtimeEpoch,
2154
+ sequence: transientSequence(),
2155
+ callId: part.toolCallId,
2156
+ toolName: part.toolName,
2157
+ status: "interrupted",
2158
+ emittedAt: now().toISOString()
2159
+ });
2160
+ await checkpoint();
2161
+ throw part.error;
2162
+ }
2163
+ const output = isAgentToolError(part.error) ? jsonValue(part.error.output) : { message: "Tool execution failed" };
2164
+ parts.push(AgentMessagePartSchema.parse({
2165
+ type: "tool-result",
2166
+ callId: part.toolCallId,
2167
+ toolName: part.toolName,
2168
+ outcome: "error",
2169
+ output
2170
+ }));
2171
+ await publish({
2172
+ type: "tool-status",
2173
+ conversationId: run.conversationId,
2174
+ runId: run.id,
2175
+ runtimeEpoch,
2176
+ sequence: transientSequence(),
2177
+ callId: part.toolCallId,
2178
+ toolName: part.toolName,
2179
+ status: "failed",
2180
+ output,
2181
+ emittedAt: now().toISOString()
2182
+ });
2183
+ } else if (part.type === "tool-output-denied") {
2184
+ parts.push(AgentMessagePartSchema.parse({
2185
+ type: "tool-result",
2186
+ callId: part.toolCallId,
2187
+ toolName: part.toolName,
2188
+ outcome: "error",
2189
+ output: { message: "Tool output denied" }
2190
+ }));
2191
+ await publish({
2192
+ type: "tool-status",
2193
+ conversationId: run.conversationId,
2194
+ runId: run.id,
2195
+ runtimeEpoch,
2196
+ sequence: transientSequence(),
2197
+ callId: part.toolCallId,
2198
+ toolName: part.toolName,
2199
+ status: "failed",
2200
+ output: { message: "Tool output denied" },
2201
+ emittedAt: now().toISOString()
2202
+ });
2203
+ } else if (part.type === "source") {
2204
+ parts.push(AgentMessagePartSchema.parse({
2205
+ type: "source",
2206
+ sourceId: part.id,
2207
+ ...part.sourceType === "url" && { url: part.url },
2208
+ ...part.title && { title: part.title }
2209
+ }));
2210
+ } else if (part.type === "file" && config.persistGeneratedFile) {
2211
+ const persisted = await config.persistGeneratedFile(part.file);
2212
+ parts.push(AgentMessagePartSchema.parse({
2213
+ type: "file",
2214
+ mediaType: part.file.mediaType,
2215
+ reference: persisted.reference,
2216
+ ...persisted.filename && { filename: persisted.filename }
2217
+ }));
2218
+ } else if (part.type === "file") {
2219
+ throw new Error("persistGeneratedFile is required for generated file output");
2220
+ } else if (part.type === "reasoning-file" && config.persistGeneratedFile) {
2221
+ const persisted = await config.persistGeneratedFile(part.file);
2222
+ parts.push(AgentMessagePartSchema.parse({
2223
+ type: "file",
2224
+ mediaType: part.file.mediaType,
2225
+ reference: persisted.reference,
2226
+ ...persisted.filename && { filename: persisted.filename }
2227
+ }));
2228
+ } else if (part.type === "reasoning-file") {
2229
+ throw new Error("persistGeneratedFile is required for generated reasoning files");
2230
+ } else if (part.type === "tool-approval-request") {
2231
+ parts.push(AgentMessagePartSchema.parse({
2232
+ type: "tool-approval-request",
2233
+ approvalId: part.approvalId,
2234
+ callId: part.toolCall.toolCallId,
2235
+ ...part.isAutomatic !== undefined && { isAutomatic: part.isAutomatic },
2236
+ ...part.signature && { signature: part.signature }
2237
+ }));
2238
+ } else if (part.type === "tool-approval-response") {
2239
+ parts.push(AgentMessagePartSchema.parse({
2240
+ type: "tool-approval-response",
2241
+ approvalId: part.approvalId,
2242
+ approved: part.approved,
2243
+ ...part.reason && { reason: part.reason }
2244
+ }));
2245
+ } else if (part.type === "custom") {
2246
+ const provider = providerEnvelope(part.providerMetadata);
2247
+ parts.push(AgentMessagePartSchema.parse({
2248
+ type: "provider",
2249
+ envelope: {
2250
+ schemaVersion: 1,
2251
+ provider: "ai-sdk-custom",
2252
+ data: { kind: part.kind, ...provider && { provider: provider.data } }
2253
+ }
2254
+ }));
2255
+ } else if (part.type === "raw") {
2256
+ parts.push(AgentMessagePartSchema.parse({
2257
+ type: "provider",
2258
+ envelope: {
2259
+ schemaVersion: 1,
2260
+ provider: "ai-sdk-raw",
2261
+ data: { value: jsonValue(part.rawValue) }
2262
+ }
2263
+ }));
2264
+ } else if (part.type === "abort") {
2265
+ terminalReason = "interrupted";
2266
+ } else if (part.type === "error") {
2267
+ terminalReason = failureThisRuntimeOwns(part.error) ?? "provider_failure";
2268
+ internalCause = part.error;
2269
+ } else if (part.type === "finish-step") {
2270
+ await operationLifecycle.finish(part.finishReason === "error" ? "failed" : "completed");
2271
+ const stepTrace = trace ? config.observe?.rootTrace(trace) : undefined;
2272
+ const stepUsage = selectedModel.normalizeUsage?.({
2273
+ usage: part.usage,
2274
+ providerMetadata: part.providerMetadata
2275
+ }) ?? normalizeSdkUsage(part.usage);
2276
+ lastPromptTokens = stepUsage.inputTokens;
2277
+ modelUsage = addUsage(modelUsage, stepUsage);
2278
+ usage = nonModelUsage ? addUsage(nonModelUsage, billedUsage() ?? modelUsage) : billedUsage();
2279
+ config.observe?.emit({
2280
+ schemaVersion: 1,
2281
+ eventId: generateId(),
2282
+ type: "step-finished",
2283
+ conversationId: run.conversationId,
2284
+ runId: run.id,
2285
+ traceId: stepTrace?.traceId ?? trace?.traceId ?? generateId(),
2286
+ spanId: stepTrace?.spanId ?? generateId(),
2287
+ ...stepTrace?.parentSpanId && { parentSpanId: stepTrace.parentSpanId },
2288
+ state: run.state,
2289
+ modelId: selectedModel.descriptor.modelId,
2290
+ step,
2291
+ usage: stepUsage,
2292
+ emittedAt: now().toISOString()
2293
+ });
2294
+ step += 1;
2295
+ } else if (part.type === "finish" && part.finishReason !== "stop") {
2296
+ if (terminalReason === "success") {
2297
+ terminalReason = part.finishReason === "error" ? "provider_failure" : "provider_stop";
2298
+ internalCause ??= { finishReason: part.finishReason };
2299
+ }
2300
+ }
2301
+ if (part.type === "finish") {
2302
+ sawProviderFinish = true;
2303
+ modelUsage = mergeModelTotals(normalizeSdkUsage(part.totalUsage), modelUsage);
2304
+ usage = nonModelUsage ? addUsage(nonModelUsage, billedUsage() ?? modelUsage) : billedUsage();
2305
+ }
2306
+ const structuralBoundary = [
2307
+ "tool-call",
2308
+ "tool-result",
2309
+ "tool-error",
2310
+ "tool-output-denied",
2311
+ "tool-approval-request",
2312
+ "tool-approval-response",
2313
+ "finish-step"
2314
+ ].includes(part.type);
2315
+ if (structuralBoundary || eventsSinceCheckpoint >= checkpointEveryEvents) {
1730
2316
  await checkpoint();
1731
- throw part.error;
2317
+ eventsSinceCheckpoint = 0;
2318
+ if (part.type === "finish-step")
2319
+ operationLifecycle.checkpointStep(step - 1);
1732
2320
  }
1733
- const output = isAgentToolError(part.error) ? jsonValue(part.error.output) : { message: "Tool execution failed" };
1734
- parts.push(AgentMessagePartSchema.parse({
1735
- type: "tool-result",
1736
- callId: part.toolCallId,
1737
- toolName: part.toolName,
1738
- outcome: "error",
1739
- output
1740
- }));
1741
- await publish({
1742
- type: "tool-status",
1743
- conversationId: run.conversationId,
1744
- runId: run.id,
1745
- runtimeEpoch,
1746
- sequence,
1747
- callId: part.toolCallId,
1748
- toolName: part.toolName,
1749
- status: "failed",
1750
- output,
1751
- emittedAt: now().toISOString()
1752
- });
1753
- } else if (part.type === "tool-output-denied") {
1754
- parts.push(AgentMessagePartSchema.parse({
1755
- type: "tool-result",
1756
- callId: part.toolCallId,
1757
- toolName: part.toolName,
1758
- outcome: "error",
1759
- output: { message: "Tool output denied" }
1760
- }));
2321
+ }
2322
+ if (retrying) {
1761
2323
  await publish({
1762
- type: "tool-status",
2324
+ type: "attempt-reset",
1763
2325
  conversationId: run.conversationId,
1764
2326
  runId: run.id,
1765
2327
  runtimeEpoch,
1766
- sequence,
1767
- callId: part.toolCallId,
1768
- toolName: part.toolName,
1769
- status: "failed",
1770
- output: { message: "Tool output denied" },
1771
- emittedAt: now().toISOString()
1772
- });
1773
- } else if (part.type === "source") {
1774
- parts.push(AgentMessagePartSchema.parse({
1775
- type: "source",
1776
- sourceId: part.id,
1777
- ...part.sourceType === "url" && { url: part.url },
1778
- ...part.title && { title: part.title }
1779
- }));
1780
- } else if (part.type === "file" && config.persistGeneratedFile) {
1781
- const persisted = await config.persistGeneratedFile(part.file);
1782
- parts.push(AgentMessagePartSchema.parse({
1783
- type: "file",
1784
- mediaType: part.file.mediaType,
1785
- reference: persisted.reference,
1786
- ...persisted.filename && { filename: persisted.filename }
1787
- }));
1788
- } else if (part.type === "file") {
1789
- throw new Error("persistGeneratedFile is required for generated file output");
1790
- } else if (part.type === "reasoning-file" && config.persistGeneratedFile) {
1791
- const persisted = await config.persistGeneratedFile(part.file);
1792
- parts.push(AgentMessagePartSchema.parse({
1793
- type: "file",
1794
- mediaType: part.file.mediaType,
1795
- reference: persisted.reference,
1796
- ...persisted.filename && { filename: persisted.filename }
1797
- }));
1798
- } else if (part.type === "reasoning-file") {
1799
- throw new Error("persistGeneratedFile is required for generated reasoning files");
1800
- } else if (part.type === "tool-approval-request") {
1801
- parts.push(AgentMessagePartSchema.parse({
1802
- type: "tool-approval-request",
1803
- approvalId: part.approvalId,
1804
- callId: part.toolCall.toolCallId,
1805
- ...part.isAutomatic !== undefined && { isAutomatic: part.isAutomatic },
1806
- ...part.signature && { signature: part.signature }
1807
- }));
1808
- } else if (part.type === "tool-approval-response") {
1809
- parts.push(AgentMessagePartSchema.parse({
1810
- type: "tool-approval-response",
1811
- approvalId: part.approvalId,
1812
- approved: part.approved,
1813
- ...part.reason && { reason: part.reason }
1814
- }));
1815
- } else if (part.type === "custom") {
1816
- const provider = providerEnvelope(part.providerMetadata);
1817
- parts.push(AgentMessagePartSchema.parse({
1818
- type: "provider",
1819
- envelope: {
1820
- schemaVersion: 1,
1821
- provider: "ai-sdk-custom",
1822
- data: { kind: part.kind, ...provider && { provider: provider.data } }
1823
- }
1824
- }));
1825
- } else if (part.type === "raw") {
1826
- parts.push(AgentMessagePartSchema.parse({
1827
- type: "provider",
1828
- envelope: {
1829
- schemaVersion: 1,
1830
- provider: "ai-sdk-raw",
1831
- data: { value: jsonValue(part.rawValue) }
1832
- }
1833
- }));
1834
- } else if (part.type === "abort") {
1835
- terminalReason = "interrupted";
1836
- } else if (part.type === "error") {
1837
- terminalReason = part.error instanceof AgentContextOverflowError ? "context_overflow" : "provider_failure";
1838
- internalCause = part.error;
1839
- } else if (part.type === "finish-step") {
1840
- await operationLifecycle.finish(part.finishReason === "error" ? "failed" : "completed");
1841
- const stepTrace = trace ? config.observe?.rootTrace(trace) : undefined;
1842
- const stepUsage = selectedModel.normalizeUsage?.({
1843
- usage: part.usage,
1844
- providerMetadata: part.providerMetadata
1845
- }) ?? normalizeSdkUsage(part.usage);
1846
- lastPromptTokens = stepUsage.inputTokens;
1847
- modelUsage = addUsage(modelUsage, stepUsage);
1848
- usage = nonModelUsage ? addUsage(nonModelUsage, modelUsage) : modelUsage;
1849
- config.observe?.emit({
1850
- schemaVersion: 1,
1851
- eventId: generateId(),
1852
- type: "step-finished",
1853
- conversationId: run.conversationId,
1854
- runId: run.id,
1855
- traceId: stepTrace?.traceId ?? trace?.traceId ?? generateId(),
1856
- spanId: stepTrace?.spanId ?? generateId(),
1857
- ...stepTrace?.parentSpanId && { parentSpanId: stepTrace.parentSpanId },
1858
- state: run.state,
1859
- modelId: selectedModel.descriptor.modelId,
1860
- step,
1861
- usage: stepUsage,
2328
+ sequence: transientSequence(),
2329
+ attempt: retryAttempt,
1862
2330
  emittedAt: now().toISOString()
1863
2331
  });
1864
- step += 1;
1865
- } else if (part.type === "finish" && part.finishReason !== "stop") {
1866
- if (terminalReason === "success") {
1867
- terminalReason = part.finishReason === "error" ? "provider_failure" : "provider_stop";
1868
- internalCause ??= { finishReason: part.finishReason };
1869
- }
1870
- }
1871
- if (part.type === "finish") {
1872
- sawProviderFinish = true;
1873
- modelUsage = mergeModelTotals(normalizeSdkUsage(part.totalUsage), modelUsage);
1874
- usage = nonModelUsage ? addUsage(nonModelUsage, modelUsage) : modelUsage;
1875
- }
1876
- const structuralBoundary = [
1877
- "tool-call",
1878
- "tool-result",
1879
- "tool-error",
1880
- "tool-output-denied",
1881
- "tool-approval-request",
1882
- "tool-approval-response",
1883
- "finish-step"
1884
- ].includes(part.type);
1885
- if (structuralBoundary || eventsSinceCheckpoint >= checkpointEveryEvents) {
1886
- await checkpoint();
1887
- eventsSinceCheckpoint = 0;
1888
- if (part.type === "finish-step")
1889
- operationLifecycle.checkpointStep(step - 1);
2332
+ continue;
1890
2333
  }
2334
+ break;
1891
2335
  }
1892
2336
  await operationLifecycle.finish(executionSignal.aborted ? "cancelled" : terminalReason === "provider_failure" ? "failed" : "completed");
1893
2337
  if (terminalPolicyName !== undefined)
@@ -1907,7 +2351,7 @@ function createRunExecutor(dependencies) {
1907
2351
  reason: terminalReason,
1908
2352
  ...terminalPolicyName && { policyName: terminalPolicyName }
1909
2353
  })) {
1910
- terminalReason = "provider_failure";
2354
+ terminalReason = "output_rejected";
1911
2355
  internalCause = new Error("Agent terminal output was rejected by the protocol");
1912
2356
  }
1913
2357
  }
@@ -1934,8 +2378,12 @@ function createRunExecutor(dependencies) {
1934
2378
  type: "control",
1935
2379
  reason: isToolExecutionControlError(error) && error.reason === "stale_run" ? "stale-run" : "run-interrupted"
1936
2380
  }));
2381
+ } else if (error instanceof AgentContextOverflowError) {
2382
+ terminalReason = "context_overflow";
2383
+ } else if (error instanceof AgentRuntimeConflictError) {
2384
+ terminalReason = "storage_conflict";
1937
2385
  } else {
1938
- terminalReason = error instanceof AgentContextOverflowError ? "context_overflow" : "provider_failure";
2386
+ terminalReason = failureThisRuntimeOwns(error) ?? (hasProviderOrigin(error) ? "provider_failure" : "runtime_failure");
1939
2387
  }
1940
2388
  } finally {
1941
2389
  idleDeadline.dispose();
@@ -2007,6 +2455,13 @@ function createRunExecutor(dependencies) {
2007
2455
  usage: spent,
2008
2456
  ...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt }
2009
2457
  } : undefined;
2458
+ if (config.children && terminal.committedByCaller && (terminalReason === "interrupted" || terminalReason === "cancelled" || terminalReason === "timeout" || terminalReason === "shutdown")) {
2459
+ try {
2460
+ await config.children.stopChildren(run.conversationId);
2461
+ } catch (error) {
2462
+ internalCause ??= error;
2463
+ }
2464
+ }
2010
2465
  emitSpend({
2011
2466
  eventId: terminal.committedByCaller ? agentDurableEventId("terminal", run.id, observedVersion) : unsettledEventId(observedVersion),
2012
2467
  state: run.state,
@@ -2639,4 +3094,4 @@ function createAgentRuntime(config) {
2639
3094
  };
2640
3095
  }
2641
3096
 
2642
- export { AgentContextOverflowError, createAgentSessionCoordinator, registerDeferredToolRepair, registerDeferredToolCatalog, deferredToolCatalog, repairedSearchCall, createAgentRuntimeEventSink, projectAgentHistoryDetailed, projectAgentHistory, createAgentToolFenceLifecycle, AgentTokenCountSchema, selectAgentHistory, composeAgentPrompt, AgentRuntimeConflictError, createAgentRuntime };
3097
+ export { AgentRuntimeConflictError, normalizeSdkUsage, AgentContextOverflowError, createAgentSessionCoordinator, registerDeferredToolRepair, registerDeferredToolCatalog, deferredToolCatalog, repairedSearchCall, createAgentRuntimeEventSink, projectAgentHistoryDetailed, projectAgentHistory, createAgentToolFenceLifecycle, AgentTokenCountSchema, selectAgentHistory, composeAgentPrompt, AgentProviderStreamCutError, classifyProviderFailure, isToolResultFailure, recordAgentRetryDecision, defineStateSlot, createAgentStateSlotStore, renderAgentStateSlots, agentGoalStateSlot, agentTodoStateSlot, createAgentRuntime };