stitchkit 0.85.1 → 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 +178 -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-mutation-queue.d.ts +21 -0
- package/dist/agent-runtime/run-mutation-queue.d.ts.map +1 -0
- package/dist/agent-runtime/run-operation-lifecycle.d.ts +3 -0
- 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-jpp7jd1p.js → index-33xckd7h.js} +898 -425
- 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 };
|
|
810
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
|
+
`);
|
|
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,11 +1169,44 @@ 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
|
+
|
|
1191
|
+
// src/agent-runtime/run-mutation-queue.ts
|
|
1192
|
+
function createRunMutationQueue() {
|
|
1193
|
+
let tail = Promise.resolve();
|
|
1194
|
+
return (mutation) => {
|
|
1195
|
+
const result = tail.then(mutation, mutation);
|
|
1196
|
+
tail = result.then(() => {
|
|
1197
|
+
return;
|
|
1198
|
+
}, () => {
|
|
1199
|
+
return;
|
|
1200
|
+
});
|
|
1201
|
+
return result;
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
|
|
937
1205
|
// src/agent-runtime/run-operation-lifecycle.ts
|
|
938
1206
|
import { wrapLanguageModel } from "ai";
|
|
939
1207
|
|
|
940
1208
|
// src/agent-runtime/runtime-internals.ts
|
|
941
|
-
import { z as
|
|
1209
|
+
import { z as z3 } from "zod";
|
|
942
1210
|
function findRun(runs, runId) {
|
|
943
1211
|
const run = runs.find((candidate) => candidate.id === runId);
|
|
944
1212
|
if (!run)
|
|
@@ -946,7 +1214,7 @@ function findRun(runs, runId) {
|
|
|
946
1214
|
return run;
|
|
947
1215
|
}
|
|
948
1216
|
function jsonValue(value) {
|
|
949
|
-
const parsed =
|
|
1217
|
+
const parsed = z3.json().safeParse(value);
|
|
950
1218
|
return parsed.success ? parsed.data : { message: "Non-JSON tool output omitted" };
|
|
951
1219
|
}
|
|
952
1220
|
function providerEnvelope(value) {
|
|
@@ -1084,7 +1352,7 @@ function createAgentRunOperationLifecycle(config) {
|
|
|
1084
1352
|
let providerCallId;
|
|
1085
1353
|
let checkpointedStep = -1;
|
|
1086
1354
|
const checkpointWaiters = new Map;
|
|
1087
|
-
const record = async (
|
|
1355
|
+
const record = (operation) => config.serialize(async () => {
|
|
1088
1356
|
const current = config.currentRun();
|
|
1089
1357
|
const snapshot = appliedSnapshot(await config.store.recordRunOperation({
|
|
1090
1358
|
conversationId: current.conversationId,
|
|
@@ -1106,14 +1374,16 @@ function createAgentRunOperationLifecycle(config) {
|
|
|
1106
1374
|
operation,
|
|
1107
1375
|
emittedAt: config.now().toISOString()
|
|
1108
1376
|
});
|
|
1377
|
+
});
|
|
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
|
+
}));
|
|
1109
1386
|
};
|
|
1110
|
-
const startModelRequest = (callId, step) => record(AgentRunOperationSchema.parse({
|
|
1111
|
-
operationId: `${callId}:${step}`,
|
|
1112
|
-
kind: "model-request",
|
|
1113
|
-
phase: "started",
|
|
1114
|
-
step,
|
|
1115
|
-
startedAt: config.now().toISOString()
|
|
1116
|
-
}));
|
|
1117
1387
|
return {
|
|
1118
1388
|
noteProviderCall(callId) {
|
|
1119
1389
|
providerCallId = callId;
|
|
@@ -1139,7 +1409,11 @@ function createAgentRunOperationLifecycle(config) {
|
|
|
1139
1409
|
throw new Error("AgentRuntime model call reached the provider without lifecycle identity");
|
|
1140
1410
|
}
|
|
1141
1411
|
await startModelRequest(callId, step);
|
|
1142
|
-
|
|
1412
|
+
try {
|
|
1413
|
+
return await doStream();
|
|
1414
|
+
} catch (error) {
|
|
1415
|
+
throw isOwnInputRefusal(error) ? error : markProviderOrigin(error);
|
|
1416
|
+
}
|
|
1143
1417
|
}
|
|
1144
1418
|
}
|
|
1145
1419
|
});
|
|
@@ -1204,6 +1478,39 @@ function snapshotForRunPrompt(snapshot, runId) {
|
|
|
1204
1478
|
messages: snapshot.messages.filter((message) => !ownedIds.has(message.id) || eligibleIds.has(message.id))
|
|
1205
1479
|
});
|
|
1206
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
|
+
}
|
|
1207
1514
|
function createRunExecutor(dependencies) {
|
|
1208
1515
|
const {
|
|
1209
1516
|
config,
|
|
@@ -1301,9 +1608,15 @@ function createRunExecutor(dependencies) {
|
|
|
1301
1608
|
const absorbed = new Map;
|
|
1302
1609
|
let eventsSinceCheckpoint = 0;
|
|
1303
1610
|
let sequence = 0;
|
|
1611
|
+
const transientSequence = () => {
|
|
1612
|
+
sequence += 1;
|
|
1613
|
+
return sequence;
|
|
1614
|
+
};
|
|
1304
1615
|
let terminalReason = "success";
|
|
1305
1616
|
let nonModelUsage = input.acceptedRun.usage;
|
|
1306
1617
|
let modelUsage;
|
|
1618
|
+
let abandonedUsage;
|
|
1619
|
+
const billedUsage = () => abandonedUsage && modelUsage ? addUsage(abandonedUsage, modelUsage) : abandonedUsage ?? modelUsage;
|
|
1307
1620
|
let usage = nonModelUsage;
|
|
1308
1621
|
let sawProviderFinish = false;
|
|
1309
1622
|
let step = 0;
|
|
@@ -1314,9 +1627,11 @@ function createRunExecutor(dependencies) {
|
|
|
1314
1627
|
let terminalPolicyName;
|
|
1315
1628
|
const idleDeadline = createIdleDeadline(input.signal, idleTimeoutMs);
|
|
1316
1629
|
const executionSignal = idleDeadline.signal;
|
|
1630
|
+
const serialize = createRunMutationQueue();
|
|
1317
1631
|
const operationLifecycle = createAgentRunOperationLifecycle({
|
|
1318
1632
|
store: config.store,
|
|
1319
1633
|
runtimeEpoch,
|
|
1634
|
+
serialize,
|
|
1320
1635
|
currentRun: () => run,
|
|
1321
1636
|
acceptSnapshot: (next) => {
|
|
1322
1637
|
snapshot = next;
|
|
@@ -1347,7 +1662,7 @@ function createRunExecutor(dependencies) {
|
|
|
1347
1662
|
...provider && { provider }
|
|
1348
1663
|
}));
|
|
1349
1664
|
};
|
|
1350
|
-
const checkpoint = async () => {
|
|
1665
|
+
const checkpoint = () => serialize(async () => {
|
|
1351
1666
|
assistant = AgentMessageSchema.parse({
|
|
1352
1667
|
...assistant,
|
|
1353
1668
|
parts,
|
|
@@ -1380,7 +1695,7 @@ function createRunExecutor(dependencies) {
|
|
|
1380
1695
|
metrics: checkpointMetrics,
|
|
1381
1696
|
emittedAt: now().toISOString()
|
|
1382
1697
|
});
|
|
1383
|
-
};
|
|
1698
|
+
});
|
|
1384
1699
|
try {
|
|
1385
1700
|
if (config.history?.compact) {
|
|
1386
1701
|
await operationLifecycle.startCompaction(generateId());
|
|
@@ -1409,7 +1724,8 @@ function createRunExecutor(dependencies) {
|
|
|
1409
1724
|
}
|
|
1410
1725
|
if (compacted.usage) {
|
|
1411
1726
|
nonModelUsage = addUsage(nonModelUsage, compacted.usage);
|
|
1412
|
-
|
|
1727
|
+
const billed = billedUsage();
|
|
1728
|
+
usage = billed ? addUsage(nonModelUsage, billed) : nonModelUsage;
|
|
1413
1729
|
}
|
|
1414
1730
|
}
|
|
1415
1731
|
const assertCurrent = async () => {
|
|
@@ -1473,6 +1789,18 @@ function createRunExecutor(dependencies) {
|
|
|
1473
1789
|
throw new AgentContextOverflowError("Agent context still exceeds the model budget after compaction");
|
|
1474
1790
|
}
|
|
1475
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
|
+
}
|
|
1476
1804
|
const projectHistory = async (source) => {
|
|
1477
1805
|
if (config.history?.project)
|
|
1478
1806
|
return config.history.project(source.messages);
|
|
@@ -1493,7 +1821,7 @@ function createRunExecutor(dependencies) {
|
|
|
1493
1821
|
throw new Error(`Invalid approval continuation ${decision.messageId}: ${decision.reason}`);
|
|
1494
1822
|
}
|
|
1495
1823
|
}
|
|
1496
|
-
carriedSystem = detailed.system;
|
|
1824
|
+
carriedSystem = [...durableSystem, ...detailed.system];
|
|
1497
1825
|
return [...detailed.messages];
|
|
1498
1826
|
};
|
|
1499
1827
|
const projectInputs = async (source) => {
|
|
@@ -1540,10 +1868,12 @@ function createRunExecutor(dependencies) {
|
|
|
1540
1868
|
return stopped;
|
|
1541
1869
|
});
|
|
1542
1870
|
}
|
|
1871
|
+
let takenThisAttempt = [];
|
|
1543
1872
|
const takeInjectedMessages = async () => {
|
|
1544
1873
|
const taken = injection?.take(input.key, run.id) ?? [];
|
|
1545
1874
|
if (taken.length === 0)
|
|
1546
1875
|
return [];
|
|
1876
|
+
takenThisAttempt.push(...taken);
|
|
1547
1877
|
const messages = [];
|
|
1548
1878
|
for (const entry of taken) {
|
|
1549
1879
|
messages.push(...await projectInputs([entry.input]));
|
|
@@ -1554,324 +1884,456 @@ function createRunExecutor(dependencies) {
|
|
|
1554
1884
|
return messages;
|
|
1555
1885
|
};
|
|
1556
1886
|
const fallbackModel = selectedModel.model;
|
|
1557
|
-
const
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
onLanguageModelCallStart: (event) => {
|
|
1566
|
-
operationLifecycle.noteProviderCall(event.callId);
|
|
1567
|
-
},
|
|
1568
|
-
repairToolCall: deferredToolRepair(config.loop?.prepareStep),
|
|
1569
|
-
...config.loop?.toolApproval && {
|
|
1570
|
-
toolApproval: config.loop.toolApproval,
|
|
1571
|
-
runtimeContext: input.context
|
|
1572
|
-
},
|
|
1573
|
-
...config.loop?.toolApprovalSecret && {
|
|
1574
|
-
experimental_toolApprovalSecret: config.loop.toolApprovalSecret
|
|
1575
|
-
},
|
|
1576
|
-
prepareStep: async (options) => {
|
|
1577
|
-
const previousStep = options.steps.at(-1);
|
|
1578
|
-
if (previousStep) {
|
|
1579
|
-
lastPromptTokens = selectedModel?.normalizeUsage?.({
|
|
1580
|
-
usage: previousStep.usage,
|
|
1581
|
-
providerMetadata: previousStep.providerMetadata
|
|
1582
|
-
})?.inputTokens ?? normalizeSdkUsage(previousStep.usage).inputTokens;
|
|
1583
|
-
}
|
|
1584
|
-
const prepared = await config.loop?.prepareStep?.({
|
|
1585
|
-
...options,
|
|
1586
|
-
...runtimeContext
|
|
1587
|
-
});
|
|
1588
|
-
const injected = await takeInjectedMessages();
|
|
1589
|
-
const preparedStep = injected.length === 0 ? prepared : {
|
|
1590
|
-
...prepared,
|
|
1591
|
-
messages: [...prepared?.messages ?? options.messages, ...injected]
|
|
1592
|
-
};
|
|
1593
|
-
return {
|
|
1594
|
-
...preparedStep,
|
|
1595
|
-
model: await operationLifecycle.prepareModel(preparedStep?.model ?? fallbackModel, options.stepNumber, generateId())
|
|
1596
|
-
};
|
|
1597
|
-
}
|
|
1598
|
-
});
|
|
1599
|
-
for await (const part of result.stream) {
|
|
1600
|
-
idleDeadline.touch();
|
|
1601
|
-
eventsSinceCheckpoint += 1;
|
|
1602
|
-
sequence += 1;
|
|
1603
|
-
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")) {
|
|
1604
|
-
firstOutputAt = performance.now();
|
|
1605
|
-
}
|
|
1606
|
-
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") {
|
|
1607
|
-
await operationLifecycle.firstOutput();
|
|
1608
|
-
}
|
|
1609
|
-
if (part.type === "text-delta") {
|
|
1610
|
-
appendText(parts, part.text);
|
|
1611
|
-
await publish({
|
|
1612
|
-
type: "assistant-delta",
|
|
1613
|
-
conversationId: run.conversationId,
|
|
1614
|
-
runId: run.id,
|
|
1615
|
-
runtimeEpoch,
|
|
1616
|
-
sequence,
|
|
1617
|
-
textDelta: part.text,
|
|
1618
|
-
emittedAt: now().toISOString()
|
|
1619
|
-
});
|
|
1620
|
-
} else if (part.type === "reasoning-start") {
|
|
1621
|
-
reasoningPartIndex = undefined;
|
|
1622
|
-
updateReasoning("", part.providerMetadata);
|
|
1623
|
-
const provider = providerEnvelope(part.providerMetadata);
|
|
1624
|
-
await publish({
|
|
1625
|
-
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({
|
|
1626
1895
|
conversationId: run.conversationId,
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
sequence,
|
|
1630
|
-
...provider && { provider },
|
|
1631
|
-
emittedAt: now().toISOString()
|
|
1632
|
-
});
|
|
1633
|
-
} else if (part.type === "reasoning-delta") {
|
|
1634
|
-
updateReasoning(part.text, part.providerMetadata);
|
|
1635
|
-
const provider = providerEnvelope(part.providerMetadata);
|
|
1636
|
-
await publish({
|
|
1637
|
-
type: "reasoning-delta",
|
|
1638
|
-
conversationId: run.conversationId,
|
|
1639
|
-
runId: run.id,
|
|
1640
|
-
runtimeEpoch,
|
|
1641
|
-
sequence,
|
|
1642
|
-
textDelta: part.text,
|
|
1643
|
-
...provider && { provider },
|
|
1644
|
-
emittedAt: now().toISOString()
|
|
1645
|
-
});
|
|
1646
|
-
} else if (part.type === "reasoning-end") {
|
|
1647
|
-
updateReasoning("", part.providerMetadata);
|
|
1648
|
-
reasoningPartIndex = undefined;
|
|
1649
|
-
const provider = providerEnvelope(part.providerMetadata);
|
|
1650
|
-
await publish({
|
|
1651
|
-
type: "reasoning-end",
|
|
1652
|
-
conversationId: run.conversationId,
|
|
1653
|
-
runId: run.id,
|
|
1654
|
-
runtimeEpoch,
|
|
1655
|
-
sequence,
|
|
1656
|
-
...provider && { provider },
|
|
1657
|
-
emittedAt: now().toISOString()
|
|
1896
|
+
...fromSeq && { fromSeq },
|
|
1897
|
+
limit: 1e4
|
|
1658
1898
|
});
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
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({
|
|
1670
1918
|
conversationId: run.conversationId,
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
sequence,
|
|
1674
|
-
callId: part.toolCallId,
|
|
1675
|
-
toolName: part.toolName,
|
|
1676
|
-
status: "started",
|
|
1677
|
-
input: jsonValue(part.input),
|
|
1678
|
-
emittedAt: now().toISOString()
|
|
1919
|
+
kind: "provider/message",
|
|
1920
|
+
payload: { sha256, message: JSON.parse(body) }
|
|
1679
1921
|
});
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
await publish({
|
|
1689
|
-
type: "tool-status",
|
|
1690
|
-
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: {
|
|
1691
1930
|
runId: run.id,
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
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
|
+
}));
|
|
1703
2136
|
await publish({
|
|
1704
2137
|
type: "tool-status",
|
|
1705
2138
|
conversationId: run.conversationId,
|
|
1706
2139
|
runId: run.id,
|
|
1707
2140
|
runtimeEpoch,
|
|
1708
|
-
sequence,
|
|
2141
|
+
sequence: transientSequence(),
|
|
2142
|
+
callId: part.toolCallId,
|
|
2143
|
+
toolName: part.toolName,
|
|
2144
|
+
status: "completed",
|
|
2145
|
+
output: jsonValue(part.output),
|
|
2146
|
+
emittedAt: now().toISOString()
|
|
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",
|
|
1709
2168
|
callId: part.toolCallId,
|
|
1710
2169
|
toolName: part.toolName,
|
|
1711
|
-
|
|
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,
|
|
1712
2294
|
emittedAt: now().toISOString()
|
|
1713
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) {
|
|
1714
2318
|
await checkpoint();
|
|
1715
|
-
|
|
2319
|
+
eventsSinceCheckpoint = 0;
|
|
2320
|
+
if (part.type === "finish-step")
|
|
2321
|
+
operationLifecycle.checkpointStep(step - 1);
|
|
1716
2322
|
}
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
type: "tool-result",
|
|
1720
|
-
callId: part.toolCallId,
|
|
1721
|
-
toolName: part.toolName,
|
|
1722
|
-
outcome: "error",
|
|
1723
|
-
output
|
|
1724
|
-
}));
|
|
1725
|
-
await publish({
|
|
1726
|
-
type: "tool-status",
|
|
1727
|
-
conversationId: run.conversationId,
|
|
1728
|
-
runId: run.id,
|
|
1729
|
-
runtimeEpoch,
|
|
1730
|
-
sequence,
|
|
1731
|
-
callId: part.toolCallId,
|
|
1732
|
-
toolName: part.toolName,
|
|
1733
|
-
status: "failed",
|
|
1734
|
-
output,
|
|
1735
|
-
emittedAt: now().toISOString()
|
|
1736
|
-
});
|
|
1737
|
-
} else if (part.type === "tool-output-denied") {
|
|
1738
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1739
|
-
type: "tool-result",
|
|
1740
|
-
callId: part.toolCallId,
|
|
1741
|
-
toolName: part.toolName,
|
|
1742
|
-
outcome: "error",
|
|
1743
|
-
output: { message: "Tool output denied" }
|
|
1744
|
-
}));
|
|
2323
|
+
}
|
|
2324
|
+
if (retrying) {
|
|
1745
2325
|
await publish({
|
|
1746
|
-
type: "
|
|
2326
|
+
type: "attempt-reset",
|
|
1747
2327
|
conversationId: run.conversationId,
|
|
1748
2328
|
runId: run.id,
|
|
1749
2329
|
runtimeEpoch,
|
|
1750
|
-
sequence,
|
|
1751
|
-
|
|
1752
|
-
toolName: part.toolName,
|
|
1753
|
-
status: "failed",
|
|
1754
|
-
output: { message: "Tool output denied" },
|
|
2330
|
+
sequence: transientSequence(),
|
|
2331
|
+
attempt: retryAttempt,
|
|
1755
2332
|
emittedAt: now().toISOString()
|
|
1756
2333
|
});
|
|
1757
|
-
|
|
1758
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1759
|
-
type: "source",
|
|
1760
|
-
sourceId: part.id,
|
|
1761
|
-
...part.sourceType === "url" && { url: part.url },
|
|
1762
|
-
...part.title && { title: part.title }
|
|
1763
|
-
}));
|
|
1764
|
-
} else if (part.type === "file" && config.persistGeneratedFile) {
|
|
1765
|
-
const persisted = await config.persistGeneratedFile(part.file);
|
|
1766
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1767
|
-
type: "file",
|
|
1768
|
-
mediaType: part.file.mediaType,
|
|
1769
|
-
reference: persisted.reference,
|
|
1770
|
-
...persisted.filename && { filename: persisted.filename }
|
|
1771
|
-
}));
|
|
1772
|
-
} else if (part.type === "file") {
|
|
1773
|
-
throw new Error("persistGeneratedFile is required for generated file output");
|
|
1774
|
-
} else if (part.type === "reasoning-file" && config.persistGeneratedFile) {
|
|
1775
|
-
const persisted = await config.persistGeneratedFile(part.file);
|
|
1776
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1777
|
-
type: "file",
|
|
1778
|
-
mediaType: part.file.mediaType,
|
|
1779
|
-
reference: persisted.reference,
|
|
1780
|
-
...persisted.filename && { filename: persisted.filename }
|
|
1781
|
-
}));
|
|
1782
|
-
} else if (part.type === "reasoning-file") {
|
|
1783
|
-
throw new Error("persistGeneratedFile is required for generated reasoning files");
|
|
1784
|
-
} else if (part.type === "tool-approval-request") {
|
|
1785
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1786
|
-
type: "tool-approval-request",
|
|
1787
|
-
approvalId: part.approvalId,
|
|
1788
|
-
callId: part.toolCall.toolCallId,
|
|
1789
|
-
...part.isAutomatic !== undefined && { isAutomatic: part.isAutomatic },
|
|
1790
|
-
...part.signature && { signature: part.signature }
|
|
1791
|
-
}));
|
|
1792
|
-
} else if (part.type === "tool-approval-response") {
|
|
1793
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1794
|
-
type: "tool-approval-response",
|
|
1795
|
-
approvalId: part.approvalId,
|
|
1796
|
-
approved: part.approved,
|
|
1797
|
-
...part.reason && { reason: part.reason }
|
|
1798
|
-
}));
|
|
1799
|
-
} else if (part.type === "custom") {
|
|
1800
|
-
const provider = providerEnvelope(part.providerMetadata);
|
|
1801
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1802
|
-
type: "provider",
|
|
1803
|
-
envelope: {
|
|
1804
|
-
schemaVersion: 1,
|
|
1805
|
-
provider: "ai-sdk-custom",
|
|
1806
|
-
data: { kind: part.kind, ...provider && { provider: provider.data } }
|
|
1807
|
-
}
|
|
1808
|
-
}));
|
|
1809
|
-
} else if (part.type === "raw") {
|
|
1810
|
-
parts.push(AgentMessagePartSchema.parse({
|
|
1811
|
-
type: "provider",
|
|
1812
|
-
envelope: {
|
|
1813
|
-
schemaVersion: 1,
|
|
1814
|
-
provider: "ai-sdk-raw",
|
|
1815
|
-
data: { value: jsonValue(part.rawValue) }
|
|
1816
|
-
}
|
|
1817
|
-
}));
|
|
1818
|
-
} else if (part.type === "abort") {
|
|
1819
|
-
terminalReason = "interrupted";
|
|
1820
|
-
} else if (part.type === "error") {
|
|
1821
|
-
terminalReason = part.error instanceof AgentContextOverflowError ? "context_overflow" : "provider_failure";
|
|
1822
|
-
internalCause = part.error;
|
|
1823
|
-
} else if (part.type === "finish-step") {
|
|
1824
|
-
await operationLifecycle.finish(part.finishReason === "error" ? "failed" : "completed");
|
|
1825
|
-
const stepTrace = trace ? config.observe?.rootTrace(trace) : undefined;
|
|
1826
|
-
const stepUsage = selectedModel.normalizeUsage?.({
|
|
1827
|
-
usage: part.usage,
|
|
1828
|
-
providerMetadata: part.providerMetadata
|
|
1829
|
-
}) ?? normalizeSdkUsage(part.usage);
|
|
1830
|
-
lastPromptTokens = stepUsage.inputTokens;
|
|
1831
|
-
modelUsage = addUsage(modelUsage, stepUsage);
|
|
1832
|
-
usage = nonModelUsage ? addUsage(nonModelUsage, modelUsage) : modelUsage;
|
|
1833
|
-
config.observe?.emit({
|
|
1834
|
-
schemaVersion: 1,
|
|
1835
|
-
eventId: generateId(),
|
|
1836
|
-
type: "step-finished",
|
|
1837
|
-
conversationId: run.conversationId,
|
|
1838
|
-
runId: run.id,
|
|
1839
|
-
traceId: stepTrace?.traceId ?? trace?.traceId ?? generateId(),
|
|
1840
|
-
spanId: stepTrace?.spanId ?? generateId(),
|
|
1841
|
-
...stepTrace?.parentSpanId && { parentSpanId: stepTrace.parentSpanId },
|
|
1842
|
-
state: run.state,
|
|
1843
|
-
modelId: selectedModel.descriptor.modelId,
|
|
1844
|
-
step,
|
|
1845
|
-
usage: stepUsage,
|
|
1846
|
-
emittedAt: now().toISOString()
|
|
1847
|
-
});
|
|
1848
|
-
step += 1;
|
|
1849
|
-
} else if (part.type === "finish" && part.finishReason !== "stop") {
|
|
1850
|
-
if (terminalReason === "success") {
|
|
1851
|
-
terminalReason = part.finishReason === "error" ? "provider_failure" : "provider_stop";
|
|
1852
|
-
internalCause ??= { finishReason: part.finishReason };
|
|
1853
|
-
}
|
|
1854
|
-
}
|
|
1855
|
-
if (part.type === "finish") {
|
|
1856
|
-
sawProviderFinish = true;
|
|
1857
|
-
modelUsage = mergeModelTotals(normalizeSdkUsage(part.totalUsage), modelUsage);
|
|
1858
|
-
usage = nonModelUsage ? addUsage(nonModelUsage, modelUsage) : modelUsage;
|
|
1859
|
-
}
|
|
1860
|
-
const structuralBoundary = [
|
|
1861
|
-
"tool-call",
|
|
1862
|
-
"tool-result",
|
|
1863
|
-
"tool-error",
|
|
1864
|
-
"tool-output-denied",
|
|
1865
|
-
"tool-approval-request",
|
|
1866
|
-
"tool-approval-response",
|
|
1867
|
-
"finish-step"
|
|
1868
|
-
].includes(part.type);
|
|
1869
|
-
if (structuralBoundary || eventsSinceCheckpoint >= checkpointEveryEvents) {
|
|
1870
|
-
await checkpoint();
|
|
1871
|
-
eventsSinceCheckpoint = 0;
|
|
1872
|
-
if (part.type === "finish-step")
|
|
1873
|
-
operationLifecycle.checkpointStep(step - 1);
|
|
2334
|
+
continue;
|
|
1874
2335
|
}
|
|
2336
|
+
break;
|
|
1875
2337
|
}
|
|
1876
2338
|
await operationLifecycle.finish(executionSignal.aborted ? "cancelled" : terminalReason === "provider_failure" ? "failed" : "completed");
|
|
1877
2339
|
if (terminalPolicyName !== undefined)
|
|
@@ -1891,7 +2353,7 @@ function createRunExecutor(dependencies) {
|
|
|
1891
2353
|
reason: terminalReason,
|
|
1892
2354
|
...terminalPolicyName && { policyName: terminalPolicyName }
|
|
1893
2355
|
})) {
|
|
1894
|
-
terminalReason = "
|
|
2356
|
+
terminalReason = "output_rejected";
|
|
1895
2357
|
internalCause = new Error("Agent terminal output was rejected by the protocol");
|
|
1896
2358
|
}
|
|
1897
2359
|
}
|
|
@@ -1918,8 +2380,12 @@ function createRunExecutor(dependencies) {
|
|
|
1918
2380
|
type: "control",
|
|
1919
2381
|
reason: isToolExecutionControlError(error) && error.reason === "stale_run" ? "stale-run" : "run-interrupted"
|
|
1920
2382
|
}));
|
|
2383
|
+
} else if (error instanceof AgentContextOverflowError) {
|
|
2384
|
+
terminalReason = "context_overflow";
|
|
2385
|
+
} else if (error instanceof AgentRuntimeConflictError) {
|
|
2386
|
+
terminalReason = "storage_conflict";
|
|
1921
2387
|
} else {
|
|
1922
|
-
terminalReason = error
|
|
2388
|
+
terminalReason = failureThisRuntimeOwns(error) ?? (hasProviderOrigin(error) ? "provider_failure" : "runtime_failure");
|
|
1923
2389
|
}
|
|
1924
2390
|
} finally {
|
|
1925
2391
|
idleDeadline.dispose();
|
|
@@ -1991,6 +2457,13 @@ function createRunExecutor(dependencies) {
|
|
|
1991
2457
|
usage: spent,
|
|
1992
2458
|
...firstOutputAt !== undefined && { ttftMs: firstOutputAt - runStartedAt }
|
|
1993
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
|
+
}
|
|
1994
2467
|
emitSpend({
|
|
1995
2468
|
eventId: terminal.committedByCaller ? agentDurableEventId("terminal", run.id, observedVersion) : unsettledEventId(observedVersion),
|
|
1996
2469
|
state: run.state,
|
|
@@ -2623,4 +3096,4 @@ function createAgentRuntime(config) {
|
|
|
2623
3096
|
};
|
|
2624
3097
|
}
|
|
2625
3098
|
|
|
2626
|
-
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 };
|