@deepstrike/sdk 0.1.15 → 0.2.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/dist/collaboration/harness.d.ts +4 -1
- package/dist/collaboration/harness.js +20 -6
- package/dist/collaboration/modes/creator-verifier.d.ts +8 -2
- package/dist/collaboration/modes/creator-verifier.js +9 -3
- package/dist/collaboration/pool.d.ts +24 -3
- package/dist/collaboration/pool.js +65 -5
- package/dist/harness/harness.d.ts +5 -1
- package/dist/harness/harness.js +23 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +5 -0
- package/dist/kernel.d.ts +12 -43
- package/dist/kernel.js +1 -1
- package/dist/providers/anthropic.js +7 -2
- package/dist/providers/base.d.ts +12 -0
- package/dist/providers/base.js +75 -0
- package/dist/providers/catalog.d.ts +3 -2
- package/dist/providers/catalog.js +61 -13
- package/dist/providers/deepseek.js +1 -1
- package/dist/providers/gemini.d.ts +3 -0
- package/dist/providers/gemini.js +26 -6
- package/dist/providers/glm.d.ts +9 -0
- package/dist/providers/glm.js +21 -0
- package/dist/providers/kimi.js +2 -0
- package/dist/providers/minimax.js +5 -0
- package/dist/providers/openai-responses.js +9 -0
- package/dist/providers/openai.js +52 -6
- package/dist/providers/profiles.d.ts +1304 -242
- package/dist/providers/profiles.js +429 -26
- package/dist/providers/qwen.d.ts +3 -1
- package/dist/providers/qwen.js +43 -13
- package/dist/runtime/archive.d.ts +15 -0
- package/dist/runtime/archive.js +35 -0
- package/dist/runtime/execution-plane.js +14 -4
- package/dist/runtime/filtered-plane.d.ts +14 -0
- package/dist/runtime/filtered-plane.js +45 -0
- package/dist/runtime/kernel-step.d.ts +88 -0
- package/dist/runtime/kernel-step.js +262 -0
- package/dist/runtime/process-sandbox-plane.d.ts +4 -4
- package/dist/runtime/process-sandbox-plane.js +5 -5
- package/dist/runtime/provider-replay.js +37 -3
- package/dist/runtime/replay-sanitize.d.ts +5 -0
- package/dist/runtime/replay-sanitize.js +25 -0
- package/dist/runtime/runner.d.ts +60 -4
- package/dist/runtime/runner.js +589 -86
- package/dist/runtime/session-log.d.ts +93 -1
- package/dist/runtime/session-repair.d.ts +37 -0
- package/dist/runtime/session-repair.js +77 -0
- package/dist/runtime/sub-agent-orchestrator.d.ts +19 -0
- package/dist/runtime/sub-agent-orchestrator.js +114 -0
- package/dist/skills/watcher.d.ts +19 -0
- package/dist/skills/watcher.js +38 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.js +82 -11
- package/dist/types/agent.d.ts +68 -0
- package/dist/types/agent.js +78 -0
- package/dist/types.d.ts +27 -0
- package/package.json +2 -2
package/dist/runtime/runner.js
CHANGED
|
@@ -1,14 +1,104 @@
|
|
|
1
1
|
import { getKernel } from "../kernel.js";
|
|
2
2
|
import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-replay.js";
|
|
3
|
+
import { sanitizeReplayText } from "./replay-sanitize.js";
|
|
4
|
+
import { buildLlmCompletedEvent, buildRunTerminalEvent, repairEventsForRecovery } from "./session-repair.js";
|
|
5
|
+
import { capabilityMarker, capabilitySkill, capabilityTool, capabilityCommandMount, capabilityCommandUnmount, kernelAction, kernelApply, forceCompact, messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
|
|
6
|
+
import { agentRunSpecToKernel, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel } from "../types/agent.js";
|
|
7
|
+
import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
|
|
3
8
|
export class RuntimeRunner {
|
|
4
9
|
opts;
|
|
5
10
|
interrupted = false;
|
|
11
|
+
activeKernel = null;
|
|
12
|
+
pendingObservations = [];
|
|
13
|
+
currentSessionId = null;
|
|
14
|
+
nextArchiveStart = 0;
|
|
6
15
|
constructor(opts) {
|
|
7
16
|
this.opts = opts;
|
|
8
17
|
}
|
|
18
|
+
/** Host configuration (for coordinator / sub-agent spawn). */
|
|
19
|
+
get hostOptions() {
|
|
20
|
+
return this.opts;
|
|
21
|
+
}
|
|
22
|
+
/** Mount a tool capability on the currently-running kernel runtime. No-op if not running. */
|
|
23
|
+
mountTool(schema) {
|
|
24
|
+
if (!this.activeKernel)
|
|
25
|
+
return;
|
|
26
|
+
kernelApply(this.activeKernel, this.pendingObservations, capabilityCommandMount(capabilityTool(schema)));
|
|
27
|
+
}
|
|
28
|
+
/** Mount a skill capability on the currently-running kernel runtime. No-op if not running. */
|
|
29
|
+
mountSkill(name, description) {
|
|
30
|
+
if (!this.activeKernel)
|
|
31
|
+
return;
|
|
32
|
+
kernelApply(this.activeKernel, this.pendingObservations, capabilityCommandMount(capabilitySkill({ name, description, estimatedTokens: 0 })));
|
|
33
|
+
}
|
|
34
|
+
/** Mount a generic marker capability (e.g. MCP server, agent) on the active run. No-op if not running. */
|
|
35
|
+
mountMarker(kind, id, description) {
|
|
36
|
+
if (!this.activeKernel)
|
|
37
|
+
return;
|
|
38
|
+
kernelApply(this.activeKernel, this.pendingObservations, capabilityCommandMount(capabilityMarker(kind, id, description)));
|
|
39
|
+
}
|
|
40
|
+
/** Unmount a capability by kind + id from the active run. No-op if not running. */
|
|
41
|
+
unmountCapability(kind, id) {
|
|
42
|
+
if (!this.activeKernel)
|
|
43
|
+
return;
|
|
44
|
+
kernelApply(this.activeKernel, this.pendingObservations, capabilityCommandUnmount(kind, id));
|
|
45
|
+
}
|
|
46
|
+
/** Push a large artifact into the kernel artifacts partition (not inlined in history). */
|
|
47
|
+
pushArtifact(message, tokens) {
|
|
48
|
+
if (!this.activeKernel)
|
|
49
|
+
return;
|
|
50
|
+
kernelApply(this.activeKernel, this.pendingObservations, {
|
|
51
|
+
kind: "push_artifact",
|
|
52
|
+
message: messageToKernelMessage(message),
|
|
53
|
+
...(tokens !== undefined ? { tokens } : {}),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Spawn an isolated sub-agent via the kernel, run it on the host, and feed the result back.
|
|
58
|
+
* Requires an active parent run (`run()` / `wake()` in progress or paused at milestone).
|
|
59
|
+
*/
|
|
60
|
+
async *spawnSubAgent(spec) {
|
|
61
|
+
if (!this.activeKernel || !this.currentSessionId) {
|
|
62
|
+
throw new Error("spawnSubAgent requires an active parent run");
|
|
63
|
+
}
|
|
64
|
+
const parentSessionId = this.currentSessionId;
|
|
65
|
+
const runtime = this.activeKernel;
|
|
66
|
+
const observations = kernelApply(runtime, this.pendingObservations, {
|
|
67
|
+
kind: "spawn_sub_agent",
|
|
68
|
+
spec: agentRunSpecToKernel(spec),
|
|
69
|
+
parent_session_id: parentSessionId,
|
|
70
|
+
});
|
|
71
|
+
this.nextArchiveStart = await this.appendObservations(parentSessionId, runtime, this.nextArchiveStart);
|
|
72
|
+
const spawned = observations.find((o) => o.kind === "agent_spawned" && typeof o.agent_id === "string");
|
|
73
|
+
if (!spawned)
|
|
74
|
+
throw new Error("spawn_sub_agent did not emit agent_spawned");
|
|
75
|
+
const manifest = {
|
|
76
|
+
kind: "agent_spawned",
|
|
77
|
+
turn: spawned.turn,
|
|
78
|
+
agent_id: spawned.agent_id,
|
|
79
|
+
parent_session_id: spawned.parent_session_id ?? parentSessionId,
|
|
80
|
+
role: spawned.role ?? spec.role,
|
|
81
|
+
isolation: spawned.isolation ?? spec.isolation ?? "shared",
|
|
82
|
+
context_inheritance: spawned.context_inheritance ?? "none",
|
|
83
|
+
permitted_capability_ids: spawned.permitted_capability_ids ?? [],
|
|
84
|
+
};
|
|
85
|
+
const orchestrator = this.opts.subAgentOrchestrator ?? defaultSubAgentOrchestrator;
|
|
86
|
+
const result = await orchestrator.run({
|
|
87
|
+
parentOpts: this.opts,
|
|
88
|
+
parentSessionId,
|
|
89
|
+
spec,
|
|
90
|
+
manifest,
|
|
91
|
+
sessionLog: this.opts.sessionLog,
|
|
92
|
+
});
|
|
93
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
94
|
+
kind: "sub_agent_completed",
|
|
95
|
+
result: subAgentResultToKernel(result),
|
|
96
|
+
});
|
|
97
|
+
yield { type: "done", iterations: result.result.turnsUsed, totalTokens: result.result.totalTokensUsed, status: result.result.termination };
|
|
98
|
+
}
|
|
9
99
|
interrupt() { this.interrupted = true; }
|
|
10
100
|
async *run(req) {
|
|
11
|
-
const prior = await this.opts.sessionLog.read(req.sessionId);
|
|
101
|
+
const prior = req.inheritEvents ?? await this.opts.sessionLog.read(req.sessionId);
|
|
12
102
|
const midRun = isMidRun(prior);
|
|
13
103
|
if (!midRun) {
|
|
14
104
|
await this.opts.sessionLog.append(req.sessionId, {
|
|
@@ -32,14 +122,16 @@ export class RuntimeRunner {
|
|
|
32
122
|
const start = startEntry.event;
|
|
33
123
|
yield* this.execute(sessionId, start.goal, start.criteria, extensions, events, true);
|
|
34
124
|
}
|
|
35
|
-
async dream(agentId, nowMs = Date.now()) {
|
|
125
|
+
async *dream(agentId, nowMs = Date.now()) {
|
|
36
126
|
if (!this.opts.dreamStore)
|
|
37
127
|
throw new Error("dreamStore not configured");
|
|
38
128
|
const kernel = getKernel();
|
|
39
129
|
const sessions = await this.opts.dreamStore.loadSessions(agentId);
|
|
40
130
|
const existingMemories = await this.opts.dreamStore.loadMemories(agentId);
|
|
41
|
-
if (!sessions.length)
|
|
42
|
-
|
|
131
|
+
if (!sessions.length) {
|
|
132
|
+
yield { type: "done", iterations: 0, totalTokens: 0, status: "completed", dreamResult: { sessionsProcessed: 0, insightsExtracted: 0, entriesAdded: 0, entriesRemoved: 0 } };
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
43
135
|
const pipeline = new kernel.IdlePipeline(agentId);
|
|
44
136
|
const action1 = pipeline.feedTrigger(sessions.map(s => ({
|
|
45
137
|
sessionId: s.sessionId, agentId: s.agentId,
|
|
@@ -51,20 +143,27 @@ export class RuntimeRunner {
|
|
|
51
143
|
createdAtMs: s.createdAtMs, updatedAtMs: s.updatedAtMs,
|
|
52
144
|
})), existingMemories.map(e => ({ text: e.text, score: e.score, metadata: JSON.stringify(e.metadata ?? null) })), nowMs);
|
|
53
145
|
if (action1.kind === "noop" || action1.kind === "aborted") {
|
|
54
|
-
|
|
146
|
+
yield { type: "done", iterations: 0, totalTokens: 0, status: "completed", dreamResult: { sessionsProcessed: 0, insightsExtracted: 0, entriesAdded: 0, entriesRemoved: 0 } };
|
|
147
|
+
return;
|
|
55
148
|
}
|
|
56
149
|
if (action1.kind !== "synthesize_insights")
|
|
57
150
|
throw new Error(`unexpected: ${action1.kind}`);
|
|
58
151
|
let synthesisText = "";
|
|
59
152
|
const providerState = this.opts.provider.createRunState?.();
|
|
60
153
|
const synthMsgs = (action1.messages ?? []);
|
|
154
|
+
const kernelSystemText = synthMsgs.filter(m => m.role === "system").map(m => m.content).join("\n\n");
|
|
61
155
|
const synthContext = {
|
|
62
|
-
systemText:
|
|
156
|
+
systemText: [kernelSystemText, this.opts.dreamSystemPrompt].filter(Boolean).join("\n\n"),
|
|
63
157
|
turns: synthMsgs.filter(m => m.role !== "system"),
|
|
64
158
|
};
|
|
159
|
+
let totalTokens = 0;
|
|
65
160
|
for await (const evt of this.opts.provider.stream(synthContext, [], undefined, providerState)) {
|
|
66
|
-
if (evt.type === "text_delta")
|
|
161
|
+
if (evt.type === "text_delta") {
|
|
67
162
|
synthesisText += evt.delta;
|
|
163
|
+
yield evt;
|
|
164
|
+
}
|
|
165
|
+
else if (evt.type === "usage")
|
|
166
|
+
totalTokens = evt.totalTokens;
|
|
68
167
|
}
|
|
69
168
|
const action2 = pipeline.feedSynthesisResult(synthesisText);
|
|
70
169
|
if (action2.kind !== "commit_memories")
|
|
@@ -84,62 +183,131 @@ export class RuntimeRunner {
|
|
|
84
183
|
},
|
|
85
184
|
};
|
|
86
185
|
await this.opts.dreamStore.commit(agentId, dsResult, existingMemories);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
186
|
+
yield {
|
|
187
|
+
type: "done", iterations: 1, totalTokens, status: "completed",
|
|
188
|
+
dreamResult: {
|
|
189
|
+
sessionsProcessed: rr.sessionsProcessed,
|
|
190
|
+
insightsExtracted: rr.insightsExtracted,
|
|
191
|
+
entriesAdded: cr.stats?.entriesAdded ?? 0,
|
|
192
|
+
entriesRemoved: (cr.toRemoveIndices ?? []).length,
|
|
193
|
+
},
|
|
92
194
|
};
|
|
93
195
|
}
|
|
94
196
|
async *execute(sessionId, goal, criteria, extensions, priorEvents, resumeMidRun = false) {
|
|
95
197
|
this.interrupted = false;
|
|
198
|
+
this.pendingObservations = [];
|
|
199
|
+
this.currentSessionId = sessionId;
|
|
96
200
|
const kernel = getKernel();
|
|
97
201
|
const ext = { ...this.opts.extensions, ...(extensions ?? {}) };
|
|
98
202
|
const providerState = this.opts.provider.createRunState?.();
|
|
99
203
|
let nextCompressedArchiveStart = nextArchivedSeqStart(priorEvents);
|
|
100
|
-
// Three-layer policy merge: explicit RuntimeOptions > provider.runtimePolicy() > defaults
|
|
101
204
|
const providerPolicy = this.opts.provider.runtimePolicy?.() ?? {};
|
|
102
205
|
const effectiveMaxTurns = this.opts.maxTurns ?? providerPolicy.maxTurns ?? 25;
|
|
103
206
|
const effectiveTimeoutMs = this.opts.timeoutMs ?? providerPolicy.timeoutMs;
|
|
104
|
-
const
|
|
207
|
+
const runtime = new kernel.KernelRuntime({
|
|
105
208
|
maxTokens: this.opts.maxTokens,
|
|
106
209
|
maxTurns: effectiveMaxTurns,
|
|
107
210
|
timeoutMs: effectiveTimeoutMs !== undefined ? BigInt(effectiveTimeoutMs) : undefined,
|
|
108
211
|
});
|
|
212
|
+
this.activeKernel = runtime;
|
|
213
|
+
this.nextArchiveStart = nextCompressedArchiveStart;
|
|
109
214
|
const router = new kernel.SignalRouter(256);
|
|
110
|
-
|
|
215
|
+
if (this.opts.tokenizer) {
|
|
216
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
217
|
+
kind: "set_tokenizer",
|
|
218
|
+
name: this.opts.tokenizer,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (this.opts.enablePlanTool !== undefined) {
|
|
222
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
223
|
+
kind: "set_plan_tool_enabled",
|
|
224
|
+
enabled: this.opts.enablePlanTool,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
228
|
+
kind: "set_tools",
|
|
229
|
+
tools: this.opts.executionPlane.schemas().map(toolSchemaToKernel),
|
|
230
|
+
});
|
|
111
231
|
if (this.opts.systemPrompt) {
|
|
112
|
-
|
|
232
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
233
|
+
kind: "add_system_message",
|
|
234
|
+
content: this.opts.systemPrompt,
|
|
235
|
+
tokens: Math.max(1, Math.ceil(this.opts.systemPrompt.length / 4)),
|
|
236
|
+
});
|
|
113
237
|
}
|
|
114
238
|
if (this.opts.initialMemory) {
|
|
115
239
|
for (const mem of this.opts.initialMemory) {
|
|
116
|
-
|
|
240
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
241
|
+
kind: "add_memory_message",
|
|
242
|
+
content: mem,
|
|
243
|
+
tokens: Math.max(1, Math.ceil(mem.length / 4)),
|
|
244
|
+
});
|
|
117
245
|
}
|
|
118
246
|
}
|
|
119
247
|
if (this.opts.skillDir) {
|
|
120
248
|
const { scanSkillDir } = await import("../skills/loader.js");
|
|
121
249
|
const metas = await scanSkillDir(this.opts.skillDir);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
250
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
251
|
+
kind: "set_available_skills",
|
|
252
|
+
skills: metas.map((m) => skillMetadataToKernel({
|
|
253
|
+
name: m.name,
|
|
254
|
+
description: m.description,
|
|
255
|
+
whenToUse: m.whenToUse,
|
|
256
|
+
effort: m.effort,
|
|
257
|
+
estimatedTokens: m.estimatedTokens ?? 0,
|
|
258
|
+
})),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (this.opts.dreamStore && this.opts.agentId) {
|
|
262
|
+
kernelApply(runtime, this.pendingObservations, { kind: "set_memory_enabled", enabled: true });
|
|
263
|
+
}
|
|
264
|
+
if (this.opts.knowledgeSource) {
|
|
265
|
+
kernelApply(runtime, this.pendingObservations, { kind: "set_knowledge_enabled", enabled: true });
|
|
126
266
|
}
|
|
127
|
-
if (this.opts.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
267
|
+
if (this.opts.milestoneContract) {
|
|
268
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
269
|
+
kind: "load_milestone_contract",
|
|
270
|
+
contract: {
|
|
271
|
+
phases: this.opts.milestoneContract.phases.map(p => ({
|
|
272
|
+
id: p.id,
|
|
273
|
+
criteria: p.criteria ?? [],
|
|
274
|
+
unlocks: p.unlocks ?? [],
|
|
275
|
+
required_evidence: p.requiredEvidence ?? [],
|
|
276
|
+
...(p.verifier ? { verifier: p.verifier } : {}),
|
|
277
|
+
})),
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
const maxBytes = runtime.recoveryContentBytes();
|
|
131
282
|
if (priorEvents && priorEvents.length > 0) {
|
|
132
|
-
|
|
133
|
-
|
|
283
|
+
const repaired = repairEventsForRecovery(priorEvents, maxBytes);
|
|
284
|
+
seedProviderReplayFromEvents(this.opts.provider, repaired);
|
|
285
|
+
const loadArchive = this.opts.compressionStore
|
|
286
|
+
? (ref) => this.opts.compressionStore.read(ref)
|
|
287
|
+
: undefined;
|
|
288
|
+
const replayed = await replayMessagesAsync(repaired, maxBytes, loadArchive);
|
|
289
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
290
|
+
kind: "preload_history",
|
|
291
|
+
messages: replayed.map(messageToKernelMessage),
|
|
292
|
+
});
|
|
134
293
|
}
|
|
135
294
|
const sessionStart = Date.now();
|
|
295
|
+
const startPayload = {
|
|
296
|
+
kind: "start_run",
|
|
297
|
+
task: { goal, criteria },
|
|
298
|
+
};
|
|
299
|
+
if (this.opts.runSpec) {
|
|
300
|
+
startPayload.run_spec = agentRunSpecToKernel(this.opts.runSpec);
|
|
301
|
+
}
|
|
136
302
|
let action = resumeMidRun
|
|
137
|
-
?
|
|
138
|
-
:
|
|
139
|
-
|
|
140
|
-
|
|
303
|
+
? kernelAction(runtime, this.pendingObservations, { kind: "resume" })
|
|
304
|
+
: kernelAction(runtime, this.pendingObservations, startPayload);
|
|
305
|
+
let hasAttemptedReactiveCompact = false;
|
|
306
|
+
while (!runtime.isTerminal()) {
|
|
307
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
308
|
+
this.nextArchiveStart = nextCompressedArchiveStart;
|
|
141
309
|
if (this.interrupted) {
|
|
142
|
-
action =
|
|
310
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
143
311
|
break;
|
|
144
312
|
}
|
|
145
313
|
if (this.opts.signalSource) {
|
|
@@ -155,9 +323,9 @@ export class RuntimeRunner {
|
|
|
155
323
|
dedupeKey: sig.dedupeKey,
|
|
156
324
|
timestampMs: Date.now(),
|
|
157
325
|
};
|
|
158
|
-
const disposition = router.ingest(kernelSig, action.kind === "
|
|
326
|
+
const disposition = router.ingest(kernelSig, action.kind === "execute_tool");
|
|
159
327
|
if (disposition === "interrupt_now") {
|
|
160
|
-
action =
|
|
328
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
161
329
|
break;
|
|
162
330
|
}
|
|
163
331
|
}
|
|
@@ -165,19 +333,20 @@ export class RuntimeRunner {
|
|
|
165
333
|
let queued = router.next();
|
|
166
334
|
while (queued) {
|
|
167
335
|
if (queued.urgency === "critical") {
|
|
168
|
-
action =
|
|
336
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
169
337
|
break;
|
|
170
338
|
}
|
|
171
339
|
queued = router.next();
|
|
172
340
|
}
|
|
173
|
-
if (
|
|
341
|
+
if (runtime.isTerminal())
|
|
174
342
|
break;
|
|
175
|
-
if (action.kind === "
|
|
343
|
+
if (action.kind === "call_provider") {
|
|
176
344
|
const finalToolCalls = [];
|
|
177
345
|
let finalText = "";
|
|
178
346
|
const context = action.context;
|
|
179
|
-
const tools =
|
|
347
|
+
const tools = action.tools;
|
|
180
348
|
let turnTokens = 0;
|
|
349
|
+
let shouldRetry = false;
|
|
181
350
|
try {
|
|
182
351
|
for await (const evt of this.opts.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState)) {
|
|
183
352
|
if (evt.type === "usage") {
|
|
@@ -194,29 +363,51 @@ export class RuntimeRunner {
|
|
|
194
363
|
}
|
|
195
364
|
}
|
|
196
365
|
catch (err) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
366
|
+
const errMsg = String(err).toLowerCase();
|
|
367
|
+
if ((errMsg.includes("413") || errMsg.includes("too long") || errMsg.includes("context length exceeded") || errMsg.includes("context_length_exceeded")) &&
|
|
368
|
+
!hasAttemptedReactiveCompact) {
|
|
369
|
+
hasAttemptedReactiveCompact = true;
|
|
370
|
+
if (forceCompact(runtime, this.pendingObservations)) {
|
|
371
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
372
|
+
shouldRetry = true;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (!shouldRetry) {
|
|
376
|
+
yield { type: "error", message: String(err) };
|
|
377
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
200
380
|
}
|
|
201
|
-
|
|
381
|
+
if (shouldRetry) {
|
|
382
|
+
action = {
|
|
383
|
+
kind: "call_provider",
|
|
384
|
+
context: runtime.render(),
|
|
385
|
+
tools,
|
|
386
|
+
};
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const assistantMessage = {
|
|
202
390
|
role: "assistant",
|
|
203
391
|
content: finalText,
|
|
204
392
|
toolCalls: finalToolCalls,
|
|
205
393
|
tokenCount: turnTokens || undefined,
|
|
394
|
+
};
|
|
395
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
396
|
+
kind: "provider_result",
|
|
397
|
+
message: messageToKernelMessage(assistantMessage),
|
|
206
398
|
});
|
|
207
399
|
const providerReplay = peekProviderReplay(this.opts.provider, finalText, finalToolCalls);
|
|
208
|
-
await this.opts.sessionLog.append(sessionId, {
|
|
209
|
-
|
|
210
|
-
turn: sm.turn,
|
|
400
|
+
await this.opts.sessionLog.append(sessionId, buildLlmCompletedEvent({
|
|
401
|
+
turn: runtime.turn(),
|
|
211
402
|
content: finalText,
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
});
|
|
403
|
+
tokenCount: turnTokens || undefined,
|
|
404
|
+
toolCalls: finalToolCalls,
|
|
405
|
+
providerReplay,
|
|
406
|
+
}));
|
|
216
407
|
}
|
|
217
|
-
else if (action.kind === "
|
|
218
|
-
const allCalls = action.calls
|
|
219
|
-
await this.opts.sessionLog.append(sessionId, { kind: "tool_requested", turn:
|
|
408
|
+
else if (action.kind === "execute_tool") {
|
|
409
|
+
const allCalls = action.calls;
|
|
410
|
+
await this.opts.sessionLog.append(sessionId, { kind: "tool_requested", turn: runtime.turn(), calls: allCalls });
|
|
220
411
|
const runCtx = {
|
|
221
412
|
agentId: this.opts.agentId,
|
|
222
413
|
skillDir: this.opts.skillDir,
|
|
@@ -226,16 +417,85 @@ export class RuntimeRunner {
|
|
|
226
417
|
onToolSuspend: this.opts.onToolSuspend,
|
|
227
418
|
};
|
|
228
419
|
const toolResults = [];
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
420
|
+
const normalCalls = allCalls.filter(c => c.name !== "update_plan");
|
|
421
|
+
const planCalls = allCalls.filter(c => c.name === "update_plan");
|
|
422
|
+
for (const call of planCalls) {
|
|
423
|
+
const update = parseUpdatePlanArgs(call.arguments);
|
|
424
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
425
|
+
kind: "update_task",
|
|
426
|
+
update: taskUpdateToKernel(update),
|
|
427
|
+
});
|
|
428
|
+
const result = { callId: call.id, output: "success", isError: false };
|
|
429
|
+
toolResults.push(result);
|
|
430
|
+
yield { type: "tool_result", callId: call.id, content: "success", isError: false };
|
|
431
|
+
}
|
|
432
|
+
if (normalCalls.length > 0) {
|
|
433
|
+
for await (const evt of this.opts.executionPlane.executeAll(normalCalls, runCtx)) {
|
|
434
|
+
yield evt;
|
|
435
|
+
if (evt.type === "tool_result") {
|
|
436
|
+
const tre = evt;
|
|
437
|
+
toolResults.push({
|
|
438
|
+
callId: tre.callId,
|
|
439
|
+
output: tre.content,
|
|
440
|
+
isError: tre.isError,
|
|
441
|
+
isFatal: tre.isFatal,
|
|
442
|
+
errorKind: tre.errorKind,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
else if (evt.type === "tool_argument_repaired") {
|
|
446
|
+
const tare = evt;
|
|
447
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
448
|
+
kind: "tool_argument_repaired",
|
|
449
|
+
turn: runtime.turn(),
|
|
450
|
+
tool: tare.name,
|
|
451
|
+
original_arguments: tare.originalArguments,
|
|
452
|
+
repaired_arguments: tare.repairedArguments,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
else if (evt.type === "tool_denied") {
|
|
456
|
+
const tde = evt;
|
|
457
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
458
|
+
kind: "tool_denied",
|
|
459
|
+
turn: runtime.turn(),
|
|
460
|
+
call_id: tde.callId,
|
|
461
|
+
tool_name: tde.toolName,
|
|
462
|
+
reason: tde.reason,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
else if (evt.type === "permission_request") {
|
|
466
|
+
const pre = evt;
|
|
467
|
+
const turn = runtime.turn();
|
|
468
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
469
|
+
kind: "permission_requested",
|
|
470
|
+
turn,
|
|
471
|
+
tool: pre.toolName,
|
|
472
|
+
arguments: JSON.stringify(pre.arguments),
|
|
473
|
+
reason: pre.reason,
|
|
474
|
+
});
|
|
475
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
476
|
+
kind: "permission_resolved",
|
|
477
|
+
turn,
|
|
478
|
+
approved: false,
|
|
479
|
+
responder: "policy_gate",
|
|
480
|
+
});
|
|
481
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
482
|
+
kind: "tool_denied",
|
|
483
|
+
turn,
|
|
484
|
+
call_id: pre.callId,
|
|
485
|
+
tool_name: pre.toolName,
|
|
486
|
+
reason: `permission denied by policy gate: ${pre.reason}`,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
234
489
|
}
|
|
490
|
+
const names = normalCalls.map(c => c.name).join(", ");
|
|
491
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
492
|
+
kind: "update_task",
|
|
493
|
+
update: taskUpdateToKernel({ progress: `Executed tools: ${names}` }),
|
|
494
|
+
});
|
|
235
495
|
}
|
|
236
496
|
await this.opts.sessionLog.append(sessionId, {
|
|
237
497
|
kind: "tool_completed",
|
|
238
|
-
turn:
|
|
498
|
+
turn: runtime.turn(),
|
|
239
499
|
results: toolResults.map(r => ({
|
|
240
500
|
call_id: r.callId,
|
|
241
501
|
output: r.output,
|
|
@@ -243,20 +503,62 @@ export class RuntimeRunner {
|
|
|
243
503
|
token_count: r.tokenCount,
|
|
244
504
|
})),
|
|
245
505
|
});
|
|
246
|
-
action =
|
|
506
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
507
|
+
kind: "tool_results",
|
|
508
|
+
results: toolResults.map(toolResultToKernel),
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
else if (action.kind === "evaluate_milestone") {
|
|
512
|
+
const milestonePolicy = this.opts.milestonePolicy ?? "require_verifier";
|
|
513
|
+
if (milestonePolicy === "auto_pass") {
|
|
514
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
515
|
+
kind: "milestone_result",
|
|
516
|
+
result: milestoneCheckResultToKernel(milestoneCheckPass(action.phaseId)),
|
|
517
|
+
});
|
|
518
|
+
this.nextArchiveStart = await this.appendObservations(sessionId, runtime, this.nextArchiveStart);
|
|
519
|
+
}
|
|
520
|
+
else if (this.opts.onMilestoneEvaluate) {
|
|
521
|
+
const check = await this.opts.onMilestoneEvaluate({
|
|
522
|
+
phaseId: action.phaseId,
|
|
523
|
+
criteria: action.criteria,
|
|
524
|
+
requiredEvidence: action.requiredEvidence,
|
|
525
|
+
});
|
|
526
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
527
|
+
kind: "milestone_result",
|
|
528
|
+
result: milestoneCheckResultToKernel(check),
|
|
529
|
+
});
|
|
530
|
+
this.nextArchiveStart = await this.appendObservations(sessionId, runtime, this.nextArchiveStart);
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
this.nextArchiveStart = await this.appendObservations(sessionId, runtime, this.nextArchiveStart);
|
|
534
|
+
const turnsUsed = Math.max(1, runtime.turn());
|
|
535
|
+
await this.opts.sessionLog.append(sessionId, buildRunTerminalEvent({
|
|
536
|
+
reason: "milestone_pending",
|
|
537
|
+
turnsUsed,
|
|
538
|
+
totalTokens: 0,
|
|
539
|
+
}));
|
|
540
|
+
yield { type: "done", iterations: turnsUsed, totalTokens: 0, status: "milestone_pending" };
|
|
541
|
+
this.activeKernel = null;
|
|
542
|
+
this.currentSessionId = null;
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
247
545
|
}
|
|
248
546
|
else if (action.kind === "done") {
|
|
249
547
|
break;
|
|
250
548
|
}
|
|
251
549
|
}
|
|
252
|
-
const result = action.result;
|
|
550
|
+
const result = action.kind === "done" ? action.result : undefined;
|
|
253
551
|
const status = result?.termination ?? "error";
|
|
254
|
-
const turnsUsed = result ? Math.max(1, result.turnsUsed) : 0;
|
|
255
|
-
const totalTokens = result?.totalTokensUsed
|
|
256
|
-
nextCompressedArchiveStart = await this.appendObservations(sessionId,
|
|
257
|
-
await this.opts.sessionLog.append(sessionId, {
|
|
552
|
+
const turnsUsed = result ? Math.max(1, result.turnsUsed) : runtime.turn() || 0;
|
|
553
|
+
const totalTokens = result?.totalTokensUsed ?? 0;
|
|
554
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
555
|
+
await this.opts.sessionLog.append(sessionId, buildRunTerminalEvent({
|
|
556
|
+
reason: status,
|
|
557
|
+
turnsUsed,
|
|
558
|
+
totalTokens,
|
|
559
|
+
}));
|
|
258
560
|
if (this.opts.dreamStore && this.opts.agentId) {
|
|
259
|
-
const newMsgs =
|
|
561
|
+
const newMsgs = runtime.drainNewMessages().map(m => ({
|
|
260
562
|
role: m.role,
|
|
261
563
|
content: m.content,
|
|
262
564
|
contentParts: m.contentParts,
|
|
@@ -278,22 +580,110 @@ export class RuntimeRunner {
|
|
|
278
580
|
}
|
|
279
581
|
}
|
|
280
582
|
yield { type: "done", iterations: turnsUsed, totalTokens, status };
|
|
583
|
+
this.activeKernel = null;
|
|
584
|
+
this.currentSessionId = null;
|
|
281
585
|
}
|
|
282
|
-
async appendObservations(sessionId,
|
|
283
|
-
const
|
|
586
|
+
async appendObservations(sessionId, runtime, nextArchiveStart) {
|
|
587
|
+
const turn = runtime.turn();
|
|
588
|
+
const preservedRefs = runtime.preservedRefs();
|
|
589
|
+
const observations = this.pendingObservations.splice(0);
|
|
284
590
|
for (const obs of observations) {
|
|
285
|
-
if (obs.kind
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
591
|
+
if (obs.kind === "compressed") {
|
|
592
|
+
const latest = await this.opts.sessionLog.latestSeq(sessionId);
|
|
593
|
+
if (latest < nextArchiveStart)
|
|
594
|
+
continue;
|
|
595
|
+
const end = latest;
|
|
596
|
+
let archiveRef = undefined;
|
|
597
|
+
const archived = obs.archived;
|
|
598
|
+
if (this.opts.compressionStore && archived && archived.length > 0) {
|
|
599
|
+
try {
|
|
600
|
+
const pathRef = await this.opts.compressionStore.write(sessionId, nextArchiveStart, archived);
|
|
601
|
+
if (pathRef)
|
|
602
|
+
archiveRef = pathRef;
|
|
603
|
+
}
|
|
604
|
+
catch {
|
|
605
|
+
// non-fatal
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const compressedSeq = await this.opts.sessionLog.append(sessionId, {
|
|
609
|
+
kind: "compressed",
|
|
610
|
+
turn,
|
|
611
|
+
archived_seq_range: [nextArchiveStart, end],
|
|
612
|
+
action: compressionAction(obs.action),
|
|
613
|
+
summary: obs.summary,
|
|
614
|
+
summary_tokens: obs.summary ? Math.max(1, Math.ceil(obs.summary.length / 4)) : undefined,
|
|
615
|
+
archive_ref: archiveRef,
|
|
616
|
+
preserved_refs: preservedRefs,
|
|
617
|
+
});
|
|
618
|
+
nextArchiveStart = compressedSeq + 1;
|
|
619
|
+
}
|
|
620
|
+
else if (obs.kind === "rollbacked") {
|
|
621
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
622
|
+
kind: "rollbacked",
|
|
623
|
+
turn: obs.turn ?? turn,
|
|
624
|
+
checkpoint_history_len: obs.checkpoint_history_len ?? 0,
|
|
625
|
+
reason: obs.reason,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
else if (obs.kind === "capability_changed") {
|
|
629
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
630
|
+
kind: "capability_changed",
|
|
631
|
+
turn: obs.turn ?? turn,
|
|
632
|
+
added: obs.added ?? [],
|
|
633
|
+
removed: obs.removed ?? [],
|
|
634
|
+
...(obs.change_kind != null && { change_kind: obs.change_kind }),
|
|
635
|
+
...(obs.capability_id != null && { capability_id: obs.capability_id }),
|
|
636
|
+
...(obs.version != null && { version: obs.version }),
|
|
637
|
+
...(obs.mounted_by != null && { mounted_by: obs.mounted_by }),
|
|
638
|
+
...(obs.mount_reason != null && { mount_reason: obs.mount_reason }),
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
else if (obs.kind === "milestone_advanced") {
|
|
642
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
643
|
+
kind: "milestone_advanced",
|
|
644
|
+
turn: obs.turn ?? turn,
|
|
645
|
+
phase_id: obs.phase_id ?? "",
|
|
646
|
+
capabilities_unlocked: obs.capabilities_unlocked ?? [],
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
else if (obs.kind === "milestone_blocked") {
|
|
650
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
651
|
+
kind: "milestone_blocked",
|
|
652
|
+
turn: obs.turn ?? turn,
|
|
653
|
+
phase_id: obs.phase_id ?? "",
|
|
654
|
+
reason: typeof obs.reason === "string" ? obs.reason : "",
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
else if (obs.kind === "milestone_evidence") {
|
|
658
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
659
|
+
kind: "milestone_evidence",
|
|
660
|
+
turn: obs.turn ?? turn,
|
|
661
|
+
phase_id: obs.phase_id ?? "",
|
|
662
|
+
evidence: obs.evidence ?? [],
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
else if (obs.kind === "checkpoint_taken") {
|
|
666
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
667
|
+
kind: "checkpoint_taken",
|
|
668
|
+
turn: obs.turn ?? turn,
|
|
669
|
+
history_len: obs.history_len ?? 0,
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
else if (obs.kind === "agent_spawned") {
|
|
673
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
674
|
+
kind: "agent_spawned",
|
|
675
|
+
turn: obs.turn ?? turn,
|
|
676
|
+
agent_id: obs.agent_id ?? "",
|
|
677
|
+
parent_session_id: obs.parent_session_id ?? "",
|
|
678
|
+
role: obs.role ?? "",
|
|
679
|
+
isolation: obs.isolation ?? "",
|
|
680
|
+
context_inheritance: obs.context_inheritance ?? "",
|
|
681
|
+
permitted_capability_ids: obs.permitted_capability_ids ?? [],
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
else if (obs.kind !== "renewed") {
|
|
685
|
+
console.warn(`[deepstrike] unhandled KernelObservation kind: ${obs.kind}`);
|
|
686
|
+
}
|
|
297
687
|
}
|
|
298
688
|
return nextArchiveStart;
|
|
299
689
|
}
|
|
@@ -301,11 +691,69 @@ export class RuntimeRunner {
|
|
|
301
691
|
function isMidRun(events) {
|
|
302
692
|
return events.length > 0 && !events.some(e => e.event.kind === "run_terminal");
|
|
303
693
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
694
|
+
function compressionAction(action) {
|
|
695
|
+
if (action === "snip_compact" ||
|
|
696
|
+
action === "micro_compact" ||
|
|
697
|
+
action === "context_collapse" ||
|
|
698
|
+
action === "auto_compact") {
|
|
699
|
+
return action;
|
|
700
|
+
}
|
|
701
|
+
return undefined;
|
|
702
|
+
}
|
|
703
|
+
export function replayMessages(events, maxBytes) {
|
|
704
|
+
const messages = [];
|
|
705
|
+
for (const { event: e } of events) {
|
|
706
|
+
if (e.kind === "run_started") {
|
|
707
|
+
const userText = e.criteria.length
|
|
708
|
+
? `${e.goal}\n\nCriteria:\n${e.criteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}`
|
|
709
|
+
: e.goal;
|
|
710
|
+
messages.push({
|
|
711
|
+
role: "user",
|
|
712
|
+
content: userText,
|
|
713
|
+
toolCalls: [],
|
|
714
|
+
tokenCount: Math.max(1, Math.ceil(userText.length / 4)),
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
else if (e.kind === "compressed") {
|
|
718
|
+
if (e.summary) {
|
|
719
|
+
const systemText = `[Compressed context: turn ${e.turn}]\n${e.summary}`;
|
|
720
|
+
messages.push({
|
|
721
|
+
role: "system",
|
|
722
|
+
content: systemText,
|
|
723
|
+
toolCalls: [],
|
|
724
|
+
tokenCount: Math.max(1, Math.ceil(systemText.length / 4)),
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
else if (e.kind === "llm_completed") {
|
|
729
|
+
messages.push({
|
|
730
|
+
role: "assistant",
|
|
731
|
+
content: sanitizeReplayText(e.content, maxBytes),
|
|
732
|
+
toolCalls: e.tool_calls ?? [],
|
|
733
|
+
tokenCount: e.token_count,
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
else if (e.kind === "tool_completed") {
|
|
737
|
+
for (const r of e.results) {
|
|
738
|
+
messages.push({
|
|
739
|
+
role: "tool",
|
|
740
|
+
content: "",
|
|
741
|
+
toolCalls: [],
|
|
742
|
+
contentParts: [{ type: "tool_result", callId: r.call_id, output: sanitizeReplayText(r.output, maxBytes), isError: r.is_error ?? false }],
|
|
743
|
+
tokenCount: r.token_count,
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
else if (e.kind === "rollbacked") {
|
|
748
|
+
const len = e.checkpoint_history_len ?? 0;
|
|
749
|
+
if (messages.length > len) {
|
|
750
|
+
messages.length = len;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return messages;
|
|
755
|
+
}
|
|
756
|
+
export async function replayMessagesAsync(events, maxBytes, loadArchive) {
|
|
309
757
|
const messages = [];
|
|
310
758
|
for (const { event: e } of events) {
|
|
311
759
|
if (e.kind === "run_started") {
|
|
@@ -319,10 +767,41 @@ function replayMessages(events) {
|
|
|
319
767
|
tokenCount: Math.max(1, Math.ceil(userText.length / 4)),
|
|
320
768
|
});
|
|
321
769
|
}
|
|
770
|
+
else if (e.kind === "compressed") {
|
|
771
|
+
let loadedSuccessfully = false;
|
|
772
|
+
if (e.archive_ref && loadArchive) {
|
|
773
|
+
try {
|
|
774
|
+
const archivedMsgs = await loadArchive(e.archive_ref);
|
|
775
|
+
for (const msg of archivedMsgs) {
|
|
776
|
+
messages.push({
|
|
777
|
+
role: msg.role,
|
|
778
|
+
content: sanitizeReplayText(msg.content, maxBytes),
|
|
779
|
+
toolCalls: msg.toolCalls ?? [],
|
|
780
|
+
tokenCount: msg.tokenCount,
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
loadedSuccessfully = true;
|
|
784
|
+
}
|
|
785
|
+
catch (err) {
|
|
786
|
+
// Loader failed (e.g. MissingArchive). We degrade and fallback.
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (!loadedSuccessfully) {
|
|
790
|
+
if (e.summary) {
|
|
791
|
+
const systemText = `[Compressed context: turn ${e.turn}]\n${e.summary}`;
|
|
792
|
+
messages.push({
|
|
793
|
+
role: "system",
|
|
794
|
+
content: systemText,
|
|
795
|
+
toolCalls: [],
|
|
796
|
+
tokenCount: Math.max(1, Math.ceil(systemText.length / 4)),
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
322
801
|
else if (e.kind === "llm_completed") {
|
|
323
802
|
messages.push({
|
|
324
803
|
role: "assistant",
|
|
325
|
-
content: e.content,
|
|
804
|
+
content: sanitizeReplayText(e.content, maxBytes),
|
|
326
805
|
toolCalls: e.tool_calls ?? [],
|
|
327
806
|
tokenCount: e.token_count,
|
|
328
807
|
});
|
|
@@ -333,11 +812,17 @@ function replayMessages(events) {
|
|
|
333
812
|
role: "tool",
|
|
334
813
|
content: "",
|
|
335
814
|
toolCalls: [],
|
|
336
|
-
contentParts: [{ type: "tool_result", callId: r.call_id, output: r.output, isError: r.is_error ?? false }],
|
|
815
|
+
contentParts: [{ type: "tool_result", callId: r.call_id, output: sanitizeReplayText(r.output, maxBytes), isError: r.is_error ?? false }],
|
|
337
816
|
tokenCount: r.token_count,
|
|
338
817
|
});
|
|
339
818
|
}
|
|
340
819
|
}
|
|
820
|
+
else if (e.kind === "rollbacked") {
|
|
821
|
+
const len = e.checkpoint_history_len ?? 0;
|
|
822
|
+
if (messages.length > len) {
|
|
823
|
+
messages.length = len;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
341
826
|
}
|
|
342
827
|
return messages;
|
|
343
828
|
}
|
|
@@ -366,3 +851,21 @@ export async function collectText(stream) {
|
|
|
366
851
|
}
|
|
367
852
|
return text;
|
|
368
853
|
}
|
|
854
|
+
function parseUpdatePlanArgs(argsStr) {
|
|
855
|
+
let parsed = {};
|
|
856
|
+
try {
|
|
857
|
+
parsed = JSON.parse(argsStr);
|
|
858
|
+
}
|
|
859
|
+
catch {
|
|
860
|
+
// Ignore parse error
|
|
861
|
+
}
|
|
862
|
+
return {
|
|
863
|
+
plan: parsed.plan,
|
|
864
|
+
currentStep: parsed.currentStep !== undefined ? Number(parsed.currentStep) : parsed.current_step !== undefined ? Number(parsed.current_step) : undefined,
|
|
865
|
+
progress: parsed.progress,
|
|
866
|
+
scratchpad: parsed.scratchpad,
|
|
867
|
+
blockedOn: parsed.blockedOn !== undefined
|
|
868
|
+
? parsed.blockedOn
|
|
869
|
+
: parsed.blocked_on,
|
|
870
|
+
};
|
|
871
|
+
}
|