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