@deepstrike/sdk 0.2.51 → 0.2.60
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 +28 -28
- package/dist/agent-ir.d.ts +103 -0
- package/dist/agent-ir.js +134 -0
- package/dist/agent.d.ts +67 -0
- package/dist/agent.js +36 -0
- package/dist/collaboration/harness.js +1 -1
- package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
- package/dist/collaboration/modes/creator-verifier.js +4 -6
- package/dist/collaboration/pool.d.ts +8 -20
- package/dist/collaboration/pool.js +27 -97
- package/dist/compat/anthropic/mcp.d.ts +15 -0
- package/dist/compat/anthropic/mcp.js +10 -0
- package/dist/compat/openai/agent.d.ts +34 -0
- package/dist/compat/openai/agent.js +24 -0
- package/dist/governance.d.ts +1 -17
- package/dist/governance.js +1 -34
- package/dist/guardrail.d.ts +6 -0
- package/dist/guardrail.js +1 -0
- package/dist/handoff-target.d.ts +12 -0
- package/dist/handoff-target.js +1 -0
- package/dist/harness/manifest.js +0 -4
- package/dist/index.d.ts +19 -7
- package/dist/index.js +8 -5
- package/dist/kernel.d.ts +2 -20
- package/dist/knowledge/public.d.ts +29 -0
- package/dist/knowledge/public.js +1 -0
- package/dist/mcp-server.d.ts +28 -0
- package/dist/mcp-server.js +1 -0
- package/dist/memory/agent.d.ts +2 -2
- package/dist/memory/agent.js +2 -2
- package/dist/memory/durable.d.ts +16 -0
- package/dist/memory/durable.js +46 -0
- package/dist/memory/in-memory-store.d.ts +9 -7
- package/dist/memory/in-memory-store.js +8 -2
- package/dist/memory/protocols.d.ts +22 -4
- package/dist/memory/public.d.ts +4 -3
- package/dist/memory/public.js +3 -2
- package/dist/providers/anthropic-adapter.d.ts +47 -0
- package/dist/providers/anthropic-adapter.js +444 -0
- package/dist/providers/anthropic-compatible.d.ts +2 -3
- package/dist/providers/anthropic-compatible.js +8 -5
- package/dist/providers/anthropic.d.ts +19 -23
- package/dist/providers/anthropic.js +169 -395
- package/dist/providers/base.js +43 -3
- package/dist/providers/capability-router.d.ts +29 -0
- package/dist/providers/capability-router.js +43 -0
- package/dist/providers/catalog.d.ts +16 -4
- package/dist/providers/catalog.js +112 -21
- package/dist/providers/content-normalization.d.ts +57 -0
- package/dist/providers/content-normalization.js +238 -0
- package/dist/providers/content-policy.d.ts +16 -0
- package/dist/providers/content-policy.js +39 -0
- package/dist/providers/credentials.d.ts +83 -0
- package/dist/providers/credentials.js +190 -0
- package/dist/providers/endpoints.d.ts +137 -0
- package/dist/providers/endpoints.js +128 -0
- package/dist/providers/factories.js +9 -3
- package/dist/providers/gemini-adapter.d.ts +33 -0
- package/dist/providers/gemini-adapter.js +272 -0
- package/dist/providers/gemini.d.ts +16 -3
- package/dist/providers/gemini.js +97 -195
- package/dist/providers/model-catalog.d.ts +37 -0
- package/dist/providers/model-catalog.js +62 -0
- package/dist/providers/model-registry.d.ts +98 -0
- package/dist/providers/model-registry.js +315 -0
- package/dist/providers/ollama-adapter.d.ts +65 -0
- package/dist/providers/ollama-adapter.js +188 -0
- package/dist/providers/ollama.d.ts +9 -4
- package/dist/providers/ollama.js +96 -109
- package/dist/providers/openai-chat-dialects.d.ts +154 -0
- package/dist/providers/openai-chat-dialects.js +179 -0
- package/dist/providers/openai-chat.d.ts +46 -18
- package/dist/providers/openai-chat.js +418 -51
- package/dist/providers/openai-responses-adapter.d.ts +42 -0
- package/dist/providers/openai-responses-adapter.js +341 -0
- package/dist/providers/openai-responses.d.ts +14 -33
- package/dist/providers/openai-responses.js +131 -264
- package/dist/providers/openai.d.ts +29 -76
- package/dist/providers/openai.js +195 -292
- package/dist/providers/protocol-adapter.d.ts +34 -0
- package/dist/providers/protocol-adapter.js +9 -0
- package/dist/providers/protocol-capabilities.d.ts +34 -0
- package/dist/providers/protocol-capabilities.js +44 -0
- package/dist/providers/provider-error.d.ts +31 -0
- package/dist/providers/provider-error.js +149 -0
- package/dist/providers/public.d.ts +26 -3
- package/dist/providers/public.js +13 -1
- package/dist/providers/registry.d.ts +7 -6
- package/dist/providers/registry.js +47 -20
- package/dist/providers/request-plan.d.ts +86 -0
- package/dist/providers/request-plan.js +175 -0
- package/dist/providers/usage-normalizer.d.ts +48 -0
- package/dist/providers/usage-normalizer.js +96 -0
- package/dist/providers/vendor-profiles.d.ts +2 -15
- package/dist/providers/vendor-profiles.js +14 -60
- package/dist/runtime/canonical-kernel-step.d.ts +10 -2
- package/dist/runtime/canonical-kernel-step.js +106 -32
- package/dist/runtime/context-policy.d.ts +10 -12
- package/dist/runtime/context-policy.js +6 -8
- package/dist/runtime/durable-content.d.ts +50 -0
- package/dist/runtime/durable-content.js +159 -0
- package/dist/runtime/execution-plane.d.ts +2 -2
- package/dist/runtime/execution-plane.js +2 -2
- package/dist/runtime/kernel-event-log.js +0 -1
- package/dist/runtime/kernel-step.d.ts +0 -1
- package/dist/runtime/kernel-step.js +4 -2
- package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
- package/dist/runtime/mcp-proxy-plane.js +44 -6
- package/dist/runtime/output-schema.d.ts +1 -2
- package/dist/runtime/provider-replay.d.ts +1 -1
- package/dist/runtime/provider-replay.js +12 -27
- package/dist/runtime/reactive-session.d.ts +1 -1
- package/dist/runtime/reactive-session.js +2 -3
- package/dist/runtime/run-group.d.ts +1 -1
- package/dist/runtime/runner.d.ts +26 -40
- package/dist/runtime/runner.js +145 -63
- package/dist/runtime/session-log.d.ts +8 -1
- package/dist/runtime/session-log.js +42 -2
- package/dist/runtime/session-repair.d.ts +1 -1
- package/dist/runtime/session-repair.js +1 -1
- package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
- package/dist/runtime/sub-agent-orchestrator.js +8 -11
- package/dist/runtime/workflow-control-flow.d.ts +0 -4
- package/dist/runtime/workflow-control-flow.js +0 -16
- package/dist/session.d.ts +11 -0
- package/dist/session.js +1 -0
- package/dist/skill.d.ts +17 -0
- package/dist/skill.js +16 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/tools/errors.d.ts +1 -3
- package/dist/tools/errors.js +1 -3
- package/dist/tools/index.d.ts +3 -0
- package/dist/types/agent.d.ts +21 -9
- package/dist/types/agent.js +30 -4
- package/dist/types.d.ts +128 -13
- package/package.json +3 -3
- package/dist/providers/deepseek.d.ts +0 -46
- package/dist/providers/deepseek.js +0 -97
- package/dist/providers/glm.d.ts +0 -25
- package/dist/providers/glm.js +0 -48
- package/dist/providers/kimi.d.ts +0 -23
- package/dist/providers/kimi.js +0 -30
- package/dist/providers/minimax.d.ts +0 -49
- package/dist/providers/minimax.js +0 -98
- package/dist/providers/profiles.d.ts +0 -1992
- package/dist/providers/profiles.js +0 -796
- package/dist/providers/qwen.d.ts +0 -38
- package/dist/providers/qwen.js +0 -97
package/dist/runtime/runner.js
CHANGED
|
@@ -13,29 +13,37 @@ import { agentRunSpecToKernel, MILESTONE_UNVERIFIED_REASON, milestoneCheckFail,
|
|
|
13
13
|
import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
|
|
14
14
|
import { extractJsonValue, schemaInstruction, schemaRetryInstruction, validateAgainstSchema, } from "./output-schema.js";
|
|
15
15
|
import { resolveReducer } from "./reducers.js";
|
|
16
|
-
import { loopInstruction, classifyInstruction, judgeGoal, dependencyOutputsNote,
|
|
16
|
+
import { loopInstruction, classifyInstruction, judgeGoal, dependencyOutputsNote, extractClassifyBranch, extractJudgeWinner, } from "./workflow-control-flow.js";
|
|
17
17
|
import { governancePolicyToKernelEvent, governanceFilterSchema } from "../governance.js";
|
|
18
|
+
import { createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, recordPromptMeasurement, } from "../providers/request-plan.js";
|
|
18
19
|
import { kernelObservationToSessionEvent } from "./kernel-event-log.js";
|
|
19
20
|
import { assertNativeProfile } from "./os-profile.js";
|
|
20
21
|
import { PayloadStore } from "./payload-store.js";
|
|
21
22
|
import { formatToolError } from "../tools/errors.js";
|
|
22
23
|
import { ManagedTaskScope } from "./reliability.js";
|
|
23
|
-
import {
|
|
24
|
+
import { contextPolicy, normalizeContextPolicy, } from "./context-policy.js";
|
|
24
25
|
import { composeSystemPrompt } from "../harness/manifest.js";
|
|
26
|
+
import { attachToolOutputOverlay, normalizeToolResultContent } from "../providers/content-normalization.js";
|
|
27
|
+
import { decodeDurableContent, decodeDurableToolResult, durableBlocksToToolOutput, toolOutputBlocksToDurable } from "./durable-content.js";
|
|
28
|
+
import { classifyProviderError, providerErrorEventFields } from "../providers/provider-error.js";
|
|
25
29
|
import { NudgeEngine } from "../harness/nudge.js";
|
|
26
30
|
export function schedulerPolicyToKernel(policy) {
|
|
27
31
|
const allowed = new Set([
|
|
28
|
-
"
|
|
32
|
+
"criticalPathWeight", "fanoutWeight", "ageWeight", "tokenCostWeight",
|
|
33
|
+
"deadlineWeight", "processPriorityWeight", "resourcePressureWeight", "budgetPressureWeight",
|
|
29
34
|
]);
|
|
30
35
|
const unknown = Object.keys(policy).filter(key => !allowed.has(key));
|
|
31
36
|
if (unknown.length > 0)
|
|
32
37
|
throw new TypeError(`unknown scheduler policy field(s): ${unknown.join(", ")}`);
|
|
33
38
|
return {
|
|
34
|
-
version: policy.version,
|
|
35
39
|
critical_path_weight: policy.criticalPathWeight,
|
|
36
40
|
fanout_weight: policy.fanoutWeight,
|
|
37
41
|
age_weight: policy.ageWeight,
|
|
38
42
|
token_cost_weight: policy.tokenCostWeight,
|
|
43
|
+
...(policy.deadlineWeight !== undefined ? { deadline_weight: policy.deadlineWeight } : {}),
|
|
44
|
+
...(policy.processPriorityWeight !== undefined ? { process_priority_weight: policy.processPriorityWeight } : {}),
|
|
45
|
+
...(policy.resourcePressureWeight !== undefined ? { resource_pressure_weight: policy.resourcePressureWeight } : {}),
|
|
46
|
+
...(policy.budgetPressureWeight !== undefined ? { budget_pressure_weight: policy.budgetPressureWeight } : {}),
|
|
39
47
|
};
|
|
40
48
|
}
|
|
41
49
|
function kernelReliabilityToKernel(policy) {
|
|
@@ -214,19 +222,19 @@ export class RuntimeRunner {
|
|
|
214
222
|
return this.fallbackPayloadStore;
|
|
215
223
|
}
|
|
216
224
|
async persistMemoryToStore(memory, agentId) {
|
|
217
|
-
if (!this.opts.
|
|
218
|
-
throw new Error("memory persistence requires
|
|
219
|
-
await this.opts.
|
|
225
|
+
if (!this.opts.memoryStore)
|
|
226
|
+
throw new Error("memory persistence requires memoryStore");
|
|
227
|
+
await this.opts.memoryStore.put(agentId, memory);
|
|
220
228
|
}
|
|
221
229
|
async retrieveMemoryFromStore(query, requestedK, agentId) {
|
|
222
|
-
if (!this.opts.
|
|
223
|
-
throw new Error("memory queries require
|
|
224
|
-
return (await this.opts.
|
|
230
|
+
if (!this.opts.memoryStore)
|
|
231
|
+
throw new Error("memory queries require memoryStore");
|
|
232
|
+
return (await this.opts.memoryStore.search(agentId, { ...query, top_k: requestedK }))
|
|
225
233
|
.slice(0, requestedK);
|
|
226
234
|
}
|
|
227
235
|
/**
|
|
228
236
|
* Route a host-originated renewal prefetch into canonical knowledge commands. This is not an
|
|
229
|
-
* agent syscall: the host selects records from its store, then the kernel owns the
|
|
237
|
+
* agent syscall: the host selects records from its store, then the kernel owns the write
|
|
230
238
|
* of live semantic context. `seenRecordIds` is the prefetch's dedupe horizon.
|
|
231
239
|
*/
|
|
232
240
|
async prefetchMemoryIntoKnowledge(runtime, query, agentId, sessionId, seenRecordIds, leftovers) {
|
|
@@ -261,7 +269,7 @@ export class RuntimeRunner {
|
|
|
261
269
|
async writeMemory(memory, opts = {}) {
|
|
262
270
|
const sessionId = opts.sessionId ?? this.currentSessionId;
|
|
263
271
|
const agentId = opts.agentId ?? this.opts.agentId;
|
|
264
|
-
if (!this.opts.
|
|
272
|
+
if (!this.opts.memoryStore || !agentId)
|
|
265
273
|
return;
|
|
266
274
|
const policy = this.opts.memoryPolicy;
|
|
267
275
|
if (policy?.validationEnabled !== false) {
|
|
@@ -300,7 +308,7 @@ export class RuntimeRunner {
|
|
|
300
308
|
async queryMemory(query, opts = {}) {
|
|
301
309
|
const sessionId = opts.sessionId ?? this.currentSessionId;
|
|
302
310
|
const agentId = opts.agentId ?? this.opts.agentId;
|
|
303
|
-
if (!this.opts.
|
|
311
|
+
if (!this.opts.memoryStore || !agentId)
|
|
304
312
|
return [];
|
|
305
313
|
const hits = await this.retrieveMemoryFromStore(query, query.top_k, agentId);
|
|
306
314
|
await this.applyHostMemoryRecallLifecycle(hits, agentId);
|
|
@@ -315,7 +323,7 @@ export class RuntimeRunner {
|
|
|
315
323
|
recall_count: hit.record.recall_count + 1,
|
|
316
324
|
last_recalled_at: Date.now(),
|
|
317
325
|
}));
|
|
318
|
-
await this.opts.
|
|
326
|
+
await this.opts.memoryStore?.recordRecall?.(agentId, recalls);
|
|
319
327
|
const threshold = this.opts.memoryPolicy?.promotionRecallThreshold;
|
|
320
328
|
if (threshold === undefined)
|
|
321
329
|
return;
|
|
@@ -423,13 +431,12 @@ export class RuntimeRunner {
|
|
|
423
431
|
const { kind: _govKind, ...governance } = governancePolicyToKernelEvent(governancePolicy);
|
|
424
432
|
const config = { governance };
|
|
425
433
|
if (this.opts.contextPolicy) {
|
|
426
|
-
config.context_policy =
|
|
434
|
+
config.context_policy = normalizeContextPolicy(contextPolicy(this.opts.contextPolicy));
|
|
427
435
|
}
|
|
428
436
|
if (this.opts.kernelReliability) {
|
|
429
437
|
config.reliability = kernelReliabilityToKernel(this.opts.kernelReliability);
|
|
430
438
|
}
|
|
431
439
|
config.signal_policy = {
|
|
432
|
-
version: 1,
|
|
433
440
|
queue_max: signalPolicy.queueMax,
|
|
434
441
|
...(signalPolicy.ttlMs !== undefined ? { ttl_ms: signalPolicy.ttlMs } : {}),
|
|
435
442
|
...(signalPolicy.deadlineEscalation !== undefined
|
|
@@ -484,11 +491,6 @@ export class RuntimeRunner {
|
|
|
484
491
|
if (this.opts.criteriaGate !== undefined) {
|
|
485
492
|
config.criteria_gate = this.opts.criteriaGate;
|
|
486
493
|
}
|
|
487
|
-
// P1: fail-closed dispatch selector (absent ⇒ kernel default "exposed"). "registered" is the
|
|
488
|
-
// escape hatch back to permissive dispatch; the kernel rejects any other value.
|
|
489
|
-
if (this.opts.toolDispatchGate !== undefined) {
|
|
490
|
-
config.tool_dispatch_gate = this.opts.toolDispatchGate;
|
|
491
|
-
}
|
|
492
494
|
// K2: knowledge budget ratio (absent ⇒ kernel default 0.25; 0 disables).
|
|
493
495
|
if (this.opts.knowledgeBudgetRatio !== undefined) {
|
|
494
496
|
config.knowledge_budget_ratio = this.opts.knowledgeBudgetRatio;
|
|
@@ -517,8 +519,8 @@ export class RuntimeRunner {
|
|
|
517
519
|
async mirrorMemoryLifecycle(obs) {
|
|
518
520
|
if (obs.kind === "memory_recalled" && obs.recalls?.length) {
|
|
519
521
|
const agentId = this.opts.agentId;
|
|
520
|
-
if (agentId && this.opts.
|
|
521
|
-
await this.opts.
|
|
522
|
+
if (agentId && this.opts.memoryStore?.recordRecall) {
|
|
523
|
+
await this.opts.memoryStore.recordRecall(agentId, obs.recalls);
|
|
522
524
|
}
|
|
523
525
|
}
|
|
524
526
|
if (obs.kind === "promotion_suggested" && obs.record_id) {
|
|
@@ -642,20 +644,15 @@ export class RuntimeRunner {
|
|
|
642
644
|
const winnerId = winner === "right" ? node.judge_match.right : node.judge_match.left;
|
|
643
645
|
return withSignal(result, { tournamentWinner: winnerId });
|
|
644
646
|
}
|
|
645
|
-
//
|
|
647
|
+
// loop-control loop iteration: run the increment under the armed pacing trap (workflowNodeToSpec set
|
|
646
648
|
// `loopRound`, and the iteration resumes the loop's stable session — transcript-as-carry).
|
|
647
|
-
//
|
|
648
|
-
//
|
|
649
|
-
// when no pace decision arrives (stub orchestrators, harness children), where no signal still
|
|
650
|
-
// means "run to max_iters" (v1).
|
|
649
|
+
// The kernel-adjudicated `pace` verb is the only continuation signal. Ending without a pace
|
|
650
|
+
// decision completes the loop.
|
|
651
651
|
if (node.loop_max_iters != null) {
|
|
652
652
|
const iteration = Number(/-i(\d+)$/.exec(node.agent_id)?.[1] ?? "0");
|
|
653
653
|
const result = await orchestrator.run(mkCtx(`${baseSpec.goal}\n\n${loopInstruction(node.loop_max_iters, iteration)}`));
|
|
654
654
|
const pace = result.result.paceDecision;
|
|
655
|
-
|
|
656
|
-
return withSignal(result, { loopContinue: pace.action !== "stop" });
|
|
657
|
-
const cont = extractLoopContinue(textOf(result));
|
|
658
|
-
return cont === undefined ? result : withSignal(result, { loopContinue: cont });
|
|
655
|
+
return withSignal(result, { loopContinue: pace?.action === "continue" });
|
|
659
656
|
}
|
|
660
657
|
// A#2 classify: run the classifier, then extract the chosen branch label; the kernel runs that
|
|
661
658
|
// branch and prunes the rest. No recognizable choice ⇒ leave unset (kernel prunes all branches).
|
|
@@ -1298,6 +1295,7 @@ export class RuntimeRunner {
|
|
|
1298
1295
|
output: `permission denied: ${denyReason}`,
|
|
1299
1296
|
is_error: true,
|
|
1300
1297
|
error_kind: "governance_denied",
|
|
1298
|
+
content: { blocks: [{ type: "text", text: `permission denied: ${denyReason}` }] },
|
|
1301
1299
|
}],
|
|
1302
1300
|
});
|
|
1303
1301
|
}
|
|
@@ -1317,7 +1315,16 @@ export class RuntimeRunner {
|
|
|
1317
1315
|
}
|
|
1318
1316
|
const ext = { ...this.opts.extensions, ...(extensions ?? {}) };
|
|
1319
1317
|
const providerState = this.opts.provider.createRunState?.();
|
|
1318
|
+
// Structured blocks are intentionally operation-local. The durable kernel wire carries the
|
|
1319
|
+
// text projection; a wake (same or new Runner) therefore has identical semantics.
|
|
1320
|
+
const toolOutputOverlay = new Map();
|
|
1320
1321
|
let nextCompressedArchiveStart = nextArchivedSeqStart(priorEvents);
|
|
1322
|
+
const recordedMeasurements = new Map();
|
|
1323
|
+
for (const entry of priorEvents ?? []) {
|
|
1324
|
+
if (entry.event.kind === "prompt_measured") {
|
|
1325
|
+
recordedMeasurements.set(entry.event.measurement.requestFingerprint, entry.event.measurement);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1321
1328
|
const providerPolicy = this.opts.provider.runtimePolicy?.() ?? {};
|
|
1322
1329
|
const effectiveMaxTurns = this.opts.maxTurns ?? providerPolicy.maxTurns ?? 25;
|
|
1323
1330
|
const effectiveTimeoutMs = this.opts.timeoutMs ?? providerPolicy.timeoutMs;
|
|
@@ -1393,7 +1400,7 @@ export class RuntimeRunner {
|
|
|
1393
1400
|
tool_ids: this.opts.stableCoreToolIds,
|
|
1394
1401
|
});
|
|
1395
1402
|
}
|
|
1396
|
-
if (this.opts.
|
|
1403
|
+
if (this.opts.memoryStore && this.opts.agentId) {
|
|
1397
1404
|
await this.commitKernelApply(runtime, this.pendingObservations, { kind: "set_memory_enabled", enabled: true });
|
|
1398
1405
|
}
|
|
1399
1406
|
// Install optional memory policy. Maps the ergonomic camelCase option onto the kernel's
|
|
@@ -1439,18 +1446,15 @@ export class RuntimeRunner {
|
|
|
1439
1446
|
const startTask = { goal, criteria };
|
|
1440
1447
|
let startRunSpec;
|
|
1441
1448
|
// P0-A: lower an explicit `runSpec`, the `allowedToolIds` ceiling, and/or the `baselineToolIds`
|
|
1442
|
-
// pre-activation surface to the kernel run spec. Each
|
|
1443
|
-
//
|
|
1444
|
-
// run_spec wire — no new ABI). Unset on all ⇒ no run_spec ⇒ no gating (铁律: no config = old
|
|
1445
|
-
// behavior).
|
|
1449
|
+
// pre-activation surface to the kernel run spec. Each run has a run spec; an omitted baseline
|
|
1450
|
+
// is the canonical minimal surface.
|
|
1446
1451
|
const allowedToolIds = this.opts.allowedToolIds;
|
|
1447
1452
|
const hasProfile = allowedToolIds !== undefined && allowedToolIds.length > 0;
|
|
1448
1453
|
// NOT the `length > 0` idiom above: `baselineToolIds: []` is the legitimate minimal surface
|
|
1449
1454
|
// (meta + stable-core only), so mere presence triggers the lowering.
|
|
1450
|
-
const baselineToolIds = this.opts.baselineToolIds;
|
|
1451
|
-
const hasBaseline = baselineToolIds !== undefined;
|
|
1455
|
+
const baselineToolIds = this.opts.baselineToolIds ?? this.opts.runSpec?.exposureBaseline ?? [];
|
|
1452
1456
|
const hasMilestoneContract = this.opts.milestoneContract !== undefined;
|
|
1453
|
-
|
|
1457
|
+
{
|
|
1454
1458
|
const baseSpec = this.opts.runSpec ?? {
|
|
1455
1459
|
identity: { agentId: this.opts.agentId ?? "root", sessionId, isSubAgent: false },
|
|
1456
1460
|
role: "custom",
|
|
@@ -1459,8 +1463,7 @@ export class RuntimeRunner {
|
|
|
1459
1463
|
let spec = hasProfile
|
|
1460
1464
|
? { ...baseSpec, capabilityFilter: { ...baseSpec.capabilityFilter, allowedIds: allowedToolIds } }
|
|
1461
1465
|
: baseSpec;
|
|
1462
|
-
|
|
1463
|
-
spec = { ...spec, exposureBaseline: baselineToolIds };
|
|
1466
|
+
spec = { ...spec, exposureBaseline: baselineToolIds };
|
|
1464
1467
|
if (hasMilestoneContract && !spec.verificationContractId) {
|
|
1465
1468
|
spec = { ...spec, verificationContractId: "node-default" };
|
|
1466
1469
|
}
|
|
@@ -1507,7 +1510,7 @@ export class RuntimeRunner {
|
|
|
1507
1510
|
// I4/T5: pre-fetch memory before root start so the model sees it on turn 1 instead of
|
|
1508
1511
|
// discovering it via the `memory` tool later. Accepted hits enter `initial_context.messages`
|
|
1509
1512
|
// and are therefore frozen into the canonical start record. Skipped on restore (the checkpoint
|
|
1510
|
-
// or journal already owns them) and when
|
|
1513
|
+
// or journal already owns them) and when memoryStore/agentId is absent.
|
|
1511
1514
|
// P0-C: the skill loaded and in effect going into the current turn (updated when the model's
|
|
1512
1515
|
// `skill` tool call resolves). Drives the per-turn `activeSkill` metric → dwell measurement.
|
|
1513
1516
|
let activeSkill;
|
|
@@ -1552,7 +1555,7 @@ export class RuntimeRunner {
|
|
|
1552
1555
|
// model sees them — the model can't plan a call it doesn't know about, so the rollback
|
|
1553
1556
|
// overhead disappears. The list of denied names is appended to systemKnowledge so the
|
|
1554
1557
|
// model knows not to plan around them.
|
|
1555
|
-
let context = action.context;
|
|
1558
|
+
let context = attachToolOutputOverlay(action.context, toolOutputOverlay);
|
|
1556
1559
|
let tools = action.tools;
|
|
1557
1560
|
if (this.opts.governancePolicy && this.opts.governancePolicy.surfaceDeniedInSystem !== false) {
|
|
1558
1561
|
const { allowed, denied } = governanceFilterSchema(tools, this.opts.governancePolicy);
|
|
@@ -1574,6 +1577,53 @@ export class RuntimeRunner {
|
|
|
1574
1577
|
let turnCacheCreationTokens = 0;
|
|
1575
1578
|
let turnCacheReadBySlot;
|
|
1576
1579
|
let turnStopReason;
|
|
1580
|
+
const providerPlan = createProviderRequestPlanForProvider(this.opts.provider, context, tools, ext);
|
|
1581
|
+
const recorded = measurementForPlan(providerPlan, recordedMeasurements.get(providerPlan.fingerprint));
|
|
1582
|
+
let promptMeasurement = recorded;
|
|
1583
|
+
if (!promptMeasurement && !context.budgetOverflow) {
|
|
1584
|
+
try {
|
|
1585
|
+
const count = this.opts.provider.countTokens
|
|
1586
|
+
? await withTimeout(this.opts.provider.countTokens(context, tools, Object.keys(ext).length ? ext : undefined), 5_000)
|
|
1587
|
+
: undefined;
|
|
1588
|
+
promptMeasurement = recordPromptMeasurement(providerPlan, count ?? {
|
|
1589
|
+
inputTokens: estimateProviderPromptTokens(context, tools),
|
|
1590
|
+
source: { kind: "heuristic" },
|
|
1591
|
+
confidence: "low_confidence",
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
catch {
|
|
1595
|
+
promptMeasurement = recordPromptMeasurement(providerPlan, {
|
|
1596
|
+
inputTokens: estimateProviderPromptTokens(context, tools),
|
|
1597
|
+
source: { kind: "heuristic" },
|
|
1598
|
+
confidence: "low_confidence",
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
recordedMeasurements.set(providerPlan.fingerprint, promptMeasurement);
|
|
1602
|
+
await this.opts.sessionLog.append(sessionId, {
|
|
1603
|
+
kind: "prompt_measured",
|
|
1604
|
+
turn: runtime.turn(),
|
|
1605
|
+
measurement: promptMeasurement,
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
const reservedPromptTokens = (this.opts.promptBudget?.promptOverheadTokens ?? 0)
|
|
1609
|
+
+ (this.opts.promptBudget?.outputReserveTokens ?? 0)
|
|
1610
|
+
+ (this.opts.promptBudget?.safetyMarginTokens ?? 0);
|
|
1611
|
+
// Heuristic and non-native counts are advisory: their purpose is to choose a better
|
|
1612
|
+
// compaction path, not to turn a coarse byte estimate into a false context-overflow
|
|
1613
|
+
// terminal. A trustworthy native/local-exact measurement can block the provider call.
|
|
1614
|
+
const measuredOverflow = promptMeasurement
|
|
1615
|
+
&& promptMeasurement.source.kind !== "heuristic"
|
|
1616
|
+
&& promptMeasurement.inputTokens + reservedPromptTokens > this.opts.maxTokens;
|
|
1617
|
+
if (context.budgetOverflow || measuredOverflow) {
|
|
1618
|
+
action = await this.commitKernelAction(runtime, this.pendingObservations, {
|
|
1619
|
+
kind: "provider_error",
|
|
1620
|
+
effect_id: providerEffectId,
|
|
1621
|
+
message: "provider-visible prompt exceeds the configured context budget",
|
|
1622
|
+
error_kind: "context_overflow",
|
|
1623
|
+
retryable: false,
|
|
1624
|
+
});
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1577
1627
|
const abortSignal = this.abortController?.signal;
|
|
1578
1628
|
try {
|
|
1579
1629
|
for await (const evt of this.opts.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState, abortSignal)) {
|
|
@@ -1615,6 +1665,9 @@ export class RuntimeRunner {
|
|
|
1615
1665
|
this.cancellationReason ??= "user";
|
|
1616
1666
|
}
|
|
1617
1667
|
else {
|
|
1668
|
+
const provider = this.opts.provider.descriptor?.().provider ?? "unknown";
|
|
1669
|
+
const providerError = classifyProviderError(provider, err);
|
|
1670
|
+
const message = providerError.message;
|
|
1618
1671
|
// Reactive recovery is now a kernel decision. Forward the raw provider error and
|
|
1619
1672
|
// dispatch whatever the kernel returns: `call_provider` to retry with a freshly
|
|
1620
1673
|
// compacted context, or `done` to terminate with an honest `ContextOverflow`. The
|
|
@@ -1625,14 +1678,15 @@ export class RuntimeRunner {
|
|
|
1625
1678
|
action = await this.commitKernelAction(runtime, this.pendingObservations, {
|
|
1626
1679
|
kind: "provider_error",
|
|
1627
1680
|
effect_id: providerEffectId,
|
|
1628
|
-
message
|
|
1681
|
+
message,
|
|
1682
|
+
...providerErrorEventFields(providerError),
|
|
1629
1683
|
});
|
|
1630
1684
|
// Withholding (query.ts parity): surface the raw provider error only when the kernel
|
|
1631
1685
|
// could NOT recover (it returned a terminal). On a recovered retry (`call_provider`)
|
|
1632
1686
|
// the error stays hidden, so embedders that terminate on `error` events don't see a
|
|
1633
1687
|
// phantom failure mid-recovery.
|
|
1634
1688
|
if (action.kind === "done") {
|
|
1635
|
-
yield { type: "error", message
|
|
1689
|
+
yield { type: "error", message };
|
|
1636
1690
|
}
|
|
1637
1691
|
continue;
|
|
1638
1692
|
}
|
|
@@ -1918,7 +1972,7 @@ export class RuntimeRunner {
|
|
|
1918
1972
|
agentId: this.opts.agentId,
|
|
1919
1973
|
memoryScope: this.opts.memoryScope,
|
|
1920
1974
|
skillDir: this.opts.skillDir,
|
|
1921
|
-
|
|
1975
|
+
memoryStore: this.opts.memoryStore,
|
|
1922
1976
|
knowledgeSource: this.opts.knowledgeSource,
|
|
1923
1977
|
onToolSuspend: this.opts.onToolSuspend,
|
|
1924
1978
|
onPermissionRequest: this.opts.onPermissionRequest,
|
|
@@ -1944,8 +1998,7 @@ export class RuntimeRunner {
|
|
|
1944
1998
|
}
|
|
1945
1999
|
// O5 (PreToolUse-hook analog): give the host a STATEFUL veto over each kernel-approved
|
|
1946
2000
|
// call. A blocked call never executes; its reason reaches the model as a committed
|
|
1947
|
-
// governance-denied tool result. Decision failures are closed
|
|
1948
|
-
// unless the host explicitly marks this hook advisory with `onToolCallFailure: "open"`.
|
|
2001
|
+
// governance-denied tool result. Decision failures are closed.
|
|
1949
2002
|
let executableCalls = normalCalls;
|
|
1950
2003
|
if (this.opts.onToolCall) {
|
|
1951
2004
|
const allowed = [];
|
|
@@ -1955,9 +2008,7 @@ export class RuntimeRunner {
|
|
|
1955
2008
|
decision = await this.opts.onToolCall({ callId: call.id, name: call.name, arguments: call.arguments });
|
|
1956
2009
|
}
|
|
1957
2010
|
catch (cause) {
|
|
1958
|
-
decision =
|
|
1959
|
-
? undefined
|
|
1960
|
-
: { block: true, reason: `onToolCall hook failed: ${formatToolError(cause)}` };
|
|
2011
|
+
decision = { block: true, reason: `onToolCall hook failed: ${formatToolError(cause)}` };
|
|
1961
2012
|
}
|
|
1962
2013
|
if (decision?.block) {
|
|
1963
2014
|
const reason = decision.reason ?? "blocked by host onToolCall hook";
|
|
@@ -1979,12 +2030,17 @@ export class RuntimeRunner {
|
|
|
1979
2030
|
yield evt;
|
|
1980
2031
|
if (evt.type === "tool_result") {
|
|
1981
2032
|
const tre = evt;
|
|
2033
|
+
if (tre.contentParts !== undefined) {
|
|
2034
|
+
const canonical = normalizeToolResultContent(tre.callId, tre.content, tre.isError, tre.contentParts);
|
|
2035
|
+
toolOutputOverlay.set(tre.callId, canonical.blocks);
|
|
2036
|
+
}
|
|
1982
2037
|
toolResults.push({
|
|
1983
2038
|
callId: tre.callId,
|
|
1984
2039
|
output: tre.content,
|
|
1985
2040
|
isError: tre.isError,
|
|
1986
2041
|
isFatal: tre.isFatal,
|
|
1987
2042
|
errorKind: tre.errorKind,
|
|
2043
|
+
...(tre.contentParts?.length ? { contentParts: tre.contentParts } : {}),
|
|
1988
2044
|
});
|
|
1989
2045
|
}
|
|
1990
2046
|
else if (evt.type === "tool_argument_repaired") {
|
|
@@ -2069,6 +2125,7 @@ export class RuntimeRunner {
|
|
|
2069
2125
|
output: r.output,
|
|
2070
2126
|
is_error: r.isError,
|
|
2071
2127
|
token_count: r.tokenCount,
|
|
2128
|
+
content: { blocks: toolOutputBlocksToDurable(r.contentParts?.length ? r.contentParts : [{ type: "text", text: r.output }]) },
|
|
2072
2129
|
})),
|
|
2073
2130
|
});
|
|
2074
2131
|
// The canonical provider resolution already activates a successfully resolved `skill` call.
|
|
@@ -2256,7 +2313,7 @@ export class RuntimeRunner {
|
|
|
2256
2313
|
});
|
|
2257
2314
|
this.activeGroupBudgetScope = undefined;
|
|
2258
2315
|
}
|
|
2259
|
-
if (this.opts.
|
|
2316
|
+
if (this.opts.memoryStore && this.opts.agentId) {
|
|
2260
2317
|
const newMsgs = runtime.drainNewMessages().map(m => ({
|
|
2261
2318
|
role: m.role,
|
|
2262
2319
|
content: m.content,
|
|
@@ -2274,9 +2331,9 @@ export class RuntimeRunner {
|
|
|
2274
2331
|
createdAtMs: sessionStart,
|
|
2275
2332
|
updatedAtMs: Date.now(),
|
|
2276
2333
|
};
|
|
2277
|
-
await this.opts.
|
|
2334
|
+
await this.opts.memoryStore.saveSession(completedSession);
|
|
2278
2335
|
if (this.opts.memoryScope) {
|
|
2279
|
-
const extracted = await extractSessionMemories(this.opts.
|
|
2336
|
+
const extracted = await extractSessionMemories(this.opts.memoryProvider ?? this.opts.provider, completedSession, this.opts.memoryScope, this.opts.memorySystemPrompt);
|
|
2280
2337
|
for (const memory of extracted) {
|
|
2281
2338
|
await this.writeMemory(memory, { sessionId, agentId: this.opts.agentId });
|
|
2282
2339
|
}
|
|
@@ -2313,7 +2370,7 @@ export class RuntimeRunner {
|
|
|
2313
2370
|
* after each sprint renewal (`phase: "renewal"`): renewal drops the old history INCLUDING the
|
|
2314
2371
|
* earlier memory hits, so the new sprint gets a fresh recall pass. Errs-open throughout. */
|
|
2315
2372
|
async prefetchMemoryIntoHistory(runtime, phase) {
|
|
2316
|
-
if (!this.opts.
|
|
2373
|
+
if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
|
|
2317
2374
|
return undefined;
|
|
2318
2375
|
// P10: recall is default-on (CC session-start recall) — with no hook configured,
|
|
2319
2376
|
// the goal itself is the query. preQueryMemory stays as the targeting override.
|
|
@@ -2351,7 +2408,7 @@ export class RuntimeRunner {
|
|
|
2351
2408
|
return undefined;
|
|
2352
2409
|
}
|
|
2353
2410
|
async prefetchMemoryIntoInitialContext(runtime) {
|
|
2354
|
-
if (!this.opts.
|
|
2411
|
+
if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
|
|
2355
2412
|
return;
|
|
2356
2413
|
const preQuery = this.opts.preQueryMemory
|
|
2357
2414
|
?? ((ctx) => [{
|
|
@@ -2440,11 +2497,11 @@ export class RuntimeRunner {
|
|
|
2440
2497
|
return nextArchiveStart;
|
|
2441
2498
|
}
|
|
2442
2499
|
async archiveSemanticPageOut(archived, action, sessionId) {
|
|
2443
|
-
if (!this.opts.
|
|
2500
|
+
if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
|
|
2444
2501
|
return;
|
|
2445
|
-
const summary = this.opts.
|
|
2446
|
-
? await this.opts.
|
|
2447
|
-
: await summarizeForLongTermMemory(this.opts.
|
|
2502
|
+
const summary = this.opts.memorySummarizer
|
|
2503
|
+
? await this.opts.memorySummarizer.summarize(archived, { action })
|
|
2504
|
+
: await summarizeForLongTermMemory(this.opts.memoryProvider ?? this.opts.provider, archived, this.opts.memorySystemPrompt);
|
|
2448
2505
|
// P2 write-funnel: route through the ONE gated WriteMemory syscall so validation,
|
|
2449
2506
|
// the rolling write quota, dedup, and the memory_written audit all apply. Score is
|
|
2450
2507
|
// advisory (0.6) — an automatic summary must never outrank curated content.
|
|
@@ -2666,11 +2723,16 @@ export function replayMessages(events, maxBytes) {
|
|
|
2666
2723
|
}
|
|
2667
2724
|
else if (e.kind === "tool_completed") {
|
|
2668
2725
|
for (const r of e.results) {
|
|
2726
|
+
const durable = decodeDurableToolResult({
|
|
2727
|
+
call_id: r.call_id,
|
|
2728
|
+
is_error: r.is_error ?? false,
|
|
2729
|
+
blocks: decodeDurableContent(r.content).blocks,
|
|
2730
|
+
});
|
|
2669
2731
|
messages.push({
|
|
2670
2732
|
role: "tool",
|
|
2671
2733
|
content: "",
|
|
2672
2734
|
toolCalls: [],
|
|
2673
|
-
contentParts: [{ type: "tool_result", callId:
|
|
2735
|
+
contentParts: [{ type: "tool_result", callId: durable.call_id, output: sanitizeReplayText(r.output, maxBytes), isError: durable.is_error, ...(durable.blocks.length ? { contentParts: durableBlocksToToolOutput(durable.blocks) } : {}) }],
|
|
2674
2736
|
tokenCount: r.token_count,
|
|
2675
2737
|
});
|
|
2676
2738
|
}
|
|
@@ -2764,11 +2826,16 @@ export async function replayMessagesAsync(events, maxBytes, loadArchive) {
|
|
|
2764
2826
|
}
|
|
2765
2827
|
else if (e.kind === "tool_completed") {
|
|
2766
2828
|
for (const r of e.results) {
|
|
2829
|
+
const durable = decodeDurableToolResult({
|
|
2830
|
+
call_id: r.call_id,
|
|
2831
|
+
is_error: r.is_error ?? false,
|
|
2832
|
+
blocks: decodeDurableContent(r.content).blocks,
|
|
2833
|
+
});
|
|
2767
2834
|
messages.push({
|
|
2768
2835
|
role: "tool",
|
|
2769
2836
|
content: "",
|
|
2770
2837
|
toolCalls: [],
|
|
2771
|
-
contentParts: [{ type: "tool_result", callId:
|
|
2838
|
+
contentParts: [{ type: "tool_result", callId: durable.call_id, output: sanitizeReplayText(r.output, maxBytes), isError: durable.is_error, ...(durable.blocks.length ? { contentParts: durableBlocksToToolOutput(durable.blocks) } : {}) }],
|
|
2772
2839
|
tokenCount: r.token_count,
|
|
2773
2840
|
});
|
|
2774
2841
|
}
|
|
@@ -2790,6 +2857,21 @@ function nextArchivedSeqStart(events) {
|
|
|
2790
2857
|
}
|
|
2791
2858
|
return next;
|
|
2792
2859
|
}
|
|
2860
|
+
async function withTimeout(promise, timeoutMs) {
|
|
2861
|
+
let timer;
|
|
2862
|
+
try {
|
|
2863
|
+
return await Promise.race([
|
|
2864
|
+
promise,
|
|
2865
|
+
new Promise((_, reject) => {
|
|
2866
|
+
timer = setTimeout(() => reject(new Error("provider token measurement timed out")), timeoutMs);
|
|
2867
|
+
}),
|
|
2868
|
+
]);
|
|
2869
|
+
}
|
|
2870
|
+
finally {
|
|
2871
|
+
if (timer !== undefined)
|
|
2872
|
+
clearTimeout(timer);
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2793
2875
|
/** Collect all text_delta events from a run into a single string. */
|
|
2794
2876
|
export async function collectText(stream) {
|
|
2795
2877
|
let text = "";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { KernelPrimitive } from "./kernel-event-log.js";
|
|
2
2
|
import type { ContentPart, ProviderReplay, ToolCall, ToolErrorKind } from "../types.js";
|
|
3
|
+
import type { RecordedPromptMeasurement } from "../providers/request-plan.js";
|
|
3
4
|
import type { MemoryRecall, MemoryScope } from "../memory/protocols.js";
|
|
4
5
|
import type { KernelJournal } from "./kernel-journal.js";
|
|
5
6
|
export type RollbackReason = {
|
|
@@ -36,6 +37,10 @@ export type SessionEvent = {
|
|
|
36
37
|
token_count?: number;
|
|
37
38
|
tool_calls: ToolCall[];
|
|
38
39
|
provider_replay?: ProviderReplay;
|
|
40
|
+
} | {
|
|
41
|
+
kind: "prompt_measured";
|
|
42
|
+
turn: number;
|
|
43
|
+
measurement: RecordedPromptMeasurement;
|
|
39
44
|
} | {
|
|
40
45
|
kind: "tool_requested";
|
|
41
46
|
turn: number;
|
|
@@ -50,6 +55,9 @@ export type SessionEvent = {
|
|
|
50
55
|
is_fatal?: boolean;
|
|
51
56
|
error_kind?: ToolErrorKind;
|
|
52
57
|
token_count?: number;
|
|
58
|
+
content: {
|
|
59
|
+
blocks: Record<string, unknown>[];
|
|
60
|
+
};
|
|
53
61
|
}>;
|
|
54
62
|
} | {
|
|
55
63
|
kind: "tool_argument_repaired";
|
|
@@ -177,7 +185,6 @@ export type SessionEvent = {
|
|
|
177
185
|
kind: "entropy_sample";
|
|
178
186
|
turn: number;
|
|
179
187
|
score: number;
|
|
180
|
-
score_version: number;
|
|
181
188
|
rho: number;
|
|
182
189
|
repeat_pressure: number;
|
|
183
190
|
failure_rate: number;
|
|
@@ -5,6 +5,7 @@ import { createInterface } from "node:readline";
|
|
|
5
5
|
import { primitiveForKind } from "./kernel-event-log.js";
|
|
6
6
|
import { KeyedSerialExecutor } from "./reliability.js";
|
|
7
7
|
import { FileKernelJournal, InMemoryKernelJournal } from "./kernel-journal.js";
|
|
8
|
+
import { decodeDurableContent } from "./durable-content.js";
|
|
8
9
|
/**
|
|
9
10
|
* **Single-process dev/test implementation** of both capabilities (spec §9.4: one class may
|
|
10
11
|
* implement several capabilities; the *interfaces* stay separate). Its `KernelJournal` half is
|
|
@@ -84,7 +85,7 @@ export class FileSessionLog {
|
|
|
84
85
|
async read(sessionId, fromSeq = 0, primitiveFilter) {
|
|
85
86
|
const results = [];
|
|
86
87
|
for (const record of await this.readRecords(sessionId)) {
|
|
87
|
-
if (
|
|
88
|
+
if (record.seq < fromSeq)
|
|
88
89
|
continue;
|
|
89
90
|
if (primitiveFilter && primitiveForKind(record.event.kind) !== primitiveFilter)
|
|
90
91
|
continue;
|
|
@@ -133,7 +134,7 @@ export class FileSessionLog {
|
|
|
133
134
|
});
|
|
134
135
|
for await (const line of rl) {
|
|
135
136
|
if (line.trim())
|
|
136
|
-
records.push(JSON.parse(line));
|
|
137
|
+
records.push(decodePersistedSessionRecord(JSON.parse(line)));
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
catch (err) {
|
|
@@ -143,3 +144,42 @@ export class FileSessionLog {
|
|
|
143
144
|
return records;
|
|
144
145
|
}
|
|
145
146
|
}
|
|
147
|
+
function decodePersistedSessionRecord(value) {
|
|
148
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
149
|
+
throw new Error("session record must be an object");
|
|
150
|
+
const record = value;
|
|
151
|
+
if (Object.keys(record).some(key => key !== "seq" && key !== "event"))
|
|
152
|
+
throw new Error("session record has unknown fields");
|
|
153
|
+
if (!Number.isInteger(record.seq) || record.seq < 0)
|
|
154
|
+
throw new Error("session record seq must be a non-negative integer");
|
|
155
|
+
if (!record.event || typeof record.event !== "object" || Array.isArray(record.event))
|
|
156
|
+
throw new Error("session record event must be an object");
|
|
157
|
+
const event = record.event;
|
|
158
|
+
if (event.kind === "llm_completed" && event.provider_replay !== undefined) {
|
|
159
|
+
assertCanonicalProviderReplay(event.provider_replay);
|
|
160
|
+
}
|
|
161
|
+
if (event.kind === "tool_completed") {
|
|
162
|
+
if (!Array.isArray(event.results))
|
|
163
|
+
throw new Error("tool_completed results must be an array");
|
|
164
|
+
for (const result of event.results) {
|
|
165
|
+
if (!result || typeof result !== "object" || Array.isArray(result))
|
|
166
|
+
throw new Error("tool_completed result must be an object");
|
|
167
|
+
const wire = result;
|
|
168
|
+
if ("blocks" in wire)
|
|
169
|
+
throw new Error("tool_completed result has removed blocks field");
|
|
170
|
+
decodeDurableContent(wire.content);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return { seq: record.seq, event: event };
|
|
174
|
+
}
|
|
175
|
+
const REPLAY_KEYS = new Set(["protocol", "provider", "model", "native_blocks", "reasoning_content", "reasoning_details", "native_message", "tool_calls"]);
|
|
176
|
+
function assertCanonicalProviderReplay(value) {
|
|
177
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
178
|
+
throw new Error("provider replay must be an object");
|
|
179
|
+
const replay = value;
|
|
180
|
+
for (const key of Object.keys(replay))
|
|
181
|
+
if (!REPLAY_KEYS.has(key))
|
|
182
|
+
throw new Error(`provider replay has unknown field ${key}`);
|
|
183
|
+
if (typeof replay.protocol !== "string" || replay.protocol.length === 0)
|
|
184
|
+
throw new Error("provider replay protocol is required");
|
|
185
|
+
}
|
|
@@ -8,7 +8,7 @@ export { REPLAY_CONTENT_MAX_BYTES as RECOVERY_CONTENT_MAX_BYTES } from "./replay
|
|
|
8
8
|
* Content is sanitized and token_count backfilled, but the stored
|
|
9
9
|
* `provider_replay` envelope is passed through verbatim — this layer is
|
|
10
10
|
* provider-neutral and must never synthesize protocol-specific replay shapes
|
|
11
|
-
* (e.g. Anthropic `native_blocks`).
|
|
11
|
+
* (e.g. Anthropic `native_blocks`). Canonical replay seeding for a given protocol
|
|
12
12
|
* is the responsibility of that provider's `seedProviderReplay`.
|
|
13
13
|
*/
|
|
14
14
|
export declare function normalizeLlmCompleted(event: Extract<SessionEvent, {
|
|
@@ -9,7 +9,7 @@ function estimateTokenCount(text) {
|
|
|
9
9
|
* Content is sanitized and token_count backfilled, but the stored
|
|
10
10
|
* `provider_replay` envelope is passed through verbatim — this layer is
|
|
11
11
|
* provider-neutral and must never synthesize protocol-specific replay shapes
|
|
12
|
-
* (e.g. Anthropic `native_blocks`).
|
|
12
|
+
* (e.g. Anthropic `native_blocks`). Canonical replay seeding for a given protocol
|
|
13
13
|
* is the responsibility of that provider's `seedProviderReplay`.
|
|
14
14
|
*/
|
|
15
15
|
export function normalizeLlmCompleted(event, maxBytes) {
|
|
@@ -13,7 +13,7 @@ export interface SubAgentRunContext {
|
|
|
13
13
|
evalProvider: import("../types.js").LLMProvider;
|
|
14
14
|
maxAttempts?: number;
|
|
15
15
|
};
|
|
16
|
-
/**
|
|
16
|
+
/** workflow-node: set when this child is a workflow node (spawned by the workflow driver). Propagated to
|
|
17
17
|
* the child runner so a nested `start_workflow` FLATTENS to the parent kernel rather than
|
|
18
18
|
* auto-pivoting into its own bootstrap (which would fragment the one-kernel/one-quota governance). */
|
|
19
19
|
isWorkflowNode?: boolean;
|