@deepstrike/wasm 0.1.16 → 0.2.1
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 +1 -1
- package/dist/governance.d.ts +13 -1
- package/dist/governance.js +34 -9
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/runtime/execution-plane.js +15 -7
- 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 +181 -0
- package/dist/runtime/provider-replay.js +7 -2
- package/dist/runtime/replay-sanitize.d.ts +4 -0
- package/dist/runtime/replay-sanitize.js +26 -0
- package/dist/runtime/runner.d.ts +25 -2
- package/dist/runtime/runner.js +386 -63
- package/dist/runtime/session-log.d.ts +93 -1
- package/dist/runtime/session-repair.d.ts +33 -0
- package/dist/runtime/session-repair.js +73 -0
- package/dist/runtime/sub-agent-orchestrator.d.ts +17 -0
- package/dist/runtime/sub-agent-orchestrator.js +112 -0
- package/dist/runtime/types/agent.d.ts +68 -0
- package/dist/runtime/types/agent.js +78 -0
- package/dist/types.d.ts +18 -0
- package/package.json +2 -2
package/dist/runtime/runner.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
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 { forceCompact, kernelAction, kernelApply, messageToKernelMessage, skillMetadataToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
|
|
6
|
+
import { agentRunSpecToKernel, subAgentResultToKernel, milestoneCheckPass, milestoneCheckResultToKernel } 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
|
+
pendingObservations = [];
|
|
12
|
+
activeKernel = null;
|
|
13
|
+
currentSessionId = null;
|
|
14
|
+
nextArchiveStart = 0;
|
|
6
15
|
constructor(opts) {
|
|
7
16
|
this.opts = opts;
|
|
8
17
|
}
|
|
18
|
+
get hostOptions() { return this.opts; }
|
|
9
19
|
interrupt() { this.interrupted = true; }
|
|
10
20
|
async *run(req) {
|
|
11
|
-
const prior = await this.opts.sessionLog.read(req.sessionId);
|
|
21
|
+
const prior = req.inheritEvents ?? await this.opts.sessionLog.read(req.sessionId);
|
|
12
22
|
const midRun = isMidRun(prior);
|
|
13
23
|
if (!midRun) {
|
|
14
24
|
await this.opts.sessionLog.append(req.sessionId, {
|
|
@@ -32,6 +42,16 @@ export class RuntimeRunner {
|
|
|
32
42
|
const start = startEntry.event;
|
|
33
43
|
yield* this.execute(sessionId, start.goal, start.criteria, extensions, events, true);
|
|
34
44
|
}
|
|
45
|
+
/** Push a large artifact into the kernel artifacts partition (not inlined in history). */
|
|
46
|
+
pushArtifact(message, tokens) {
|
|
47
|
+
if (!this.activeKernel)
|
|
48
|
+
return;
|
|
49
|
+
kernelApply(this.activeKernel, this.pendingObservations, {
|
|
50
|
+
kind: "push_artifact",
|
|
51
|
+
message: messageToKernelMessage(message),
|
|
52
|
+
...(tokens !== undefined ? { tokens } : {}),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
35
55
|
async dream(agentId, nowMs = Date.now()) {
|
|
36
56
|
if (!this.opts.dreamStore)
|
|
37
57
|
throw new Error("dreamStore not configured");
|
|
@@ -94,6 +114,8 @@ export class RuntimeRunner {
|
|
|
94
114
|
}
|
|
95
115
|
async *execute(sessionId, goal, criteria, extensions, priorEvents, resumeMidRun = false) {
|
|
96
116
|
this.interrupted = false;
|
|
117
|
+
this.pendingObservations = [];
|
|
118
|
+
this.currentSessionId = sessionId;
|
|
97
119
|
const kernel = await getKernel();
|
|
98
120
|
this.opts.governance?._attach(kernel);
|
|
99
121
|
const ext = { ...this.opts.extensions, ...(extensions ?? {}) };
|
|
@@ -102,19 +124,31 @@ export class RuntimeRunner {
|
|
|
102
124
|
const providerPolicy = this.opts.provider.runtimePolicy?.() ?? {};
|
|
103
125
|
const effectiveMaxTurns = this.opts.maxTurns ?? providerPolicy.maxTurns ?? 25;
|
|
104
126
|
const effectiveTimeoutMs = this.opts.timeoutMs ?? providerPolicy.timeoutMs;
|
|
105
|
-
const
|
|
127
|
+
const runtime = new kernel.KernelRuntime({
|
|
106
128
|
maxTokens: this.opts.maxTokens,
|
|
107
129
|
maxTurns: effectiveMaxTurns,
|
|
108
130
|
timeoutMs: effectiveTimeoutMs !== undefined ? BigInt(effectiveTimeoutMs) : undefined,
|
|
109
131
|
});
|
|
132
|
+
this.activeKernel = runtime;
|
|
110
133
|
const router = new kernel.SignalRouter(256);
|
|
111
|
-
|
|
134
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
135
|
+
kind: "set_tools",
|
|
136
|
+
tools: this.opts.executionPlane.schemas().map(toolSchemaToKernel),
|
|
137
|
+
});
|
|
112
138
|
if (this.opts.systemPrompt) {
|
|
113
|
-
|
|
139
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
140
|
+
kind: "add_system_message",
|
|
141
|
+
content: this.opts.systemPrompt,
|
|
142
|
+
tokens: Math.max(1, Math.ceil(this.opts.systemPrompt.length / 4)),
|
|
143
|
+
});
|
|
114
144
|
}
|
|
115
145
|
if (this.opts.initialMemory) {
|
|
116
146
|
for (const mem of this.opts.initialMemory) {
|
|
117
|
-
|
|
147
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
148
|
+
kind: "add_memory_message",
|
|
149
|
+
content: mem,
|
|
150
|
+
tokens: Math.max(1, Math.ceil(mem.length / 4)),
|
|
151
|
+
});
|
|
118
152
|
}
|
|
119
153
|
}
|
|
120
154
|
if (this.opts.skillContentMap && this.opts.skillContentMap.size > 0) {
|
|
@@ -123,24 +157,56 @@ export class RuntimeRunner {
|
|
|
123
157
|
description: "",
|
|
124
158
|
estimatedTokens: 0,
|
|
125
159
|
}));
|
|
126
|
-
|
|
160
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
161
|
+
kind: "set_available_skills",
|
|
162
|
+
skills: metas.map(skillMetadataToKernel),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (this.opts.dreamStore && this.opts.agentId) {
|
|
166
|
+
kernelApply(runtime, this.pendingObservations, { kind: "set_memory_enabled", enabled: true });
|
|
167
|
+
}
|
|
168
|
+
if (this.opts.knowledgeSource) {
|
|
169
|
+
kernelApply(runtime, this.pendingObservations, { kind: "set_knowledge_enabled", enabled: true });
|
|
127
170
|
}
|
|
128
|
-
if (this.opts.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
171
|
+
if (this.opts.milestoneContract) {
|
|
172
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
173
|
+
kind: "load_milestone_contract",
|
|
174
|
+
contract: {
|
|
175
|
+
phases: this.opts.milestoneContract.phases.map(p => ({
|
|
176
|
+
id: p.id,
|
|
177
|
+
criteria: p.criteria ?? [],
|
|
178
|
+
unlocks: p.unlocks ?? [],
|
|
179
|
+
verifier: p.verifier ?? null,
|
|
180
|
+
required_evidence: p.requiredEvidence ?? [],
|
|
181
|
+
})),
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const maxBytes = runtime.recoveryContentBytes();
|
|
132
186
|
if (priorEvents && priorEvents.length > 0) {
|
|
133
|
-
|
|
134
|
-
|
|
187
|
+
const repaired = repairEventsForRecovery(priorEvents, maxBytes);
|
|
188
|
+
seedProviderReplayFromEvents(this.opts.provider, repaired);
|
|
189
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
190
|
+
kind: "preload_history",
|
|
191
|
+
messages: replayMessages(repaired, maxBytes).map(messageToKernelMessage),
|
|
192
|
+
});
|
|
135
193
|
}
|
|
136
194
|
const sessionStart = Date.now();
|
|
195
|
+
const startPayload = {
|
|
196
|
+
kind: "start_run",
|
|
197
|
+
task: { goal, criteria },
|
|
198
|
+
};
|
|
199
|
+
if (this.opts.runSpec) {
|
|
200
|
+
startPayload.run_spec = agentRunSpecToKernel(this.opts.runSpec);
|
|
201
|
+
}
|
|
137
202
|
let action = resumeMidRun
|
|
138
|
-
?
|
|
139
|
-
:
|
|
140
|
-
|
|
141
|
-
|
|
203
|
+
? kernelAction(runtime, this.pendingObservations, { kind: "resume" })
|
|
204
|
+
: kernelAction(runtime, this.pendingObservations, startPayload);
|
|
205
|
+
let hasAttemptedReactiveCompact = false;
|
|
206
|
+
while (!runtime.isTerminal()) {
|
|
207
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
142
208
|
if (this.interrupted) {
|
|
143
|
-
|
|
209
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
144
210
|
break;
|
|
145
211
|
}
|
|
146
212
|
if (this.opts.signalSource) {
|
|
@@ -156,9 +222,9 @@ export class RuntimeRunner {
|
|
|
156
222
|
dedupeKey: sig.dedupeKey,
|
|
157
223
|
timestampMs: Date.now(),
|
|
158
224
|
};
|
|
159
|
-
const disposition = router.ingest(kernelSig, action.kind === "
|
|
225
|
+
const disposition = router.ingest(kernelSig, action.kind === "execute_tool");
|
|
160
226
|
if (disposition === "interrupt_now") {
|
|
161
|
-
|
|
227
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
162
228
|
break;
|
|
163
229
|
}
|
|
164
230
|
}
|
|
@@ -166,19 +232,20 @@ export class RuntimeRunner {
|
|
|
166
232
|
let queued = router.next();
|
|
167
233
|
while (queued) {
|
|
168
234
|
if (queued.urgency === "critical") {
|
|
169
|
-
|
|
235
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
170
236
|
break;
|
|
171
237
|
}
|
|
172
238
|
queued = router.next();
|
|
173
239
|
}
|
|
174
|
-
if (
|
|
240
|
+
if (runtime.isTerminal())
|
|
175
241
|
break;
|
|
176
|
-
if (action.kind === "
|
|
242
|
+
if (action.kind === "call_provider") {
|
|
177
243
|
const finalToolCalls = [];
|
|
178
244
|
let finalText = "";
|
|
179
245
|
const context = action.context;
|
|
180
|
-
const tools =
|
|
246
|
+
const tools = action.tools;
|
|
181
247
|
let turnTokens = 0;
|
|
248
|
+
let shouldRetry = false;
|
|
182
249
|
try {
|
|
183
250
|
for await (const evt of this.opts.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState)) {
|
|
184
251
|
if (evt.type === "usage") {
|
|
@@ -195,29 +262,51 @@ export class RuntimeRunner {
|
|
|
195
262
|
}
|
|
196
263
|
}
|
|
197
264
|
catch (err) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
265
|
+
const errMsg = String(err).toLowerCase();
|
|
266
|
+
if ((errMsg.includes("413") || errMsg.includes("too long") || errMsg.includes("context length exceeded") || errMsg.includes("context_length_exceeded")) &&
|
|
267
|
+
!hasAttemptedReactiveCompact) {
|
|
268
|
+
hasAttemptedReactiveCompact = true;
|
|
269
|
+
if (forceCompact(runtime, this.pendingObservations)) {
|
|
270
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
271
|
+
shouldRetry = true;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (!shouldRetry) {
|
|
275
|
+
yield { type: "error", message: String(err) };
|
|
276
|
+
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (shouldRetry) {
|
|
281
|
+
action = {
|
|
282
|
+
kind: "call_provider",
|
|
283
|
+
context: runtime.render(),
|
|
284
|
+
tools,
|
|
285
|
+
};
|
|
286
|
+
continue;
|
|
201
287
|
}
|
|
202
|
-
|
|
288
|
+
const assistantMessage = {
|
|
203
289
|
role: "assistant",
|
|
204
290
|
content: finalText,
|
|
205
291
|
toolCalls: finalToolCalls,
|
|
206
292
|
tokenCount: turnTokens || undefined,
|
|
293
|
+
};
|
|
294
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
295
|
+
kind: "provider_result",
|
|
296
|
+
message: messageToKernelMessage(assistantMessage),
|
|
207
297
|
});
|
|
208
298
|
const providerReplay = peekProviderReplay(this.opts.provider, finalText, finalToolCalls);
|
|
209
|
-
await this.opts.sessionLog.append(sessionId, {
|
|
210
|
-
|
|
211
|
-
turn: sm.turn,
|
|
299
|
+
await this.opts.sessionLog.append(sessionId, buildLlmCompletedEvent({
|
|
300
|
+
turn: runtime.turn(),
|
|
212
301
|
content: finalText,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
});
|
|
302
|
+
tokenCount: turnTokens || undefined,
|
|
303
|
+
toolCalls: finalToolCalls,
|
|
304
|
+
providerReplay,
|
|
305
|
+
}));
|
|
217
306
|
}
|
|
218
|
-
else if (action.kind === "
|
|
219
|
-
const allCalls =
|
|
220
|
-
await this.opts.sessionLog.append(sessionId, { kind: "tool_requested", turn:
|
|
307
|
+
else if (action.kind === "execute_tool") {
|
|
308
|
+
const allCalls = action.calls;
|
|
309
|
+
await this.opts.sessionLog.append(sessionId, { kind: "tool_requested", turn: runtime.turn(), calls: allCalls });
|
|
221
310
|
const runCtx = {
|
|
222
311
|
agentId: this.opts.agentId,
|
|
223
312
|
skillContentMap: this.opts.skillContentMap,
|
|
@@ -231,12 +320,62 @@ export class RuntimeRunner {
|
|
|
231
320
|
yield evt;
|
|
232
321
|
if (evt.type === "tool_result") {
|
|
233
322
|
const tre = evt;
|
|
234
|
-
toolResults.push({
|
|
323
|
+
toolResults.push({
|
|
324
|
+
callId: tre.callId,
|
|
325
|
+
output: tre.content,
|
|
326
|
+
isError: tre.isError,
|
|
327
|
+
isFatal: tre.isFatal,
|
|
328
|
+
errorKind: tre.errorKind,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
else if (evt.type === "tool_argument_repaired") {
|
|
332
|
+
const tare = evt;
|
|
333
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
334
|
+
kind: "tool_argument_repaired",
|
|
335
|
+
turn: runtime.turn(),
|
|
336
|
+
tool: tare.name,
|
|
337
|
+
original_arguments: tare.originalArguments,
|
|
338
|
+
repaired_arguments: tare.repairedArguments,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
else if (evt.type === "tool_denied") {
|
|
342
|
+
const tde = evt;
|
|
343
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
344
|
+
kind: "tool_denied",
|
|
345
|
+
turn: runtime.turn(),
|
|
346
|
+
call_id: tde.callId,
|
|
347
|
+
tool_name: tde.toolName,
|
|
348
|
+
reason: tde.reason,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
else if (evt.type === "permission_request") {
|
|
352
|
+
const pre = evt;
|
|
353
|
+
const turn = runtime.turn();
|
|
354
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
355
|
+
kind: "permission_requested",
|
|
356
|
+
turn,
|
|
357
|
+
tool: pre.toolName,
|
|
358
|
+
arguments: typeof pre.arguments === "string" ? pre.arguments : JSON.stringify(pre.arguments),
|
|
359
|
+
reason: pre.reason,
|
|
360
|
+
});
|
|
361
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
362
|
+
kind: "permission_resolved",
|
|
363
|
+
turn,
|
|
364
|
+
approved: false,
|
|
365
|
+
responder: "policy_gate",
|
|
366
|
+
});
|
|
367
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
368
|
+
kind: "tool_denied",
|
|
369
|
+
turn,
|
|
370
|
+
call_id: pre.callId,
|
|
371
|
+
tool_name: pre.toolName,
|
|
372
|
+
reason: `permission denied by policy gate: ${pre.reason}`,
|
|
373
|
+
});
|
|
235
374
|
}
|
|
236
375
|
}
|
|
237
376
|
await this.opts.sessionLog.append(sessionId, {
|
|
238
377
|
kind: "tool_completed",
|
|
239
|
-
turn:
|
|
378
|
+
turn: runtime.turn(),
|
|
240
379
|
results: toolResults.map(r => ({
|
|
241
380
|
call_id: r.callId,
|
|
242
381
|
output: r.output,
|
|
@@ -244,20 +383,62 @@ export class RuntimeRunner {
|
|
|
244
383
|
token_count: r.tokenCount,
|
|
245
384
|
})),
|
|
246
385
|
});
|
|
247
|
-
action =
|
|
386
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
387
|
+
kind: "tool_results",
|
|
388
|
+
results: toolResults.map(toolResultToKernel),
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
else if (action.kind === "evaluate_milestone") {
|
|
392
|
+
const milestonePolicy = this.opts.milestonePolicy ?? "require_verifier";
|
|
393
|
+
if (milestonePolicy === "auto_pass") {
|
|
394
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
395
|
+
kind: "milestone_result",
|
|
396
|
+
result: milestoneCheckResultToKernel(milestoneCheckPass(action.phaseId)),
|
|
397
|
+
});
|
|
398
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
399
|
+
}
|
|
400
|
+
else if (this.opts.onMilestoneEvaluate) {
|
|
401
|
+
const check = await this.opts.onMilestoneEvaluate({
|
|
402
|
+
phaseId: action.phaseId,
|
|
403
|
+
criteria: action.criteria ?? [],
|
|
404
|
+
requiredEvidence: action.requiredEvidence ?? [],
|
|
405
|
+
});
|
|
406
|
+
action = kernelAction(runtime, this.pendingObservations, {
|
|
407
|
+
kind: "milestone_result",
|
|
408
|
+
result: milestoneCheckResultToKernel(check),
|
|
409
|
+
});
|
|
410
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
414
|
+
const turnsUsed = Math.max(1, runtime.turn());
|
|
415
|
+
await this.opts.sessionLog.append(sessionId, buildRunTerminalEvent({
|
|
416
|
+
reason: "milestone_pending",
|
|
417
|
+
turnsUsed,
|
|
418
|
+
totalTokens: 0,
|
|
419
|
+
}));
|
|
420
|
+
yield { type: "done", iterations: turnsUsed, totalTokens: 0, status: "milestone_pending" };
|
|
421
|
+
this.activeKernel = null;
|
|
422
|
+
this.currentSessionId = null;
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
248
425
|
}
|
|
249
426
|
else if (action.kind === "done") {
|
|
250
427
|
break;
|
|
251
428
|
}
|
|
252
429
|
}
|
|
253
|
-
const result = action.result;
|
|
430
|
+
const result = action.kind === "done" ? action.result : undefined;
|
|
254
431
|
const status = result?.termination ?? "error";
|
|
255
|
-
const turnsUsed = result ? Math.max(1, result.turnsUsed
|
|
256
|
-
const totalTokens = result?.totalTokensUsed
|
|
257
|
-
nextCompressedArchiveStart = await this.appendObservations(sessionId,
|
|
258
|
-
await this.opts.sessionLog.append(sessionId, {
|
|
432
|
+
const turnsUsed = result ? Math.max(1, result.turnsUsed) : runtime.turn() || 0;
|
|
433
|
+
const totalTokens = result?.totalTokensUsed ?? 0;
|
|
434
|
+
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
435
|
+
await this.opts.sessionLog.append(sessionId, buildRunTerminalEvent({
|
|
436
|
+
reason: status,
|
|
437
|
+
turnsUsed,
|
|
438
|
+
totalTokens,
|
|
439
|
+
}));
|
|
259
440
|
if (this.opts.dreamStore && this.opts.agentId) {
|
|
260
|
-
const newMsgs =
|
|
441
|
+
const newMsgs = runtime.drainNewMessages().map(m => ({
|
|
261
442
|
role: m.role,
|
|
262
443
|
content: m.content,
|
|
263
444
|
tokenCount: m.tokenCount,
|
|
@@ -278,22 +459,138 @@ export class RuntimeRunner {
|
|
|
278
459
|
}
|
|
279
460
|
}
|
|
280
461
|
yield { type: "done", iterations: turnsUsed, totalTokens, status };
|
|
462
|
+
this.activeKernel = null;
|
|
463
|
+
this.currentSessionId = null;
|
|
281
464
|
}
|
|
282
|
-
async
|
|
283
|
-
|
|
465
|
+
async spawnSubAgent(spec) {
|
|
466
|
+
if (!this.activeKernel || !this.currentSessionId) {
|
|
467
|
+
throw new Error("spawnSubAgent requires an active parent run");
|
|
468
|
+
}
|
|
469
|
+
const parentSessionId = this.currentSessionId;
|
|
470
|
+
const runtime = this.activeKernel;
|
|
471
|
+
const observations = kernelApply(runtime, this.pendingObservations, {
|
|
472
|
+
kind: "spawn_sub_agent",
|
|
473
|
+
spec: agentRunSpecToKernel(spec),
|
|
474
|
+
parent_session_id: parentSessionId,
|
|
475
|
+
});
|
|
476
|
+
this.nextArchiveStart = await this.appendObservations(parentSessionId, runtime, this.nextArchiveStart);
|
|
477
|
+
const spawned = observations.find(o => o.kind === "agent_spawned" && typeof o.agent_id === "string");
|
|
478
|
+
if (!spawned)
|
|
479
|
+
throw new Error("spawn_sub_agent did not emit agent_spawned");
|
|
480
|
+
const manifest = {
|
|
481
|
+
kind: "agent_spawned",
|
|
482
|
+
turn: spawned.turn,
|
|
483
|
+
agent_id: spawned.agent_id,
|
|
484
|
+
parent_session_id: spawned.parent_session_id ?? parentSessionId,
|
|
485
|
+
role: spawned.role ?? spec.role,
|
|
486
|
+
isolation: spawned.isolation ?? spec.isolation ?? "shared",
|
|
487
|
+
context_inheritance: spawned.context_inheritance ?? "none",
|
|
488
|
+
permitted_capability_ids: spawned.permitted_capability_ids ?? [],
|
|
489
|
+
};
|
|
490
|
+
const orchestrator = this.opts.subAgentOrchestrator ?? defaultSubAgentOrchestrator;
|
|
491
|
+
const result = await orchestrator.run({
|
|
492
|
+
parentOpts: this.opts,
|
|
493
|
+
parentSessionId,
|
|
494
|
+
spec,
|
|
495
|
+
manifest,
|
|
496
|
+
sessionLog: this.opts.sessionLog,
|
|
497
|
+
});
|
|
498
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
499
|
+
kind: "sub_agent_completed",
|
|
500
|
+
result: subAgentResultToKernel(result),
|
|
501
|
+
});
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
async appendObservations(sessionId, runtime, nextArchiveStart) {
|
|
505
|
+
const turn = runtime.turn();
|
|
506
|
+
const preservedRefs = runtime.preservedRefs();
|
|
507
|
+
const observations = this.pendingObservations.splice(0);
|
|
284
508
|
for (const obs of observations) {
|
|
285
|
-
if (obs.kind
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
509
|
+
if (obs.kind === "compressed") {
|
|
510
|
+
const latest = await this.opts.sessionLog.latestSeq(sessionId);
|
|
511
|
+
if (latest < nextArchiveStart)
|
|
512
|
+
continue;
|
|
513
|
+
const end = latest;
|
|
514
|
+
const compressedSeq = await this.opts.sessionLog.append(sessionId, {
|
|
515
|
+
kind: "compressed",
|
|
516
|
+
turn,
|
|
517
|
+
archived_seq_range: [nextArchiveStart, end],
|
|
518
|
+
action: compressionAction(obs.action),
|
|
519
|
+
summary: obs.summary,
|
|
520
|
+
summary_tokens: obs.summary
|
|
521
|
+
? Math.max(1, Math.ceil(obs.summary.length / 4))
|
|
522
|
+
: undefined,
|
|
523
|
+
preserved_refs: preservedRefs,
|
|
524
|
+
});
|
|
525
|
+
nextArchiveStart = compressedSeq + 1;
|
|
526
|
+
}
|
|
527
|
+
else if (obs.kind === "rollbacked") {
|
|
528
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
529
|
+
kind: "rollbacked",
|
|
530
|
+
turn: obs.turn ?? turn,
|
|
531
|
+
checkpoint_history_len: obs.checkpoint_history_len ?? 0,
|
|
532
|
+
reason: obs.reason,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
else if (obs.kind === "capability_changed") {
|
|
536
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
537
|
+
kind: "capability_changed",
|
|
538
|
+
turn: obs.turn ?? turn,
|
|
539
|
+
added: obs.added ?? [],
|
|
540
|
+
removed: obs.removed ?? [],
|
|
541
|
+
...(obs.change_kind != null && { change_kind: obs.change_kind }),
|
|
542
|
+
...(obs.capability_id != null && { capability_id: obs.capability_id }),
|
|
543
|
+
...(obs.version != null && { version: obs.version }),
|
|
544
|
+
...(obs.mounted_by != null && { mounted_by: obs.mounted_by }),
|
|
545
|
+
...(obs.mount_reason != null && { mount_reason: obs.mount_reason }),
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
else if (obs.kind === "milestone_advanced") {
|
|
549
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
550
|
+
kind: "milestone_advanced",
|
|
551
|
+
turn: obs.turn ?? turn,
|
|
552
|
+
phase_id: obs.phase_id ?? "",
|
|
553
|
+
capabilities_unlocked: obs.capabilities_unlocked ?? [],
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
else if (obs.kind === "milestone_blocked") {
|
|
557
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
558
|
+
kind: "milestone_blocked",
|
|
559
|
+
turn: obs.turn ?? turn,
|
|
560
|
+
phase_id: obs.phase_id ?? "",
|
|
561
|
+
reason: typeof obs.reason === "string" ? obs.reason : "",
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
else if (obs.kind === "milestone_evidence") {
|
|
565
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
566
|
+
kind: "milestone_evidence",
|
|
567
|
+
turn: obs.turn ?? turn,
|
|
568
|
+
phase_id: obs.phase_id ?? "",
|
|
569
|
+
evidence: obs.evidence ?? [],
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
else if (obs.kind === "checkpoint_taken") {
|
|
573
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
574
|
+
kind: "checkpoint_taken",
|
|
575
|
+
turn: obs.turn ?? turn,
|
|
576
|
+
history_len: obs.history_len ?? 0,
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
else if (obs.kind === "agent_spawned") {
|
|
580
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
581
|
+
kind: "agent_spawned",
|
|
582
|
+
turn: obs.turn ?? turn,
|
|
583
|
+
agent_id: obs.agent_id ?? "",
|
|
584
|
+
parent_session_id: obs.parent_session_id ?? "",
|
|
585
|
+
role: obs.role ?? "",
|
|
586
|
+
isolation: obs.isolation ?? "",
|
|
587
|
+
context_inheritance: obs.context_inheritance ?? "",
|
|
588
|
+
permitted_capability_ids: obs.permitted_capability_ids ?? [],
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
else if (obs.kind !== "renewed") {
|
|
592
|
+
console.warn(`[deepstrike] unhandled KernelObservation kind: ${obs.kind}`);
|
|
593
|
+
}
|
|
297
594
|
}
|
|
298
595
|
return nextArchiveStart;
|
|
299
596
|
}
|
|
@@ -301,7 +598,16 @@ export class RuntimeRunner {
|
|
|
301
598
|
function isMidRun(events) {
|
|
302
599
|
return events.length > 0 && !events.some(e => e.event.kind === "run_terminal");
|
|
303
600
|
}
|
|
304
|
-
function
|
|
601
|
+
function compressionAction(action) {
|
|
602
|
+
if (action === "snip_compact" ||
|
|
603
|
+
action === "micro_compact" ||
|
|
604
|
+
action === "context_collapse" ||
|
|
605
|
+
action === "auto_compact") {
|
|
606
|
+
return action;
|
|
607
|
+
}
|
|
608
|
+
return undefined;
|
|
609
|
+
}
|
|
610
|
+
function replayMessages(events, maxBytes) {
|
|
305
611
|
const messages = [];
|
|
306
612
|
for (const { event: e } of events) {
|
|
307
613
|
if (e.kind === "run_started") {
|
|
@@ -315,10 +621,21 @@ function replayMessages(events) {
|
|
|
315
621
|
tokenCount: Math.max(1, Math.ceil(userText.length / 4)),
|
|
316
622
|
});
|
|
317
623
|
}
|
|
624
|
+
else if (e.kind === "compressed") {
|
|
625
|
+
if (e.summary) {
|
|
626
|
+
const systemText = `[Compressed context: turn ${e.turn}]\n${e.summary}`;
|
|
627
|
+
messages.push({
|
|
628
|
+
role: "system",
|
|
629
|
+
content: systemText,
|
|
630
|
+
toolCalls: [],
|
|
631
|
+
tokenCount: Math.max(1, Math.ceil(systemText.length / 4)),
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
318
635
|
else if (e.kind === "llm_completed") {
|
|
319
636
|
messages.push({
|
|
320
637
|
role: "assistant",
|
|
321
|
-
content: e.content,
|
|
638
|
+
content: sanitizeReplayText(e.content, maxBytes),
|
|
322
639
|
toolCalls: e.tool_calls ?? [],
|
|
323
640
|
tokenCount: e.token_count,
|
|
324
641
|
});
|
|
@@ -327,12 +644,18 @@ function replayMessages(events) {
|
|
|
327
644
|
for (const r of e.results) {
|
|
328
645
|
messages.push({
|
|
329
646
|
role: "tool",
|
|
330
|
-
content: r.output,
|
|
647
|
+
content: sanitizeReplayText(r.output, maxBytes),
|
|
331
648
|
toolCalls: [],
|
|
332
649
|
tokenCount: r.token_count,
|
|
333
650
|
});
|
|
334
651
|
}
|
|
335
652
|
}
|
|
653
|
+
else if (e.kind === "rollbacked") {
|
|
654
|
+
const len = e.checkpoint_history_len ?? 0;
|
|
655
|
+
if (messages.length > len) {
|
|
656
|
+
messages.length = len;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
336
659
|
}
|
|
337
660
|
return messages;
|
|
338
661
|
}
|