@deepstrike/sdk 0.2.52 → 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.
Files changed (148) hide show
  1. package/README.md +28 -28
  2. package/dist/agent-ir.d.ts +103 -0
  3. package/dist/agent-ir.js +134 -0
  4. package/dist/agent.d.ts +67 -0
  5. package/dist/agent.js +36 -0
  6. package/dist/collaboration/harness.js +1 -1
  7. package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
  8. package/dist/collaboration/modes/creator-verifier.js +4 -6
  9. package/dist/collaboration/pool.d.ts +8 -20
  10. package/dist/collaboration/pool.js +27 -97
  11. package/dist/compat/anthropic/mcp.d.ts +15 -0
  12. package/dist/compat/anthropic/mcp.js +10 -0
  13. package/dist/compat/openai/agent.d.ts +34 -0
  14. package/dist/compat/openai/agent.js +24 -0
  15. package/dist/governance.d.ts +1 -17
  16. package/dist/governance.js +1 -34
  17. package/dist/guardrail.d.ts +6 -0
  18. package/dist/guardrail.js +1 -0
  19. package/dist/handoff-target.d.ts +12 -0
  20. package/dist/handoff-target.js +1 -0
  21. package/dist/harness/manifest.js +0 -4
  22. package/dist/index.d.ts +19 -7
  23. package/dist/index.js +8 -5
  24. package/dist/kernel.d.ts +2 -20
  25. package/dist/knowledge/public.d.ts +29 -0
  26. package/dist/knowledge/public.js +1 -0
  27. package/dist/mcp-server.d.ts +28 -0
  28. package/dist/mcp-server.js +1 -0
  29. package/dist/memory/agent.d.ts +2 -2
  30. package/dist/memory/agent.js +2 -2
  31. package/dist/memory/durable.d.ts +16 -0
  32. package/dist/memory/durable.js +46 -0
  33. package/dist/memory/in-memory-store.d.ts +9 -7
  34. package/dist/memory/in-memory-store.js +8 -2
  35. package/dist/memory/protocols.d.ts +22 -4
  36. package/dist/memory/public.d.ts +4 -3
  37. package/dist/memory/public.js +3 -2
  38. package/dist/providers/anthropic-adapter.d.ts +47 -0
  39. package/dist/providers/anthropic-adapter.js +444 -0
  40. package/dist/providers/anthropic-compatible.d.ts +2 -3
  41. package/dist/providers/anthropic-compatible.js +8 -5
  42. package/dist/providers/anthropic.d.ts +19 -23
  43. package/dist/providers/anthropic.js +169 -395
  44. package/dist/providers/base.js +43 -3
  45. package/dist/providers/capability-router.d.ts +29 -0
  46. package/dist/providers/capability-router.js +43 -0
  47. package/dist/providers/catalog.d.ts +16 -4
  48. package/dist/providers/catalog.js +112 -21
  49. package/dist/providers/content-normalization.d.ts +57 -0
  50. package/dist/providers/content-normalization.js +238 -0
  51. package/dist/providers/content-policy.d.ts +16 -0
  52. package/dist/providers/content-policy.js +39 -0
  53. package/dist/providers/credentials.d.ts +83 -0
  54. package/dist/providers/credentials.js +190 -0
  55. package/dist/providers/endpoints.d.ts +137 -0
  56. package/dist/providers/endpoints.js +128 -0
  57. package/dist/providers/factories.js +9 -3
  58. package/dist/providers/gemini-adapter.d.ts +33 -0
  59. package/dist/providers/gemini-adapter.js +272 -0
  60. package/dist/providers/gemini.d.ts +16 -3
  61. package/dist/providers/gemini.js +97 -195
  62. package/dist/providers/model-catalog.d.ts +37 -0
  63. package/dist/providers/model-catalog.js +62 -0
  64. package/dist/providers/model-registry.d.ts +98 -0
  65. package/dist/providers/model-registry.js +315 -0
  66. package/dist/providers/ollama-adapter.d.ts +65 -0
  67. package/dist/providers/ollama-adapter.js +188 -0
  68. package/dist/providers/ollama.d.ts +9 -4
  69. package/dist/providers/ollama.js +96 -109
  70. package/dist/providers/openai-chat-dialects.d.ts +154 -0
  71. package/dist/providers/openai-chat-dialects.js +179 -0
  72. package/dist/providers/openai-chat.d.ts +46 -18
  73. package/dist/providers/openai-chat.js +418 -51
  74. package/dist/providers/openai-responses-adapter.d.ts +42 -0
  75. package/dist/providers/openai-responses-adapter.js +341 -0
  76. package/dist/providers/openai-responses.d.ts +14 -33
  77. package/dist/providers/openai-responses.js +131 -264
  78. package/dist/providers/openai.d.ts +29 -76
  79. package/dist/providers/openai.js +195 -292
  80. package/dist/providers/protocol-adapter.d.ts +34 -0
  81. package/dist/providers/protocol-adapter.js +9 -0
  82. package/dist/providers/protocol-capabilities.d.ts +34 -0
  83. package/dist/providers/protocol-capabilities.js +44 -0
  84. package/dist/providers/provider-error.d.ts +31 -0
  85. package/dist/providers/provider-error.js +149 -0
  86. package/dist/providers/public.d.ts +26 -3
  87. package/dist/providers/public.js +13 -1
  88. package/dist/providers/registry.d.ts +7 -6
  89. package/dist/providers/registry.js +47 -20
  90. package/dist/providers/request-plan.d.ts +86 -0
  91. package/dist/providers/request-plan.js +175 -0
  92. package/dist/providers/usage-normalizer.d.ts +48 -0
  93. package/dist/providers/usage-normalizer.js +96 -0
  94. package/dist/providers/vendor-profiles.d.ts +2 -15
  95. package/dist/providers/vendor-profiles.js +14 -60
  96. package/dist/runtime/canonical-kernel-step.d.ts +1 -2
  97. package/dist/runtime/canonical-kernel-step.js +47 -12
  98. package/dist/runtime/context-policy.d.ts +10 -12
  99. package/dist/runtime/context-policy.js +6 -8
  100. package/dist/runtime/durable-content.d.ts +50 -0
  101. package/dist/runtime/durable-content.js +159 -0
  102. package/dist/runtime/execution-plane.d.ts +2 -2
  103. package/dist/runtime/execution-plane.js +2 -2
  104. package/dist/runtime/kernel-event-log.js +0 -1
  105. package/dist/runtime/kernel-step.d.ts +0 -1
  106. package/dist/runtime/kernel-step.js +4 -2
  107. package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
  108. package/dist/runtime/mcp-proxy-plane.js +44 -6
  109. package/dist/runtime/output-schema.d.ts +1 -2
  110. package/dist/runtime/provider-replay.d.ts +1 -1
  111. package/dist/runtime/provider-replay.js +12 -27
  112. package/dist/runtime/reactive-session.d.ts +1 -1
  113. package/dist/runtime/reactive-session.js +2 -3
  114. package/dist/runtime/run-group.d.ts +1 -1
  115. package/dist/runtime/runner.d.ts +26 -40
  116. package/dist/runtime/runner.js +145 -63
  117. package/dist/runtime/session-log.d.ts +8 -1
  118. package/dist/runtime/session-log.js +42 -2
  119. package/dist/runtime/session-repair.d.ts +1 -1
  120. package/dist/runtime/session-repair.js +1 -1
  121. package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
  122. package/dist/runtime/sub-agent-orchestrator.js +8 -11
  123. package/dist/runtime/workflow-control-flow.d.ts +0 -4
  124. package/dist/runtime/workflow-control-flow.js +0 -16
  125. package/dist/session.d.ts +11 -0
  126. package/dist/session.js +1 -0
  127. package/dist/skill.d.ts +17 -0
  128. package/dist/skill.js +16 -0
  129. package/dist/skills/loader.d.ts +3 -0
  130. package/dist/tools/errors.d.ts +1 -3
  131. package/dist/tools/errors.js +1 -3
  132. package/dist/tools/index.d.ts +3 -0
  133. package/dist/types/agent.d.ts +21 -9
  134. package/dist/types/agent.js +30 -4
  135. package/dist/types.d.ts +128 -13
  136. package/package.json +3 -3
  137. package/dist/providers/deepseek.d.ts +0 -46
  138. package/dist/providers/deepseek.js +0 -97
  139. package/dist/providers/glm.d.ts +0 -25
  140. package/dist/providers/glm.js +0 -48
  141. package/dist/providers/kimi.d.ts +0 -23
  142. package/dist/providers/kimi.js +0 -30
  143. package/dist/providers/minimax.d.ts +0 -49
  144. package/dist/providers/minimax.js +0 -98
  145. package/dist/providers/profiles.d.ts +0 -1992
  146. package/dist/providers/profiles.js +0 -796
  147. package/dist/providers/qwen.d.ts +0 -38
  148. package/dist/providers/qwen.js +0 -97
@@ -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, extractLoopContinue, extractClassifyBranch, extractJudgeWinner, } from "./workflow-control-flow.js";
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 { contextPolicyV1, normalizeContextPolicyV1, } from "./context-policy.js";
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
- "version", "criticalPathWeight", "fanoutWeight", "ageWeight", "tokenCostWeight",
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.dreamStore)
218
- throw new Error("memory persistence requires dreamStore");
219
- await this.opts.dreamStore.upsert(agentId, memory);
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.dreamStore)
223
- throw new Error("memory queries require dreamStore");
224
- return (await this.opts.dreamStore.search(agentId, { ...query, top_k: requestedK }))
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 only mutation
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.dreamStore || !agentId)
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.dreamStore || !agentId)
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.dreamStore?.recordRecall?.(agentId, recalls);
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 = normalizeContextPolicyV1(contextPolicyV1(this.opts.contextPolicy));
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.dreamStore?.recordRecall) {
521
- await this.opts.dreamStore.recordRecall(agentId, obs.recalls);
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
- // A#2 v2 loop iteration: run the increment under the armed pacing trap (workflowNodeToSpec set
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
- // DW-3 one vocabulary: the kernel-adjudicated `pace` verb IS the continuation signal
648
- // (stop loopContinue=false); the legacy text-sniffed JSON blob survives only as the fallback
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
- if (pace)
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.dreamStore && this.opts.agentId) {
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 augments an explicit spec, else
1443
- // synthesizes a minimal top-level spec carrying just the exposure config (reuses the existing
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
- if (this.opts.runSpec || hasProfile || hasBaseline || hasMilestoneContract) {
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
- if (hasBaseline)
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 dreamStore/agentId is absent.
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: formatToolError(err),
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: formatToolError(err) };
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
- dreamStore: this.opts.dreamStore,
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 = this.opts.onToolCallFailure === "open"
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.dreamStore && this.opts.agentId) {
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.dreamStore.saveSession(completedSession);
2334
+ await this.opts.memoryStore.saveSession(completedSession);
2278
2335
  if (this.opts.memoryScope) {
2279
- const extracted = await extractSessionMemories(this.opts.dreamProvider ?? this.opts.provider, completedSession, this.opts.memoryScope, this.opts.dreamSystemPrompt);
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.dreamStore || !this.opts.agentId || !this.opts.memoryScope)
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.dreamStore || !this.opts.agentId || !this.opts.memoryScope)
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.dreamStore || !this.opts.agentId || !this.opts.memoryScope)
2500
+ if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
2444
2501
  return;
2445
- const summary = this.opts.dreamSummarizer
2446
- ? await this.opts.dreamSummarizer.summarize(archived, { action })
2447
- : await summarizeForLongTermMemory(this.opts.dreamProvider ?? this.opts.provider, archived, this.opts.dreamSystemPrompt);
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: r.call_id, output: sanitizeReplayText(r.output, maxBytes), isError: r.is_error ?? false }],
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: r.call_id, output: sanitizeReplayText(r.output, maxBytes), isError: r.is_error ?? false }],
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 (!("event" in record) || record.seq < fromSeq)
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`). Legacy reconstruction for a given protocol
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`). Legacy reconstruction for a given protocol
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
- /** M5 v2.1: set when this child is a workflow node (spawned by the workflow driver). Propagated to
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;