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