@deepstrike/wasm 0.2.2 → 0.2.6
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 +36 -2
- package/dist/governance.d.ts +32 -0
- package/dist/governance.js +18 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/providers/anthropic.js +20 -3
- package/dist/providers/base.js +11 -1
- package/dist/runtime/execution-plane.d.ts +6 -3
- package/dist/runtime/execution-plane.js +54 -23
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/kernel-event-log.d.ts +26 -0
- package/dist/runtime/kernel-event-log.js +220 -0
- package/dist/runtime/kernel-step.d.ts +23 -1
- package/dist/runtime/kernel-step.js +9 -0
- package/dist/runtime/large-result-spool.d.ts +49 -0
- package/dist/runtime/large-result-spool.js +137 -0
- package/dist/runtime/os-profile.d.ts +30 -0
- package/dist/runtime/os-profile.js +71 -0
- package/dist/runtime/os-snapshot.d.ts +31 -0
- package/dist/runtime/os-snapshot.js +108 -0
- package/dist/runtime/runner.d.ts +57 -5
- package/dist/runtime/runner.js +359 -148
- package/dist/runtime/session-log.d.ts +117 -3
- package/dist/runtime/session-log.js +10 -2
- package/dist/runtime/sub-agent-orchestrator.d.ts +2 -2
- package/dist/runtime/sub-agent-orchestrator.js +14 -23
- package/dist/runtime/types/agent.d.ts +12 -3
- package/dist/runtime/types/agent.js +18 -0
- package/dist/types.d.ts +24 -0
- package/package.json +2 -2
package/dist/runtime/runner.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { resolvePermissionRequest } from "./execution-plane.js";
|
|
2
|
+
import { governancePolicyToKernelEvent } from "../governance.js";
|
|
1
3
|
import { getKernel } from "./kernel.js";
|
|
2
4
|
import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-replay.js";
|
|
3
5
|
import { sanitizeReplayText } from "./replay-sanitize.js";
|
|
4
6
|
import { buildLlmCompletedEvent, buildRunTerminalEvent, repairEventsForRecovery } from "./session-repair.js";
|
|
5
|
-
import { forceCompact, kernelAction, kernelApply, messageToKernelMessage, skillMetadataToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
|
|
6
|
-
import { agentRunSpecToKernel,
|
|
7
|
+
import { forceCompact, kernelAction, kernelApply, kernelMaybeAction, messageToKernelMessage, skillMetadataToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
|
|
8
|
+
import { agentRunSpecToKernel, findSpawnProcessObservation, milestoneCheckPass, milestoneCheckResultToKernel, spawnObservationToManifest, subAgentResultToKernel, } from "./types/agent.js";
|
|
7
9
|
import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
|
|
10
|
+
import { kernelObservationToSessionEvent, withCategory } from "./kernel-event-log.js";
|
|
11
|
+
import { assertNativeProfile } from "./os-profile.js";
|
|
12
|
+
import { LargeResultSpool } from "./large-result-spool.js";
|
|
8
13
|
export class RuntimeRunner {
|
|
9
14
|
opts;
|
|
10
15
|
interrupted = false;
|
|
@@ -12,6 +17,8 @@ export class RuntimeRunner {
|
|
|
12
17
|
activeKernel = null;
|
|
13
18
|
currentSessionId = null;
|
|
14
19
|
nextArchiveStart = 0;
|
|
20
|
+
localPageOutCache = [];
|
|
21
|
+
pendingSpoolOutputs = new Map();
|
|
15
22
|
constructor(opts) {
|
|
16
23
|
this.opts = opts;
|
|
17
24
|
}
|
|
@@ -42,21 +49,142 @@ export class RuntimeRunner {
|
|
|
42
49
|
const start = startEntry.event;
|
|
43
50
|
yield* this.execute(sessionId, start.goal, start.criteria, extensions, events, true);
|
|
44
51
|
}
|
|
45
|
-
/** Push
|
|
46
|
-
|
|
52
|
+
/** Push content into Slot 2 (system_knowledge) via add_knowledge_message. */
|
|
53
|
+
pushKnowledge(message, tokens) {
|
|
47
54
|
if (!this.activeKernel)
|
|
48
55
|
return;
|
|
49
56
|
kernelApply(this.activeKernel, this.pendingObservations, {
|
|
50
|
-
kind: "
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
kind: "add_knowledge_message",
|
|
58
|
+
content: message.content ?? "",
|
|
59
|
+
tokens: tokens ?? Math.max(1, Math.ceil((message.content?.length ?? 0) / 4)),
|
|
53
60
|
});
|
|
54
61
|
}
|
|
62
|
+
/** Phase 4: satisfy kernel page-in requests before meta-tool execution. */
|
|
63
|
+
async applyKernelPageIn(runtime, sessionId) {
|
|
64
|
+
const requests = this.pendingObservations.filter((o) => o.kind === "page_in_requested" && typeof o.tool === "string");
|
|
65
|
+
if (requests.length === 0)
|
|
66
|
+
return;
|
|
67
|
+
const entries = [];
|
|
68
|
+
for (const req of requests) {
|
|
69
|
+
const query = typeof req.query === "string" ? req.query : "";
|
|
70
|
+
const topK = typeof req.top_k === "number" ? req.top_k : 5;
|
|
71
|
+
if (req.tool === "memory") {
|
|
72
|
+
const localHits = this.localPageOutCache.filter(m => typeof m.content === "string" && m.content.toLowerCase().includes(query.toLowerCase())).slice(0, topK);
|
|
73
|
+
for (const hit of localHits) {
|
|
74
|
+
entries.push({
|
|
75
|
+
content: `[local semantic cache] ${hit.role}: ${hit.content}`,
|
|
76
|
+
source: "semantic_cache",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const remainingK = topK - entries.length;
|
|
80
|
+
if (remainingK > 0 && this.opts.dreamStore && this.opts.agentId) {
|
|
81
|
+
const hits = await this.opts.dreamStore.search(this.opts.agentId, query, remainingK);
|
|
82
|
+
for (const hit of hits) {
|
|
83
|
+
entries.push({
|
|
84
|
+
content: `[memory score=${hit.score.toFixed(3)}] ${hit.text}`,
|
|
85
|
+
source: "memory",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (req.tool === "knowledge" && this.opts.knowledgeSource) {
|
|
91
|
+
const snippets = await this.opts.knowledgeSource.retrieve(query, topK);
|
|
92
|
+
for (const snippet of snippets) {
|
|
93
|
+
entries.push({ content: snippet, source: "knowledge" });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (entries.length === 0)
|
|
98
|
+
return;
|
|
99
|
+
kernelApply(runtime, this.pendingObservations, { kind: "page_in", entries });
|
|
100
|
+
await this.opts.sessionLog.append(sessionId, withCategory({
|
|
101
|
+
kind: "page_in",
|
|
102
|
+
turn: runtime.turn(),
|
|
103
|
+
entry_count: entries.length,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
async resolveKernelSuspend(runtime, sessionId) {
|
|
107
|
+
const gated = this.pendingObservations.filter((o) => o.kind === "tool_gated" && typeof o.call_id === "string" && typeof o.tool === "string");
|
|
108
|
+
const approved = [];
|
|
109
|
+
const denied = [];
|
|
110
|
+
const events = [];
|
|
111
|
+
const runCtx = { onPermissionRequest: this.opts.onPermissionRequest };
|
|
112
|
+
for (const g of gated) {
|
|
113
|
+
const request = {
|
|
114
|
+
type: "permission_request",
|
|
115
|
+
callId: g.call_id,
|
|
116
|
+
toolName: g.tool,
|
|
117
|
+
arguments: "{}",
|
|
118
|
+
reason: typeof g.reason === "string" ? g.reason : "",
|
|
119
|
+
};
|
|
120
|
+
events.push(request);
|
|
121
|
+
const decision = await resolvePermissionRequest(request, runCtx);
|
|
122
|
+
events.push({
|
|
123
|
+
type: "permission_resolved",
|
|
124
|
+
callId: g.call_id,
|
|
125
|
+
toolName: g.tool,
|
|
126
|
+
approved: decision.approved,
|
|
127
|
+
responder: decision.responder ?? "host",
|
|
128
|
+
...(decision.reason ? { reason: decision.reason } : {}),
|
|
129
|
+
});
|
|
130
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
131
|
+
kind: "permission_requested",
|
|
132
|
+
turn: runtime.turn(),
|
|
133
|
+
tool: g.tool,
|
|
134
|
+
arguments: "{}",
|
|
135
|
+
reason: request.reason,
|
|
136
|
+
});
|
|
137
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
138
|
+
kind: "permission_resolved",
|
|
139
|
+
turn: runtime.turn(),
|
|
140
|
+
approved: decision.approved,
|
|
141
|
+
responder: decision.responder ?? "host",
|
|
142
|
+
});
|
|
143
|
+
if (decision.approved) {
|
|
144
|
+
approved.push(g.call_id);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
denied.push(g.call_id);
|
|
148
|
+
const denyReason = decision.reason ?? "permission denied";
|
|
149
|
+
events.push({
|
|
150
|
+
type: "tool_denied",
|
|
151
|
+
callId: g.call_id,
|
|
152
|
+
toolName: g.tool,
|
|
153
|
+
reason: denyReason,
|
|
154
|
+
});
|
|
155
|
+
events.push({
|
|
156
|
+
type: "tool_result",
|
|
157
|
+
callId: g.call_id,
|
|
158
|
+
name: g.tool,
|
|
159
|
+
content: `permission denied: ${denyReason}`,
|
|
160
|
+
isError: true,
|
|
161
|
+
errorKind: "governance_denied",
|
|
162
|
+
});
|
|
163
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
164
|
+
kind: "tool_denied",
|
|
165
|
+
turn: runtime.turn(),
|
|
166
|
+
call_id: g.call_id,
|
|
167
|
+
tool_name: g.tool,
|
|
168
|
+
reason: denyReason,
|
|
169
|
+
});
|
|
170
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
171
|
+
kind: "tool_completed",
|
|
172
|
+
turn: runtime.turn(),
|
|
173
|
+
results: [{
|
|
174
|
+
call_id: g.call_id,
|
|
175
|
+
output: `permission denied: ${denyReason}`,
|
|
176
|
+
is_error: true,
|
|
177
|
+
error_kind: "governance_denied",
|
|
178
|
+
}],
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return { approved, denied, events };
|
|
183
|
+
}
|
|
55
184
|
async dream(agentId, nowMs = Date.now()) {
|
|
56
185
|
if (!this.opts.dreamStore)
|
|
57
186
|
throw new Error("dreamStore not configured");
|
|
58
187
|
const kernel = await getKernel();
|
|
59
|
-
this.opts.governance?._attach(kernel);
|
|
60
188
|
const sessions = await this.opts.dreamStore.loadSessions(agentId);
|
|
61
189
|
const existingMemories = await this.opts.dreamStore.loadMemories(agentId);
|
|
62
190
|
if (!sessions.length)
|
|
@@ -77,13 +205,14 @@ export class RuntimeRunner {
|
|
|
77
205
|
if (action1.kind !== "synthesize_insights")
|
|
78
206
|
throw new Error(`unexpected: ${action1.kind}`);
|
|
79
207
|
let synthesisText = "";
|
|
80
|
-
const
|
|
208
|
+
const dreamProvider = this.opts.dreamProvider ?? this.opts.provider;
|
|
209
|
+
const providerState = dreamProvider.createRunState?.();
|
|
81
210
|
const synthMsgs = (action1.messages ?? []);
|
|
82
211
|
const synthContext = {
|
|
83
212
|
systemText: synthMsgs.filter(m => m.role === "system").map(m => m.content).join("\n\n"),
|
|
84
213
|
turns: synthMsgs.filter(m => m.role !== "system"),
|
|
85
214
|
};
|
|
86
|
-
for await (const evt of
|
|
215
|
+
for await (const evt of dreamProvider.stream(synthContext, [], undefined, providerState)) {
|
|
87
216
|
if (evt.type === "text_delta")
|
|
88
217
|
synthesisText += evt.delta;
|
|
89
218
|
}
|
|
@@ -115,9 +244,9 @@ export class RuntimeRunner {
|
|
|
115
244
|
async *execute(sessionId, goal, criteria, extensions, priorEvents, resumeMidRun = false) {
|
|
116
245
|
this.interrupted = false;
|
|
117
246
|
this.pendingObservations = [];
|
|
247
|
+
this.pendingSpoolOutputs.clear();
|
|
118
248
|
this.currentSessionId = sessionId;
|
|
119
249
|
const kernel = await getKernel();
|
|
120
|
-
this.opts.governance?._attach(kernel);
|
|
121
250
|
const ext = { ...this.opts.extensions, ...(extensions ?? {}) };
|
|
122
251
|
const providerState = this.opts.provider.createRunState?.();
|
|
123
252
|
let nextCompressedArchiveStart = nextArchivedSeqStart(priorEvents);
|
|
@@ -130,7 +259,18 @@ export class RuntimeRunner {
|
|
|
130
259
|
timeoutMs: effectiveTimeoutMs !== undefined ? BigInt(effectiveTimeoutMs) : undefined,
|
|
131
260
|
});
|
|
132
261
|
this.activeKernel = runtime;
|
|
133
|
-
|
|
262
|
+
if (this.opts.tokenizer) {
|
|
263
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
264
|
+
kind: "set_tokenizer",
|
|
265
|
+
name: this.opts.tokenizer,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (this.opts.enablePlanTool !== undefined) {
|
|
269
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
270
|
+
kind: "set_plan_tool_enabled",
|
|
271
|
+
enabled: this.opts.enablePlanTool,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
134
274
|
kernelApply(runtime, this.pendingObservations, {
|
|
135
275
|
kind: "set_tools",
|
|
136
276
|
tools: this.opts.executionPlane.schemas().map(toolSchemaToKernel),
|
|
@@ -145,7 +285,7 @@ export class RuntimeRunner {
|
|
|
145
285
|
if (this.opts.initialMemory) {
|
|
146
286
|
for (const mem of this.opts.initialMemory) {
|
|
147
287
|
kernelApply(runtime, this.pendingObservations, {
|
|
148
|
-
kind: "
|
|
288
|
+
kind: "add_knowledge_message",
|
|
149
289
|
content: mem,
|
|
150
290
|
tokens: Math.max(1, Math.ceil(mem.length / 4)),
|
|
151
291
|
});
|
|
@@ -199,11 +339,64 @@ export class RuntimeRunner {
|
|
|
199
339
|
if (this.opts.runSpec) {
|
|
200
340
|
startPayload.run_spec = agentRunSpecToKernel(this.opts.runSpec);
|
|
201
341
|
}
|
|
342
|
+
const osProfile = assertNativeProfile(this.opts.osProfile ?? "native");
|
|
343
|
+
const attentionPolicy = this.opts.attentionPolicy ?? osProfile.attentionPolicy;
|
|
344
|
+
const governancePolicy = this.opts.governancePolicy ?? osProfile.governancePolicy;
|
|
345
|
+
kernelApply(runtime, this.pendingObservations, governancePolicyToKernelEvent(governancePolicy));
|
|
346
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
347
|
+
kind: "set_attention_policy",
|
|
348
|
+
...(attentionPolicy.maxQueueSize !== undefined
|
|
349
|
+
? { max_queue_size: attentionPolicy.maxQueueSize }
|
|
350
|
+
: {}),
|
|
351
|
+
});
|
|
352
|
+
if (this.opts.schedulerBudget) {
|
|
353
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
354
|
+
kind: "set_scheduler_budget",
|
|
355
|
+
...(this.opts.schedulerBudget.maxWallMs !== undefined
|
|
356
|
+
? { max_wall_ms: this.opts.schedulerBudget.maxWallMs }
|
|
357
|
+
: {}),
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
if (this.opts.resourceQuota) {
|
|
361
|
+
const q = this.opts.resourceQuota;
|
|
362
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
363
|
+
kind: "set_resource_quota",
|
|
364
|
+
quota: {
|
|
365
|
+
...(q.maxConcurrentSubagents !== undefined
|
|
366
|
+
? { max_concurrent_subagents: q.maxConcurrentSubagents }
|
|
367
|
+
: {}),
|
|
368
|
+
...(q.maxSpawnDepth !== undefined ? { max_spawn_depth: q.maxSpawnDepth } : {}),
|
|
369
|
+
...(q.memoryWritesPerWindow !== undefined
|
|
370
|
+
? {
|
|
371
|
+
memory_writes_per_window: [
|
|
372
|
+
q.memoryWritesPerWindow.maxWrites,
|
|
373
|
+
q.memoryWritesPerWindow.windowMs,
|
|
374
|
+
],
|
|
375
|
+
}
|
|
376
|
+
: {}),
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
if (this.opts.memoryPolicy) {
|
|
381
|
+
const m = this.opts.memoryPolicy;
|
|
382
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
383
|
+
kind: "set_memory_policy",
|
|
384
|
+
...(m.memoryPath !== undefined ? { memory_path: m.memoryPath } : {}),
|
|
385
|
+
...(m.staleWarningDays !== undefined ? { stale_warning_days: m.staleWarningDays } : {}),
|
|
386
|
+
...(m.retrievalTopK !== undefined ? { retrieval_top_k: m.retrievalTopK } : {}),
|
|
387
|
+
...(m.validationEnabled !== undefined ? { validation_enabled: m.validationEnabled } : {}),
|
|
388
|
+
...(m.maxContentBytes !== undefined ? { max_content_bytes: m.maxContentBytes } : {}),
|
|
389
|
+
...(m.maxNameLength !== undefined ? { max_name_length: m.maxNameLength } : {}),
|
|
390
|
+
});
|
|
391
|
+
}
|
|
202
392
|
let action = resumeMidRun
|
|
203
393
|
? kernelAction(runtime, this.pendingObservations, { kind: "resume" })
|
|
204
394
|
: kernelAction(runtime, this.pendingObservations, startPayload);
|
|
205
395
|
let hasAttemptedReactiveCompact = false;
|
|
206
396
|
while (!runtime.isTerminal()) {
|
|
397
|
+
if (action.kind === "execute_tool") {
|
|
398
|
+
await this.applyKernelPageIn(runtime, sessionId);
|
|
399
|
+
}
|
|
207
400
|
nextCompressedArchiveStart = await this.appendObservations(sessionId, runtime, nextCompressedArchiveStart);
|
|
208
401
|
if (this.interrupted) {
|
|
209
402
|
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
@@ -212,30 +405,27 @@ export class RuntimeRunner {
|
|
|
212
405
|
if (this.opts.signalSource) {
|
|
213
406
|
const sig = await this.opts.signalSource.nextSignal();
|
|
214
407
|
if (sig) {
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
action = kernelAction(runtime, this.pendingObservations, { kind: "timeout" });
|
|
236
|
-
break;
|
|
408
|
+
const id = crypto.randomUUID();
|
|
409
|
+
const source = sig.source ?? "custom";
|
|
410
|
+
const signalType = sig.signalType ?? "event";
|
|
411
|
+
const urgency = sig.urgency ?? "normal";
|
|
412
|
+
const summary = String(sig.payload?.goal ?? "signal");
|
|
413
|
+
const sigAction = kernelMaybeAction(runtime, this.pendingObservations, {
|
|
414
|
+
kind: "signal",
|
|
415
|
+
signal: {
|
|
416
|
+
id,
|
|
417
|
+
source,
|
|
418
|
+
signal_type: signalType,
|
|
419
|
+
urgency,
|
|
420
|
+
summary,
|
|
421
|
+
payload: sig.payload ?? {},
|
|
422
|
+
...(sig.dedupeKey ? { dedupe_key: sig.dedupeKey } : {}),
|
|
423
|
+
timestamp_ms: Date.now(),
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
if (sigAction)
|
|
427
|
+
action = sigAction;
|
|
237
428
|
}
|
|
238
|
-
queued = router.next();
|
|
239
429
|
}
|
|
240
430
|
if (runtime.isTerminal())
|
|
241
431
|
break;
|
|
@@ -245,11 +435,16 @@ export class RuntimeRunner {
|
|
|
245
435
|
const context = action.context;
|
|
246
436
|
const tools = action.tools;
|
|
247
437
|
let turnTokens = 0;
|
|
438
|
+
let turnInputTokens = 0;
|
|
439
|
+
let turnOutputTokens = 0;
|
|
248
440
|
let shouldRetry = false;
|
|
249
441
|
try {
|
|
250
442
|
for await (const evt of this.opts.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState)) {
|
|
251
443
|
if (evt.type === "usage") {
|
|
252
|
-
|
|
444
|
+
const usageEvt = evt;
|
|
445
|
+
turnTokens = usageEvt.totalTokens;
|
|
446
|
+
turnInputTokens = usageEvt.inputTokens ?? 0;
|
|
447
|
+
turnOutputTokens = usageEvt.outputTokens ?? 0;
|
|
253
448
|
continue;
|
|
254
449
|
}
|
|
255
450
|
yield evt;
|
|
@@ -289,17 +484,33 @@ export class RuntimeRunner {
|
|
|
289
484
|
role: "assistant",
|
|
290
485
|
content: finalText,
|
|
291
486
|
toolCalls: finalToolCalls,
|
|
292
|
-
tokenCount: turnTokens || undefined,
|
|
487
|
+
tokenCount: turnOutputTokens || turnTokens || undefined,
|
|
293
488
|
};
|
|
294
|
-
|
|
489
|
+
const providerEvent = {
|
|
295
490
|
kind: "provider_result",
|
|
296
491
|
message: messageToKernelMessage(assistantMessage),
|
|
297
|
-
|
|
492
|
+
...(turnInputTokens > 0 ? { observed_input_tokens: turnInputTokens } : {}),
|
|
493
|
+
...(turnOutputTokens > 0 ? { observed_output_tokens: turnOutputTokens } : {}),
|
|
494
|
+
now_ms: Date.now(),
|
|
495
|
+
};
|
|
496
|
+
let nextAction = kernelMaybeAction(runtime, this.pendingObservations, providerEvent);
|
|
497
|
+
const hasSuspended = this.pendingObservations.some(o => o.kind === "suspended");
|
|
498
|
+
if (!nextAction && hasSuspended) {
|
|
499
|
+
const resolved = await this.resolveKernelSuspend(runtime, sessionId);
|
|
500
|
+
for (const evt of resolved.events)
|
|
501
|
+
yield evt;
|
|
502
|
+
nextAction = kernelAction(runtime, this.pendingObservations, {
|
|
503
|
+
kind: "resume",
|
|
504
|
+
approved_calls: resolved.approved,
|
|
505
|
+
denied_calls: resolved.denied,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
action = nextAction ?? kernelAction(runtime, this.pendingObservations, providerEvent);
|
|
298
509
|
const providerReplay = peekProviderReplay(this.opts.provider, finalText, finalToolCalls);
|
|
299
510
|
await this.opts.sessionLog.append(sessionId, buildLlmCompletedEvent({
|
|
300
511
|
turn: runtime.turn(),
|
|
301
512
|
content: finalText,
|
|
302
|
-
tokenCount: turnTokens || undefined,
|
|
513
|
+
tokenCount: turnOutputTokens || turnTokens || undefined,
|
|
303
514
|
toolCalls: finalToolCalls,
|
|
304
515
|
providerReplay,
|
|
305
516
|
}));
|
|
@@ -312,8 +523,8 @@ export class RuntimeRunner {
|
|
|
312
523
|
skillContentMap: this.opts.skillContentMap,
|
|
313
524
|
dreamStore: this.opts.dreamStore,
|
|
314
525
|
knowledgeSource: this.opts.knowledgeSource,
|
|
315
|
-
governance: this.opts.governance,
|
|
316
526
|
onToolSuspend: this.opts.onToolSuspend,
|
|
527
|
+
onPermissionRequest: this.opts.onPermissionRequest,
|
|
317
528
|
};
|
|
318
529
|
const toolResults = [];
|
|
319
530
|
for await (const evt of this.opts.executionPlane.executeAll(allCalls, runCtx)) {
|
|
@@ -358,18 +569,15 @@ export class RuntimeRunner {
|
|
|
358
569
|
arguments: typeof pre.arguments === "string" ? pre.arguments : JSON.stringify(pre.arguments),
|
|
359
570
|
reason: pre.reason,
|
|
360
571
|
});
|
|
572
|
+
}
|
|
573
|
+
else if (evt.type === "permission_resolved") {
|
|
574
|
+
const resolved = evt;
|
|
575
|
+
const turn = runtime.turn();
|
|
361
576
|
await this.opts.sessionLog.append(sessionId, {
|
|
362
577
|
kind: "permission_resolved",
|
|
363
578
|
turn,
|
|
364
|
-
approved:
|
|
365
|
-
responder:
|
|
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}`,
|
|
579
|
+
approved: resolved.approved,
|
|
580
|
+
responder: resolved.responder,
|
|
373
581
|
});
|
|
374
582
|
}
|
|
375
583
|
}
|
|
@@ -383,6 +591,12 @@ export class RuntimeRunner {
|
|
|
383
591
|
token_count: r.tokenCount,
|
|
384
592
|
})),
|
|
385
593
|
});
|
|
594
|
+
for (const call of allCalls) {
|
|
595
|
+
const result = toolResults.find(r => r.callId === call.id);
|
|
596
|
+
if (result) {
|
|
597
|
+
this.pendingSpoolOutputs.set(call.id, { tool: call.name, output: result.output });
|
|
598
|
+
}
|
|
599
|
+
}
|
|
386
600
|
action = kernelAction(runtime, this.pendingObservations, {
|
|
387
601
|
kind: "tool_results",
|
|
388
602
|
results: toolResults.map(toolResultToKernel),
|
|
@@ -474,19 +688,10 @@ export class RuntimeRunner {
|
|
|
474
688
|
parent_session_id: parentSessionId,
|
|
475
689
|
});
|
|
476
690
|
this.nextArchiveStart = await this.appendObservations(parentSessionId, runtime, this.nextArchiveStart);
|
|
477
|
-
const spawned = observations
|
|
691
|
+
const spawned = findSpawnProcessObservation(observations);
|
|
478
692
|
if (!spawned)
|
|
479
|
-
throw new Error("spawn_sub_agent did not emit
|
|
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
|
-
};
|
|
693
|
+
throw new Error("spawn_sub_agent did not emit agent_process_changed");
|
|
694
|
+
const manifest = spawnObservationToManifest(spawned, spec, parentSessionId);
|
|
490
695
|
const orchestrator = this.opts.subAgentOrchestrator ?? defaultSubAgentOrchestrator;
|
|
491
696
|
const result = await orchestrator.run({
|
|
492
697
|
parentOpts: this.opts,
|
|
@@ -505,95 +710,94 @@ export class RuntimeRunner {
|
|
|
505
710
|
const turn = runtime.turn();
|
|
506
711
|
const preservedRefs = runtime.preservedRefs();
|
|
507
712
|
const observations = this.pendingObservations.splice(0);
|
|
508
|
-
for (
|
|
509
|
-
if (obs.kind === "
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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
|
-
});
|
|
713
|
+
for (let obs of observations) {
|
|
714
|
+
if (obs.kind === "page_in_requested")
|
|
715
|
+
continue;
|
|
716
|
+
let spoolRef;
|
|
717
|
+
if (obs.kind === "large_result_spooled") {
|
|
718
|
+
const pending = this.pendingSpoolOutputs.get(obs.call_id ?? "");
|
|
719
|
+
if (pending) {
|
|
720
|
+
const spool = this.opts.resultSpool ?? new LargeResultSpool();
|
|
721
|
+
try {
|
|
722
|
+
spoolRef = await spool.persistOutput(obs.call_id ?? "", pending.output);
|
|
723
|
+
}
|
|
724
|
+
catch {
|
|
725
|
+
// non-fatal
|
|
726
|
+
}
|
|
727
|
+
if (!obs.tool && pending.tool) {
|
|
728
|
+
obs = { ...obs, tool: pending.tool };
|
|
729
|
+
}
|
|
730
|
+
this.pendingSpoolOutputs.delete(obs.call_id ?? "");
|
|
731
|
+
}
|
|
571
732
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
733
|
+
const latest = obs.kind === "compressed" ? await this.opts.sessionLog.latestSeq(sessionId) : undefined;
|
|
734
|
+
const event = kernelObservationToSessionEvent(obs, turn, {
|
|
735
|
+
nextArchiveStart,
|
|
736
|
+
latestSeq: latest,
|
|
737
|
+
preservedRefs,
|
|
738
|
+
spoolRef,
|
|
739
|
+
compressionAction,
|
|
740
|
+
});
|
|
741
|
+
if (!event)
|
|
742
|
+
continue;
|
|
743
|
+
if (obs.kind === "page_out" && obs.archived) {
|
|
744
|
+
this.localPageOutCache.push(...obs.archived);
|
|
578
745
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
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
|
-
});
|
|
746
|
+
const compressedSeq = await this.opts.sessionLog.append(sessionId, event);
|
|
747
|
+
if (event.kind === "compressed") {
|
|
748
|
+
nextArchiveStart = compressedSeq + 1;
|
|
590
749
|
}
|
|
591
|
-
|
|
592
|
-
|
|
750
|
+
if (obs.kind === "page_out"
|
|
751
|
+
&& obs.tier_hint === "semantic"
|
|
752
|
+
&& Array.isArray(obs.archived)
|
|
753
|
+
&& obs.archived.length > 0) {
|
|
754
|
+
void this.archiveSemanticPageOut(obs.archived, compressionAction(obs.action));
|
|
593
755
|
}
|
|
594
756
|
}
|
|
595
757
|
return nextArchiveStart;
|
|
596
758
|
}
|
|
759
|
+
async archiveSemanticPageOut(archived, action) {
|
|
760
|
+
if (!this.opts.dreamStore || !this.opts.agentId)
|
|
761
|
+
return;
|
|
762
|
+
try {
|
|
763
|
+
const summary = this.opts.dreamSummarizer
|
|
764
|
+
? await this.opts.dreamSummarizer.summarize(archived, { action })
|
|
765
|
+
: await summarizeForLongTermMemory(this.opts.dreamProvider ?? this.opts.provider, archived, this.opts.dreamSystemPrompt);
|
|
766
|
+
const existing = await this.opts.dreamStore.loadMemories(this.opts.agentId);
|
|
767
|
+
await this.opts.dreamStore.commit(this.opts.agentId, {
|
|
768
|
+
toAdd: [{ text: summary, score: 1.0, metadata: { source: "semantic_page_out", action } }],
|
|
769
|
+
toRemoveIndices: [],
|
|
770
|
+
stats: {
|
|
771
|
+
insightsProcessed: 1,
|
|
772
|
+
duplicatesRemoved: 0,
|
|
773
|
+
conflictsResolved: 0,
|
|
774
|
+
entriesAdded: 1,
|
|
775
|
+
},
|
|
776
|
+
}, existing);
|
|
777
|
+
}
|
|
778
|
+
catch {
|
|
779
|
+
// non-fatal
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
async function summarizeForLongTermMemory(provider, archived, systemPrompt) {
|
|
784
|
+
const transcript = archived
|
|
785
|
+
.map(m => `${m.role}: ${m.content}`)
|
|
786
|
+
.join("\n");
|
|
787
|
+
const context = {
|
|
788
|
+
systemText: [
|
|
789
|
+
systemPrompt,
|
|
790
|
+
"Summarize the following conversation for long-term memory. Preserve key facts, decisions, and open questions.",
|
|
791
|
+
].filter(Boolean).join("\n\n"),
|
|
792
|
+
turns: [{ role: "user", content: transcript, toolCalls: [] }],
|
|
793
|
+
};
|
|
794
|
+
let text = "";
|
|
795
|
+
const state = provider.createRunState?.();
|
|
796
|
+
for await (const evt of provider.stream(context, [], undefined, state)) {
|
|
797
|
+
if (evt.type === "text_delta")
|
|
798
|
+
text += evt.delta;
|
|
799
|
+
}
|
|
800
|
+
return text.trim() || transcript.slice(0, 2000);
|
|
597
801
|
}
|
|
598
802
|
function isMidRun(events) {
|
|
599
803
|
return events.length > 0 && !events.some(e => e.event.kind === "run_terminal");
|
|
@@ -608,8 +812,14 @@ function compressionAction(action) {
|
|
|
608
812
|
return undefined;
|
|
609
813
|
}
|
|
610
814
|
function replayMessages(events, maxBytes) {
|
|
611
|
-
|
|
815
|
+
// Build upgraded-summary index: compressed_seq -> upgraded summary
|
|
816
|
+
const upgradedSummaries = new Map();
|
|
612
817
|
for (const { event: e } of events) {
|
|
818
|
+
if (e.kind === "summary_upgraded")
|
|
819
|
+
upgradedSummaries.set(e.compressed_seq, e.summary);
|
|
820
|
+
}
|
|
821
|
+
const messages = [];
|
|
822
|
+
for (const { seq, event: e } of events) {
|
|
613
823
|
if (e.kind === "run_started") {
|
|
614
824
|
const userText = e.criteria.length
|
|
615
825
|
? `${e.goal}\n\nCriteria:\n${e.criteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}`
|
|
@@ -622,8 +832,9 @@ function replayMessages(events, maxBytes) {
|
|
|
622
832
|
});
|
|
623
833
|
}
|
|
624
834
|
else if (e.kind === "compressed") {
|
|
625
|
-
|
|
626
|
-
|
|
835
|
+
const summary = upgradedSummaries.get(seq) ?? e.summary;
|
|
836
|
+
if (summary) {
|
|
837
|
+
const systemText = `[Compressed context: turn ${e.turn}]\n${summary}`;
|
|
627
838
|
messages.push({
|
|
628
839
|
role: "system",
|
|
629
840
|
content: systemText,
|