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.
- package/CHANGELOG.md +160 -0
- package/README.md +3 -0
- package/dist/agent-runtime/agent-tool.d.ts +25 -0
- package/dist/agent-runtime/agent-tool.d.ts.map +1 -0
- package/dist/agent-runtime/child-tools.d.ts +69 -0
- package/dist/agent-runtime/child-tools.d.ts.map +1 -0
- package/dist/agent-runtime/children.d.ts +113 -0
- package/dist/agent-runtime/children.d.ts.map +1 -0
- package/dist/agent-runtime/coding-tool-contract.d.ts +29 -0
- package/dist/agent-runtime/coding-tool-contract.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-refusals.d.ts +2 -0
- package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-shell.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tools.d.ts +1 -0
- package/dist/agent-runtime/coding-tools.d.ts.map +1 -1
- package/dist/agent-runtime/control-schema.d.ts +17 -0
- package/dist/agent-runtime/control-schema.d.ts.map +1 -1
- package/dist/agent-runtime/event-schema.d.ts +34 -0
- package/dist/agent-runtime/event-schema.d.ts.map +1 -1
- package/dist/agent-runtime/event-search-tools.d.ts +53 -0
- package/dist/agent-runtime/event-search-tools.d.ts.map +1 -0
- package/dist/agent-runtime/event-search.d.ts +23 -0
- package/dist/agent-runtime/event-search.d.ts.map +1 -0
- package/dist/agent-runtime/fault-bench.d.ts +45 -0
- package/dist/agent-runtime/fault-bench.d.ts.map +1 -0
- package/dist/agent-runtime/observability.d.ts +6 -0
- package/dist/agent-runtime/observability.d.ts.map +1 -1
- package/dist/agent-runtime/projections.d.ts +69 -0
- package/dist/agent-runtime/projections.d.ts.map +1 -0
- package/dist/agent-runtime/provider-failure.d.ts +5 -1
- package/dist/agent-runtime/provider-failure.d.ts.map +1 -1
- package/dist/agent-runtime/provider-origin.d.ts +12 -0
- package/dist/agent-runtime/provider-origin.d.ts.map +1 -0
- package/dist/agent-runtime/retry-policy.d.ts +27 -0
- package/dist/agent-runtime/retry-policy.d.ts.map +1 -0
- package/dist/agent-runtime/run-execution.d.ts +0 -9
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/run-operation-lifecycle.d.ts.map +1 -1
- package/dist/agent-runtime/runtime.d.ts +15 -0
- package/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/agent-runtime/sandbox.d.ts +66 -0
- package/dist/agent-runtime/sandbox.d.ts.map +1 -0
- package/dist/agent-runtime/schedule-tools.d.ts +35 -0
- package/dist/agent-runtime/schedule-tools.d.ts.map +1 -0
- package/dist/agent-runtime/schedules.d.ts +63 -0
- package/dist/agent-runtime/schedules.d.ts.map +1 -0
- package/dist/agent-runtime/schemas.d.ts +9 -0
- package/dist/agent-runtime/schemas.d.ts.map +1 -1
- package/dist/agent-runtime/spill.d.ts +24 -0
- package/dist/agent-runtime/spill.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-purge.d.ts.map +1 -1
- package/dist/agent-runtime/sqlite.d.ts +26 -0
- package/dist/agent-runtime/sqlite.d.ts.map +1 -1
- package/dist/agent-runtime/state-slots.d.ts +48 -0
- package/dist/agent-runtime/state-slots.d.ts.map +1 -0
- package/dist/agent-runtime/state-tools.d.ts +58 -0
- package/dist/agent-runtime/state-tools.d.ts.map +1 -0
- package/dist/agent-runtime/store-driver.d.ts +13 -0
- package/dist/agent-runtime/store-driver.d.ts.map +1 -1
- package/dist/agent-runtime/store-events.d.ts +829 -0
- package/dist/agent-runtime/store-events.d.ts.map +1 -0
- package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts +6 -0
- package/dist/agent-runtime/store-migrations/v1-to-v2.d.ts.map +1 -0
- package/dist/agent-runtime/store.d.ts +45 -0
- package/dist/agent-runtime/store.d.ts.map +1 -1
- package/dist/agent-runtime/terminal-commit.d.ts +1 -1
- package/dist/agent-runtime-browser.js +5 -3
- package/dist/agent-runtime-coding-tools.js +144 -15
- package/dist/agent-runtime-harness.js +12 -10
- package/dist/agent-runtime-sqlite-bun.d.ts +1 -1
- package/dist/agent-runtime-sqlite-bun.d.ts.map +1 -1
- package/dist/agent-runtime-sqlite-bun.js +4 -3
- package/dist/agent-runtime-sqlite-node.d.ts +1 -1
- package/dist/agent-runtime-sqlite-node.d.ts.map +1 -1
- package/dist/agent-runtime-sqlite-node.js +4 -3
- package/dist/agent-runtime-testing.d.ts +3 -0
- package/dist/agent-runtime-testing.d.ts.map +1 -0
- package/dist/agent-runtime-testing.js +156 -0
- package/dist/agent-runtime.d.ts +16 -2
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +1591 -154
- package/dist/application.js +14 -14
- package/dist/cli.js +6 -6
- package/dist/{index-fwbkp2jn.js → index-0vfdh685.js} +2 -2
- package/dist/{index-5z8tezpx.js → index-0ydchz76.js} +3 -3
- package/dist/{index-3ds42w1w.js → index-1szetq6f.js} +33 -4
- package/dist/{index-2jg7b11j.js → index-33xckd7h.js} +879 -422
- package/dist/{index-27487ay5.js → index-9hw9eq48.js} +4 -4
- package/dist/{index-66nxrgy0.js → index-b7qwhbzq.js} +428 -46
- package/dist/index-cnyk6te3.js +77 -0
- package/dist/index-gskm1k5a.js +50 -0
- package/dist/{index-fq492hg0.js → index-hber83mk.js} +254 -157
- package/dist/{index-4hk633vz.js → index-hkm6wysp.js} +9 -2
- package/dist/{index-dx9xehwt.js → index-kc6h6hg0.js} +1 -1
- package/dist/{index-x15ss2dx.js → index-p1b1y93x.js} +3 -0
- package/dist/{index-mgtxfe6b.js → index-r159gjwy.js} +8 -1
- package/dist/{index-s4ckmrac.js → index-rcgsnrr6.js} +3 -3
- package/dist/index-vfgb58nf.js +252 -0
- package/dist/{index-dggwnnjv.js → index-wn9cb82y.js} +1 -1
- package/dist/{index-ff0kcqvp.js → index-z2452tsw.js} +3 -3
- package/dist/testing/agent-store-conformance.d.ts.map +1 -1
- package/dist/testing.js +54 -80
- package/dist/tool-invoker.js +4 -4
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools/manifest.d.ts +16 -0
- package/dist/tools/manifest.d.ts.map +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +10 -8
- package/llms-full.txt +321 -13
- 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
|
-
|
|
11
|
-
} from "./index-
|
|
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-
|
|
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-
|
|
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/
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
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
|
|
697
|
-
if (
|
|
698
|
-
return
|
|
699
|
-
|
|
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
|
|
702
|
-
|
|
703
|
-
|
|
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
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
888
|
+
reason: "unknown",
|
|
889
|
+
...status !== undefined && { status },
|
|
890
|
+
retryable: false,
|
|
891
|
+
evidence: "none"
|
|
709
892
|
};
|
|
710
893
|
}
|
|
711
|
-
function
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
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
|
|
720
|
-
|
|
721
|
-
|
|
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
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
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
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
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
|
-
|
|
756
|
-
|
|
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
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
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
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
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
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
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
|
-
|
|
808
|
-
}
|
|
809
|
-
|
|
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
|
|
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 =
|
|
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) =>
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
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
|
-
|
|
1644
|
-
|
|
1645
|
-
sequence,
|
|
1646
|
-
...provider && { provider },
|
|
1647
|
-
emittedAt: now().toISOString()
|
|
1896
|
+
...fromSeq && { fromSeq },
|
|
1897
|
+
limit: 1e4
|
|
1648
1898
|
});
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
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
|
-
|
|
1688
|
-
|
|
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
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
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
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
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: "
|
|
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
|
-
|
|
2319
|
+
eventsSinceCheckpoint = 0;
|
|
2320
|
+
if (part.type === "finish-step")
|
|
2321
|
+
operationLifecycle.checkpointStep(step - 1);
|
|
1732
2322
|
}
|
|
1733
|
-
|
|
1734
|
-
|
|
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: "
|
|
2326
|
+
type: "attempt-reset",
|
|
1763
2327
|
conversationId: run.conversationId,
|
|
1764
2328
|
runId: run.id,
|
|
1765
2329
|
runtimeEpoch,
|
|
1766
|
-
sequence,
|
|
1767
|
-
|
|
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
|
-
|
|
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 = "
|
|
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
|
|
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,
|
|
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 };
|