tinker-agent 1.0.65
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/README.md +173 -0
- package/package.json +78 -0
- package/patches/markdansi@0.3.2.patch +37 -0
- package/src/agent/context-builder.ts +43 -0
- package/src/agent/context-meter.ts +310 -0
- package/src/agent/loop.ts +525 -0
- package/src/agent/runtime-session.ts +1212 -0
- package/src/agent/session-ledger.ts +828 -0
- package/src/agent/turn-cancellation.ts +44 -0
- package/src/agent/types.ts +77 -0
- package/src/cli/config.ts +283 -0
- package/src/cli/index.ts +29 -0
- package/src/cli/model-profiles.ts +289 -0
- package/src/cli/run-runner.ts +107 -0
- package/src/cli/tui-runner.tsx +290 -0
- package/src/context/compiled-context-hash.ts +138 -0
- package/src/context/compiled-context-validator.ts +209 -0
- package/src/context/context-manager.ts +362 -0
- package/src/context/context-policy.ts +8 -0
- package/src/context/context-protocol-validator.ts +463 -0
- package/src/context/context-revision-compiler.ts +281 -0
- package/src/context/context-revision.ts +111 -0
- package/src/context/context-source.ts +30 -0
- package/src/context/context-swap-renderer.ts +272 -0
- package/src/context/protocol-frame.ts +240 -0
- package/src/context/swap-planner.ts +725 -0
- package/src/events/append-private-file.ts +16 -0
- package/src/events/bash-result-detail.ts +70 -0
- package/src/events/composite-event-sink.ts +82 -0
- package/src/events/event-sink.ts +16 -0
- package/src/events/jsonl-event-log.ts +13 -0
- package/src/events/observation-text-log.ts +195 -0
- package/src/events/stdout-event-printer.ts +396 -0
- package/src/events/types.ts +263 -0
- package/src/ids/runtime-id.ts +68 -0
- package/src/ids/uuid-v7.ts +5 -0
- package/src/instructions/project-instructions.ts +242 -0
- package/src/mcp/mcp-config.ts +144 -0
- package/src/mcp/mcp-manager.ts +216 -0
- package/src/mcp/mcp-tool-executor.ts +178 -0
- package/src/model/committed-prefix-auditor.ts +68 -0
- package/src/model/fake-model-client.ts +280 -0
- package/src/model/model-client.ts +64 -0
- package/src/model/model-context-profile.ts +134 -0
- package/src/model/model-request-preflight.ts +120 -0
- package/src/model/openai-chat-mapping.ts +444 -0
- package/src/model/openai-chat-model-client.ts +190 -0
- package/src/model/prompt-prefix-hash.ts +47 -0
- package/src/model/token-estimator.ts +148 -0
- package/src/observation/observation-builder.ts +481 -0
- package/src/session/resume-projection.ts +616 -0
- package/src/session/session-catalog.ts +270 -0
- package/src/session/session-errors.ts +121 -0
- package/src/session/session-history-reader.ts +535 -0
- package/src/session/session-lock.ts +291 -0
- package/src/session/session-schema.ts +741 -0
- package/src/session/session-store.ts +3067 -0
- package/src/session/sqlite-session-ledger.ts +153 -0
- package/src/tools/bash-task.ts +617 -0
- package/src/tools/bash.ts +450 -0
- package/src/tools/cwd-state.ts +22 -0
- package/src/tools/edit.ts +428 -0
- package/src/tools/file-diff.ts +116 -0
- package/src/tools/glob.ts +202 -0
- package/src/tools/grep.ts +550 -0
- package/src/tools/hash.ts +9 -0
- package/src/tools/path-safety.ts +33 -0
- package/src/tools/read.ts +319 -0
- package/src/tools/recall.ts +400 -0
- package/src/tools/registry.ts +213 -0
- package/src/tools/ripgrep.ts +220 -0
- package/src/tools/task-list.ts +59 -0
- package/src/tools/task-output-snapshot.ts +47 -0
- package/src/tools/task-output-tool.ts +62 -0
- package/src/tools/task-output.ts +159 -0
- package/src/tools/task-stop.ts +59 -0
- package/src/tools/task-tool-args.ts +29 -0
- package/src/tools/types.ts +330 -0
- package/src/tools/web-fetch/backend.ts +27 -0
- package/src/tools/web-fetch/browser-backend.ts +126 -0
- package/src/tools/web-fetch/exa-backend.ts +172 -0
- package/src/tools/web-fetch/index.ts +298 -0
- package/src/tools/web-fetch/local-backend.ts +267 -0
- package/src/tools/web-fetch/refiner.ts +78 -0
- package/src/tools/web-fetch/route.ts +95 -0
- package/src/tools/web-search.ts +300 -0
- package/src/tools/write.ts +244 -0
- package/src/tui/app.tsx +497 -0
- package/src/tui/components/assistant-markdown.tsx +47 -0
- package/src/tui/components/background-tasks.tsx +92 -0
- package/src/tui/components/bash-result-view.tsx +47 -0
- package/src/tui/components/context-status.tsx +127 -0
- package/src/tui/components/diff-view.tsx +151 -0
- package/src/tui/components/file-viewer.tsx +212 -0
- package/src/tui/components/footer.tsx +60 -0
- package/src/tui/components/header.tsx +21 -0
- package/src/tui/components/model-picker.tsx +142 -0
- package/src/tui/components/prompt-input.tsx +432 -0
- package/src/tui/components/resume-session-picker.tsx +273 -0
- package/src/tui/components/timeline.tsx +121 -0
- package/src/tui/context-format.ts +24 -0
- package/src/tui/event-store.ts +865 -0
- package/src/tui/git-branch.ts +23 -0
- package/src/tui/line-editor.ts +157 -0
- package/src/tui/prompt-history.ts +94 -0
- package/src/tui/slash-commands.ts +126 -0
- package/src/tui/tui-projection-policy.ts +35 -0
- package/src/tui/tui-projection-store.ts +123 -0
- package/src/tui/tui-session-controller.ts +170 -0
- package/src/tui/view-file.ts +122 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import type { ModelClient, PreparedModelRequest } from "../model/model-client";
|
|
2
|
+
import {
|
|
3
|
+
CommittedPrefixAuditError,
|
|
4
|
+
CommittedPrefixAuditor,
|
|
5
|
+
} from "../model/committed-prefix-auditor";
|
|
6
|
+
import type { ObservationBuilder } from "../observation/observation-builder";
|
|
7
|
+
import type { ToolRegistry, ToolRuntime } from "../tools/registry";
|
|
8
|
+
import { ToolExecutionFatalError } from "../tools/types";
|
|
9
|
+
import type { ContextMeter } from "./context-meter";
|
|
10
|
+
import type { RuntimeSessionContext } from "./runtime-session";
|
|
11
|
+
import type { AgentTurnLedger } from "./session-ledger";
|
|
12
|
+
import { ContextProtocolError } from "../context/context-protocol-validator";
|
|
13
|
+
import { CompiledContextError } from "../context/compiled-context-validator";
|
|
14
|
+
import { ContextRevisionError } from "../context/context-revision-compiler";
|
|
15
|
+
import type { BuiltContextRequest } from "../context/context-revision";
|
|
16
|
+
import { swapOnlyPolicyV1 } from "../context/context-policy";
|
|
17
|
+
import {
|
|
18
|
+
SwapPlanningDiagnosticError,
|
|
19
|
+
type SwapPlanningResult,
|
|
20
|
+
type SwapPlanningTrigger,
|
|
21
|
+
type SwapPlanner,
|
|
22
|
+
} from "../context/swap-planner";
|
|
23
|
+
import { SessionError } from "../session/session-errors";
|
|
24
|
+
import {
|
|
25
|
+
normalizeSyntheticDetail,
|
|
26
|
+
type SyntheticToolCompletionInput,
|
|
27
|
+
} from "../context/protocol-frame";
|
|
28
|
+
import { throwIfTurnCancelled, turnCancellationSource } from "./turn-cancellation";
|
|
29
|
+
import type {
|
|
30
|
+
IterationIdentity,
|
|
31
|
+
RunAgentResult,
|
|
32
|
+
ToolCall,
|
|
33
|
+
TurnCancellation,
|
|
34
|
+
TurnIdentity,
|
|
35
|
+
} from "./types";
|
|
36
|
+
|
|
37
|
+
export type RunAgentInput = {
|
|
38
|
+
ledger: AgentTurnLedger;
|
|
39
|
+
maxIterations: number;
|
|
40
|
+
model: ModelClient;
|
|
41
|
+
contextMeter: ContextMeter;
|
|
42
|
+
committedPrefixAuditor?: CommittedPrefixAuditor;
|
|
43
|
+
shadowPlanning?: {
|
|
44
|
+
planner: SwapPlanner;
|
|
45
|
+
select(input: {
|
|
46
|
+
built: BuiltContextRequest;
|
|
47
|
+
preflight: ReturnType<ContextMeter["measure"]>;
|
|
48
|
+
}):
|
|
49
|
+
| {
|
|
50
|
+
trigger: Exclude<SwapPlanningTrigger, "manual">;
|
|
51
|
+
forcedTargetTokens?: number;
|
|
52
|
+
}
|
|
53
|
+
| undefined;
|
|
54
|
+
onResult?(result: SwapPlanningResult, built: BuiltContextRequest): void;
|
|
55
|
+
};
|
|
56
|
+
tools: ToolRegistry;
|
|
57
|
+
toolRuntime: ToolRuntime;
|
|
58
|
+
observationBuilder: ObservationBuilder;
|
|
59
|
+
runtimeSession: RuntimeSessionContext;
|
|
60
|
+
turn: TurnIdentity;
|
|
61
|
+
signal: AbortSignal;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export class FatalAgentTurnError extends Error {
|
|
65
|
+
constructor(
|
|
66
|
+
readonly result: Extract<RunAgentResult, { status: "failed" }>,
|
|
67
|
+
options?: ErrorOptions,
|
|
68
|
+
) {
|
|
69
|
+
super(result.error, options);
|
|
70
|
+
this.name = "FatalAgentTurnError";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function runAgent(input: RunAgentInput): Promise<RunAgentResult> {
|
|
75
|
+
let lastIteration: IterationIdentity | undefined;
|
|
76
|
+
const committedPrefixAuditor =
|
|
77
|
+
input.committedPrefixAuditor ?? new CommittedPrefixAuditor();
|
|
78
|
+
|
|
79
|
+
for (
|
|
80
|
+
let iterationNumber = 1;
|
|
81
|
+
iterationNumber <= input.maxIterations;
|
|
82
|
+
iterationNumber += 1
|
|
83
|
+
) {
|
|
84
|
+
const iteration = input.runtimeSession.createIteration(input.turn, iterationNumber);
|
|
85
|
+
lastIteration = iteration;
|
|
86
|
+
await input.runtimeSession.append({
|
|
87
|
+
type: "agent.iteration.started",
|
|
88
|
+
...iteration,
|
|
89
|
+
data: { iterationNumber },
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (input.signal.aborted) {
|
|
93
|
+
return cancelledResult(
|
|
94
|
+
cancellation(input.signal, iteration, "agent_boundary"),
|
|
95
|
+
iteration,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let prepared: PreparedModelRequest;
|
|
100
|
+
let built: BuiltContextRequest;
|
|
101
|
+
let preflight;
|
|
102
|
+
try {
|
|
103
|
+
throwIfTurnCancelled(input.signal);
|
|
104
|
+
built = input.ledger.buildModelRequest(input.tools.definitions());
|
|
105
|
+
prepared = input.model.prepare(built.request);
|
|
106
|
+
committedPrefixAuditor.audit(built.compiled.revisionId, prepared);
|
|
107
|
+
preflight = input.contextMeter.measure(prepared);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (input.signal.aborted) {
|
|
110
|
+
return cancelledResult(
|
|
111
|
+
cancellation(input.signal, iteration, "agent_boundary"),
|
|
112
|
+
iteration,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (isCanonicalContextFailure(error)) {
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
return failedResult(error, iteration);
|
|
119
|
+
}
|
|
120
|
+
await input.runtimeSession.append({
|
|
121
|
+
type: "context.usage.updated",
|
|
122
|
+
...iteration,
|
|
123
|
+
data: { phase: "preflight", snapshot: preflight },
|
|
124
|
+
});
|
|
125
|
+
await runShadowPlanning({
|
|
126
|
+
input,
|
|
127
|
+
iteration,
|
|
128
|
+
built,
|
|
129
|
+
prepared,
|
|
130
|
+
preflight,
|
|
131
|
+
});
|
|
132
|
+
try {
|
|
133
|
+
input.contextMeter.assertWithinBudget(preflight);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return failedResult(error, iteration);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
await input.runtimeSession.append({
|
|
139
|
+
type: "model.request.started",
|
|
140
|
+
...iteration,
|
|
141
|
+
data: {},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
let modelOutput;
|
|
145
|
+
try {
|
|
146
|
+
throwIfTurnCancelled(input.signal);
|
|
147
|
+
modelOutput = await input.model.request(prepared, {
|
|
148
|
+
signal: input.signal,
|
|
149
|
+
identity: {
|
|
150
|
+
iteration,
|
|
151
|
+
runtimeSession: input.runtimeSession,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
throwIfTurnCancelled(input.signal);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (input.signal.aborted) {
|
|
157
|
+
return cancelledResult(
|
|
158
|
+
cancellation(input.signal, iteration, "model_request"),
|
|
159
|
+
iteration,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return failedResult(error, iteration);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
input.ledger.appendAssistant({
|
|
168
|
+
iteration,
|
|
169
|
+
message: modelOutput.message,
|
|
170
|
+
provider: prepared.provider,
|
|
171
|
+
model: prepared.model,
|
|
172
|
+
});
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if (error instanceof ContextProtocolError) {
|
|
175
|
+
return failedResult(error, iteration);
|
|
176
|
+
}
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
await input.runtimeSession.append({
|
|
181
|
+
type: "model.request.finished",
|
|
182
|
+
...iteration,
|
|
183
|
+
data: { output: modelOutput },
|
|
184
|
+
});
|
|
185
|
+
const measured = input.contextMeter.recordProviderUsage(prepared, modelOutput);
|
|
186
|
+
await input.runtimeSession.append({
|
|
187
|
+
type: "context.usage.updated",
|
|
188
|
+
...iteration,
|
|
189
|
+
data: { phase: "measured", snapshot: measured },
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const toolCalls = modelOutput.message.toolCalls ?? [];
|
|
193
|
+
if (toolCalls.length === 0) {
|
|
194
|
+
await input.runtimeSession.append({
|
|
195
|
+
type: "agent.iteration.finished",
|
|
196
|
+
...iteration,
|
|
197
|
+
data: { outcome: "completed", toolCallCount: 0 },
|
|
198
|
+
});
|
|
199
|
+
return {
|
|
200
|
+
status: "completed",
|
|
201
|
+
finalText: modelOutput.message.content ?? "",
|
|
202
|
+
lastIteration: iteration,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const progressContent = modelOutput.message.content?.trim();
|
|
207
|
+
if (progressContent !== undefined && progressContent !== "") {
|
|
208
|
+
await input.runtimeSession.append({
|
|
209
|
+
type: "assistant.progress",
|
|
210
|
+
...iteration,
|
|
211
|
+
data: { content: progressContent },
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (let callIndex = 0; callIndex < toolCalls.length; callIndex += 1) {
|
|
216
|
+
const call = requireToolCall(toolCalls, callIndex);
|
|
217
|
+
requireCallInIteration(call, iteration, callIndex + 1);
|
|
218
|
+
|
|
219
|
+
if (input.signal.aborted) {
|
|
220
|
+
input.ledger.commitToolCompletions(
|
|
221
|
+
cancelledToolCompletions(toolCalls, callIndex),
|
|
222
|
+
);
|
|
223
|
+
return cancelledResult(
|
|
224
|
+
cancellation(input.signal, iteration, "agent_boundary"),
|
|
225
|
+
iteration,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
input.ledger.assertCanExecuteTool(call);
|
|
230
|
+
|
|
231
|
+
await input.runtimeSession.append({
|
|
232
|
+
type: "tool.started",
|
|
233
|
+
...call,
|
|
234
|
+
data: { call },
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
let raw;
|
|
238
|
+
try {
|
|
239
|
+
raw = await input.toolRuntime.execute(call, { signal: input.signal });
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (!input.signal.aborted) {
|
|
242
|
+
input.ledger.commitToolCompletions(
|
|
243
|
+
failedToolCompletions(toolCalls, callIndex, error),
|
|
244
|
+
);
|
|
245
|
+
const result = failedResult(error, iteration);
|
|
246
|
+
if (error instanceof ToolExecutionFatalError) {
|
|
247
|
+
throw new FatalAgentTurnError(result, { cause: error });
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
input.ledger.commitToolCompletions(
|
|
253
|
+
cancelledToolCompletions(toolCalls, callIndex, call),
|
|
254
|
+
);
|
|
255
|
+
return cancelledResult(
|
|
256
|
+
cancellation(input.signal, iteration, "tool_execution", call),
|
|
257
|
+
iteration,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const observation = input.observationBuilder.build({ call, raw });
|
|
262
|
+
input.ledger.commitToolCompletions([
|
|
263
|
+
{
|
|
264
|
+
call,
|
|
265
|
+
kind: "returned",
|
|
266
|
+
raw,
|
|
267
|
+
observation: observation.content,
|
|
268
|
+
},
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
await input.runtimeSession.append({
|
|
272
|
+
type: "tool.raw_result",
|
|
273
|
+
...call,
|
|
274
|
+
data: { call, raw },
|
|
275
|
+
});
|
|
276
|
+
await input.runtimeSession.append({
|
|
277
|
+
type: "tool.finished",
|
|
278
|
+
...call,
|
|
279
|
+
data: { call, ok: raw.ok },
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
await input.runtimeSession.append({
|
|
283
|
+
type: "tool.observation",
|
|
284
|
+
...call,
|
|
285
|
+
data: { call, observation },
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
if (input.signal.aborted) {
|
|
289
|
+
if (callIndex + 1 < toolCalls.length) {
|
|
290
|
+
input.ledger.commitToolCompletions(
|
|
291
|
+
cancelledToolCompletions(toolCalls, callIndex + 1),
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
return cancelledResult(
|
|
295
|
+
cancellation(input.signal, iteration, "agent_boundary"),
|
|
296
|
+
iteration,
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
await input.runtimeSession.append({
|
|
302
|
+
type: "agent.iteration.finished",
|
|
303
|
+
...iteration,
|
|
304
|
+
data: { outcome: "continue", toolCallCount: toolCalls.length },
|
|
305
|
+
});
|
|
306
|
+
input.runtimeSession.finishIterationForContinuation(iteration);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (lastIteration === undefined) {
|
|
310
|
+
throw new Error("Agent loop did not create an iteration identity.");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
status: "failed",
|
|
315
|
+
error: `Agent turn ${input.turn.turnId} stopped after maxIterations=${input.maxIterations}; last iteration=${lastIteration.iterationId}`,
|
|
316
|
+
lastIteration,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function runShadowPlanning(input: {
|
|
321
|
+
input: RunAgentInput;
|
|
322
|
+
iteration: IterationIdentity;
|
|
323
|
+
built: BuiltContextRequest;
|
|
324
|
+
prepared: PreparedModelRequest;
|
|
325
|
+
preflight: ReturnType<ContextMeter["measure"]>;
|
|
326
|
+
}): Promise<void> {
|
|
327
|
+
const shadowPlanning = input.input.shadowPlanning;
|
|
328
|
+
if (shadowPlanning === undefined) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const decision = shadowPlanning.select({
|
|
332
|
+
built: input.built,
|
|
333
|
+
preflight: input.preflight,
|
|
334
|
+
});
|
|
335
|
+
if (decision === undefined) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const startedAt = performance.now();
|
|
340
|
+
let result: SwapPlanningResult;
|
|
341
|
+
try {
|
|
342
|
+
result = shadowPlanning.planner.plan({
|
|
343
|
+
active: input.built.compiled,
|
|
344
|
+
revision: input.built.revision,
|
|
345
|
+
activeOverrides: input.built.activeOverrides,
|
|
346
|
+
canonical: input.built.canonical,
|
|
347
|
+
activePrepared: input.prepared,
|
|
348
|
+
activeUsage: input.preflight,
|
|
349
|
+
tools: input.input.tools.definitions(),
|
|
350
|
+
policy: swapOnlyPolicyV1,
|
|
351
|
+
trigger: decision.trigger,
|
|
352
|
+
...(decision.forcedTargetTokens === undefined
|
|
353
|
+
? {}
|
|
354
|
+
: { forcedTargetTokens: decision.forcedTargetTokens }),
|
|
355
|
+
});
|
|
356
|
+
} catch (error) {
|
|
357
|
+
if (isCanonicalContextFailure(error)) {
|
|
358
|
+
throw error;
|
|
359
|
+
}
|
|
360
|
+
const failure =
|
|
361
|
+
error instanceof SwapPlanningDiagnosticError
|
|
362
|
+
? error
|
|
363
|
+
: new SwapPlanningDiagnosticError(
|
|
364
|
+
"validate",
|
|
365
|
+
"unexpected_shadow_failure",
|
|
366
|
+
"Shadow planning failed without changing the active request.",
|
|
367
|
+
);
|
|
368
|
+
await input.input.runtimeSession.append({
|
|
369
|
+
type: "context.shadow.failed",
|
|
370
|
+
...input.iteration,
|
|
371
|
+
data: {
|
|
372
|
+
policyVersion: "swap-only-v1",
|
|
373
|
+
stage: failure.stage,
|
|
374
|
+
errorCode: failure.code,
|
|
375
|
+
error: failure.message,
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
shadowPlanning.onResult?.(result, input.built);
|
|
381
|
+
|
|
382
|
+
await input.input.runtimeSession.append({
|
|
383
|
+
type: "context.shadow.planned",
|
|
384
|
+
...input.iteration,
|
|
385
|
+
data: {
|
|
386
|
+
policyVersion: "swap-only-v1",
|
|
387
|
+
trigger: decision.trigger,
|
|
388
|
+
outcome: result.outcome,
|
|
389
|
+
canonicalMessageCount: result.canonicalMessageCount,
|
|
390
|
+
eligibleCandidateCount: result.eligibleCandidateCount,
|
|
391
|
+
selectedCandidateCount: result.plan?.addedOverrides.length ?? 0,
|
|
392
|
+
excludedByReason: { ...result.excludedByReason },
|
|
393
|
+
selectedByRawKind: { ...result.selectedByRawKind },
|
|
394
|
+
originalObservationBytes: result.originalObservationBytes,
|
|
395
|
+
projectedObservationBytes: result.projectedObservationBytes,
|
|
396
|
+
rawTokensBefore: result.rawTokensBefore,
|
|
397
|
+
...(result.plan === undefined
|
|
398
|
+
? {}
|
|
399
|
+
: {
|
|
400
|
+
rawTokensAfter: result.plan.rawTokensAfter,
|
|
401
|
+
guardedTokensAfter: result.plan.guardedTokensAfter,
|
|
402
|
+
planHash: result.plan.planHash,
|
|
403
|
+
}),
|
|
404
|
+
guardedTokensBefore: result.guardedTokensBefore,
|
|
405
|
+
targetTokens: result.targetTokens,
|
|
406
|
+
durationMs: Math.round((performance.now() - startedAt) * 100) / 100,
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function isCanonicalContextFailure(error: unknown): boolean {
|
|
412
|
+
return (
|
|
413
|
+
error instanceof ContextProtocolError ||
|
|
414
|
+
error instanceof ContextRevisionError ||
|
|
415
|
+
error instanceof CompiledContextError ||
|
|
416
|
+
error instanceof CommittedPrefixAuditError ||
|
|
417
|
+
error instanceof SessionError
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function cancelledToolCompletions(
|
|
422
|
+
toolCalls: readonly ToolCall[],
|
|
423
|
+
startIndex: number,
|
|
424
|
+
activeCall?: ToolCall,
|
|
425
|
+
): SyntheticToolCompletionInput[] {
|
|
426
|
+
const completions: SyntheticToolCompletionInput[] = [];
|
|
427
|
+
for (let index = startIndex; index < toolCalls.length; index += 1) {
|
|
428
|
+
const call = requireToolCall(toolCalls, index);
|
|
429
|
+
completions.push({
|
|
430
|
+
call,
|
|
431
|
+
kind: "synthetic",
|
|
432
|
+
reason: call === activeCall ? "cancelled_active" : "skipped_after_cancel",
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
return completions;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function failedToolCompletions(
|
|
439
|
+
toolCalls: readonly ToolCall[],
|
|
440
|
+
startIndex: number,
|
|
441
|
+
error: unknown,
|
|
442
|
+
): SyntheticToolCompletionInput[] {
|
|
443
|
+
const completions: SyntheticToolCompletionInput[] = [];
|
|
444
|
+
for (let index = startIndex; index < toolCalls.length; index += 1) {
|
|
445
|
+
const call = requireToolCall(toolCalls, index);
|
|
446
|
+
completions.push(
|
|
447
|
+
index === startIndex
|
|
448
|
+
? {
|
|
449
|
+
call,
|
|
450
|
+
kind: "synthetic",
|
|
451
|
+
reason: "failed_active",
|
|
452
|
+
detail: normalizeSyntheticDetail(error),
|
|
453
|
+
}
|
|
454
|
+
: { call, kind: "synthetic", reason: "skipped_after_failure" },
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
return completions;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function requireToolCall(toolCalls: readonly ToolCall[], index: number): ToolCall {
|
|
461
|
+
const call = toolCalls[index];
|
|
462
|
+
if (call === undefined) {
|
|
463
|
+
throw new Error(`Missing tool call at index ${index}.`);
|
|
464
|
+
}
|
|
465
|
+
return call;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function requireCallInIteration(
|
|
469
|
+
call: ToolCall,
|
|
470
|
+
iteration: IterationIdentity,
|
|
471
|
+
toolCallNumber: number,
|
|
472
|
+
): void {
|
|
473
|
+
if (
|
|
474
|
+
call.sessionId !== iteration.sessionId ||
|
|
475
|
+
call.turnId !== iteration.turnId ||
|
|
476
|
+
call.iterationId !== iteration.iterationId ||
|
|
477
|
+
call.toolCallNumber !== toolCallNumber
|
|
478
|
+
) {
|
|
479
|
+
throw new Error(
|
|
480
|
+
`Tool call ${call.toolCallId} has invalid identity for iteration ${iteration.iterationId}.`,
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function cancellation(
|
|
486
|
+
signal: AbortSignal,
|
|
487
|
+
iteration: IterationIdentity,
|
|
488
|
+
phase: TurnCancellation["phase"],
|
|
489
|
+
call?: ToolCall,
|
|
490
|
+
): TurnCancellation {
|
|
491
|
+
return {
|
|
492
|
+
source: turnCancellationSource(signal),
|
|
493
|
+
phase,
|
|
494
|
+
iterationId: iteration.iterationId,
|
|
495
|
+
iterationNumber: iteration.iterationNumber,
|
|
496
|
+
toolCallId: call?.toolCallId,
|
|
497
|
+
toolName: call?.name,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function cancelledResult(
|
|
502
|
+
turnCancellation: TurnCancellation,
|
|
503
|
+
lastIteration: IterationIdentity,
|
|
504
|
+
): RunAgentResult {
|
|
505
|
+
return {
|
|
506
|
+
status: "cancelled",
|
|
507
|
+
cancellation: turnCancellation,
|
|
508
|
+
lastIteration,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function failedResult(
|
|
513
|
+
error: unknown,
|
|
514
|
+
lastIteration: IterationIdentity,
|
|
515
|
+
): Extract<RunAgentResult, { status: "failed" }> {
|
|
516
|
+
return {
|
|
517
|
+
status: "failed",
|
|
518
|
+
error: errorMessage(error),
|
|
519
|
+
lastIteration,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function errorMessage(error: unknown): string {
|
|
524
|
+
return error instanceof Error ? error.message : String(error);
|
|
525
|
+
}
|