@deepstrike/wasm 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 (54) hide show
  1. package/README.md +15 -14
  2. package/dist/agent-ir.d.ts +81 -0
  3. package/dist/agent-ir.js +115 -0
  4. package/dist/agent.d.ts +140 -0
  5. package/dist/agent.js +34 -0
  6. package/dist/governance.d.ts +0 -25
  7. package/dist/governance.js +1 -53
  8. package/dist/index.d.ts +23 -8
  9. package/dist/index.js +11 -4
  10. package/dist/memory/durable.d.ts +13 -0
  11. package/dist/memory/durable.js +42 -0
  12. package/dist/memory/in-memory-store.d.ts +8 -6
  13. package/dist/memory/in-memory-store.js +8 -2
  14. package/dist/memory/index.d.ts +18 -2
  15. package/dist/providers/anthropic.d.ts +9 -0
  16. package/dist/providers/anthropic.js +12 -33
  17. package/dist/providers/content-policy.d.ts +16 -0
  18. package/dist/providers/content-policy.js +39 -0
  19. package/dist/providers/openai.d.ts +36 -17
  20. package/dist/providers/openai.js +86 -46
  21. package/dist/providers/provider-error.d.ts +22 -0
  22. package/dist/providers/provider-error.js +90 -0
  23. package/dist/providers/request-plan.d.ts +87 -0
  24. package/dist/providers/request-plan.js +153 -0
  25. package/dist/providers/stop-reason.d.ts +5 -0
  26. package/dist/providers/stop-reason.js +24 -0
  27. package/dist/runtime/canonical-kernel-step.d.ts +2 -5
  28. package/dist/runtime/canonical-kernel-step.js +40 -58
  29. package/dist/runtime/context-policy.d.ts +10 -12
  30. package/dist/runtime/context-policy.js +6 -8
  31. package/dist/runtime/durable-content.d.ts +44 -0
  32. package/dist/runtime/durable-content.js +119 -0
  33. package/dist/runtime/execution-plane.d.ts +2 -2
  34. package/dist/runtime/execution-plane.js +2 -2
  35. package/dist/runtime/kernel-event-log.js +0 -1
  36. package/dist/runtime/kernel-step.d.ts +1 -2
  37. package/dist/runtime/kernel-step.js +1 -1
  38. package/dist/runtime/provider-replay.d.ts +1 -1
  39. package/dist/runtime/provider-replay.js +12 -20
  40. package/dist/runtime/runner.d.ts +22 -18
  41. package/dist/runtime/runner.js +115 -55
  42. package/dist/runtime/session-log.d.ts +8 -1
  43. package/dist/runtime/session-repair.d.ts +1 -1
  44. package/dist/runtime/session-repair.js +1 -1
  45. package/dist/runtime/sha256.d.ts +2 -0
  46. package/dist/runtime/sha256.js +38 -0
  47. package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
  48. package/dist/runtime/sub-agent-orchestrator.js +3 -3
  49. package/dist/runtime/types/agent.d.ts +17 -7
  50. package/dist/runtime/types/agent.js +30 -4
  51. package/dist/runtime/workflow-control-flow.d.ts +0 -4
  52. package/dist/runtime/workflow-control-flow.js +0 -16
  53. package/dist/types.d.ts +58 -5
  54. package/package.json +2 -2
@@ -5,6 +5,7 @@ import { getKernel } from "./kernel.js";
5
5
  import { CanonicalRunnerRuntime, canonicalKernelAction, canonicalKernelApply, canonicalKernelMaybeAction, canonicalStartAgent, canonicalStartWorkflow, sha256 as canonicalSha256, } from "./canonical-kernel-step.js";
6
6
  import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-replay.js";
7
7
  import { sanitizeReplayText } from "./replay-sanitize.js";
8
+ import { decodeDurableContent, decodeDurableToolResult, durableBlocksToToolOutput, toolOutputBlocksToDurable } from "./durable-content.js";
8
9
  import { formatToolError } from "../tools/errors.js";
9
10
  import { buildLlmCompletedEvent, buildRunTerminalEvent, buildWorkflowNodeCompletedEvent, buildWorkflowNodesSubmittedEvent, } from "./session-repair.js";
10
11
  import { messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
@@ -12,24 +13,30 @@ import { agentRunSpecToKernel, MILESTONE_UNVERIFIED_REASON, milestoneCheckFail,
12
13
  import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
13
14
  import { extractJsonValue, schemaInstruction, schemaRetryInstruction, validateAgainstSchema, } from "./output-schema.js";
14
15
  import { resolveReducer } from "./reducers.js";
15
- 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";
16
17
  import { kernelObservationToSessionEvent } from "./kernel-event-log.js";
17
18
  import { assertNativeProfile } from "./os-profile.js";
19
+ import { classifyProviderError, providerErrorEventFields } from "../providers/provider-error.js";
18
20
  import { PayloadStore } from "./payload-store.js";
19
- import { contextPolicyV1, normalizeContextPolicyV1, } from "./context-policy.js";
21
+ import { contextPolicy, normalizeContextPolicy, } from "./context-policy.js";
22
+ import { createProviderRequestPlanForProvider, estimateProviderPromptTokens, measurementForPlan, recordPromptMeasurement, } from "../providers/request-plan.js";
20
23
  export function schedulerPolicyToKernel(policy) {
21
24
  const allowed = new Set([
22
- "version", "criticalPathWeight", "fanoutWeight", "ageWeight", "tokenCostWeight",
25
+ "criticalPathWeight", "fanoutWeight", "ageWeight", "tokenCostWeight",
26
+ "deadlineWeight", "processPriorityWeight", "resourcePressureWeight", "budgetPressureWeight",
23
27
  ]);
24
28
  const unknown = Object.keys(policy).filter(key => !allowed.has(key));
25
29
  if (unknown.length > 0)
26
30
  throw new TypeError(`unknown scheduler policy field(s): ${unknown.join(", ")}`);
27
31
  return {
28
- version: policy.version,
29
32
  critical_path_weight: policy.criticalPathWeight,
30
33
  fanout_weight: policy.fanoutWeight,
31
34
  age_weight: policy.ageWeight,
32
35
  token_cost_weight: policy.tokenCostWeight,
36
+ ...(policy.deadlineWeight !== undefined ? { deadline_weight: policy.deadlineWeight } : {}),
37
+ ...(policy.processPriorityWeight !== undefined ? { process_priority_weight: policy.processPriorityWeight } : {}),
38
+ ...(policy.resourcePressureWeight !== undefined ? { resource_pressure_weight: policy.resourcePressureWeight } : {}),
39
+ ...(policy.budgetPressureWeight !== undefined ? { budget_pressure_weight: policy.budgetPressureWeight } : {}),
33
40
  };
34
41
  }
35
42
  function kernelReliabilityToKernel(policy) {
@@ -292,10 +299,10 @@ export class RuntimeRunner {
292
299
  yield* this.execute(sessionId, start.run_id, start.goal, start.criteria, extensions, events, true, start.attachments);
293
300
  }
294
301
  async writeMemory(memory, sessionId) {
295
- if (!this.opts.dreamStore || !this.opts.agentId)
302
+ if (!this.opts.memoryStore || !this.opts.agentId)
296
303
  return;
297
304
  try {
298
- await this.opts.dreamStore.upsert(this.opts.agentId, memory);
305
+ await this.opts.memoryStore.put(this.opts.agentId, memory);
299
306
  }
300
307
  catch (cause) {
301
308
  throw new Error(formatToolError(cause));
@@ -419,6 +426,7 @@ export class RuntimeRunner {
419
426
  output: `permission denied: ${denyReason}`,
420
427
  is_error: true,
421
428
  error_kind: "governance_denied",
429
+ content: { blocks: [{ type: "text", text: `permission denied: ${denyReason}` }] },
422
430
  }],
423
431
  });
424
432
  }
@@ -436,6 +444,12 @@ export class RuntimeRunner {
436
444
  const ext = { ...this.opts.extensions, ...(extensions ?? {}) };
437
445
  const providerState = this.opts.provider.createRunState?.();
438
446
  let nextCompressedArchiveStart = nextArchivedSeqStart(priorEvents);
447
+ const recordedMeasurements = new Map();
448
+ for (const entry of priorEvents ?? []) {
449
+ if (entry.event.kind === "prompt_measured") {
450
+ recordedMeasurements.set(entry.event.measurement.requestFingerprint, entry.event.measurement);
451
+ }
452
+ }
439
453
  const providerPolicy = this.opts.provider.runtimePolicy?.() ?? {};
440
454
  const effectiveMaxTurns = this.opts.maxTurns ?? providerPolicy.maxTurns ?? 25;
441
455
  const effectiveTimeoutMs = this.opts.timeoutMs ?? providerPolicy.timeoutMs;
@@ -494,7 +508,7 @@ export class RuntimeRunner {
494
508
  tool_ids: this.opts.stableCoreToolIds,
495
509
  });
496
510
  }
497
- if (this.opts.dreamStore && this.opts.agentId) {
511
+ if (this.opts.memoryStore && this.opts.agentId) {
498
512
  await this.commitKernelApply(runtime, this.pendingObservations, { kind: "set_memory_enabled", enabled: true });
499
513
  }
500
514
  if (this.opts.knowledgeSource) {
@@ -542,7 +556,7 @@ export class RuntimeRunner {
542
556
  const output = toolResultByCallId.get(tc.id);
543
557
  if (output && !this.knowledgePushedSkills.has(name)) {
544
558
  this.knowledgePushedSkills.add(name);
545
- // K1: keyed — the kernel-side upsert is the authoritative dedup across wake replays.
559
+ // K1: keyed — the kernel-side put is the authoritative dedup across wake replays.
546
560
  this.pushKnowledge({ role: "system", content: output }, undefined, { key: `skill:${name}` });
547
561
  }
548
562
  }
@@ -565,15 +579,14 @@ export class RuntimeRunner {
565
579
  const startTask = { goal, criteria };
566
580
  let startRunSpec;
567
581
  // P0-A: lower an explicit `runSpec`, the `allowedToolIds` ceiling, and/or the `baselineToolIds`
568
- // pre-activation surface to the kernel run spec (reuses the existing run_spec wire — no new
569
- // ABI). Unset on all ⇒ no gating (铁律: no config = old behavior).
582
+ // pre-activation surface to the kernel run spec. Every run has a run spec; an omitted baseline
583
+ // is the canonical minimal surface.
570
584
  const allowedToolIds = this.opts.allowedToolIds;
571
585
  const hasProfile = allowedToolIds !== undefined && allowedToolIds.length > 0;
572
586
  // NOT the `length > 0` idiom above: `baselineToolIds: []` is the legitimate minimal surface
573
587
  // (meta + stable-core only), so mere presence triggers the lowering.
574
- const baselineToolIds = this.opts.baselineToolIds;
575
- const hasBaseline = baselineToolIds !== undefined;
576
- if (this.opts.runSpec || hasProfile || hasBaseline) {
588
+ const baselineToolIds = this.opts.baselineToolIds ?? this.opts.runSpec?.exposureBaseline ?? [];
589
+ {
577
590
  const baseSpec = this.opts.runSpec ?? {
578
591
  identity: { agentId: this.opts.agentId ?? "root", sessionId, isSubAgent: false },
579
592
  role: "custom",
@@ -582,8 +595,7 @@ export class RuntimeRunner {
582
595
  let spec = hasProfile
583
596
  ? { ...baseSpec, capabilityFilter: { ...baseSpec.capabilityFilter, allowedIds: allowedToolIds } }
584
597
  : baseSpec;
585
- if (hasBaseline)
586
- spec = { ...spec, exposureBaseline: baselineToolIds };
598
+ spec = { ...spec, exposureBaseline: baselineToolIds };
587
599
  startRunSpec = agentRunSpecToKernel(spec);
588
600
  }
589
601
  if (!resumeMidRun)
@@ -651,6 +663,43 @@ export class RuntimeRunner {
651
663
  let turnCacheCreationTokens = 0;
652
664
  let turnCacheReadBySlot;
653
665
  let turnStopReason;
666
+ const providerPlan = createProviderRequestPlanForProvider(this.opts.provider, context, tools, ext);
667
+ let promptMeasurement = measurementForPlan(providerPlan, recordedMeasurements.get(providerPlan.fingerprint));
668
+ if (!promptMeasurement && !context.budgetOverflow) {
669
+ try {
670
+ const counted = this.opts.provider.countTokens
671
+ ? await withTimeout(this.opts.provider.countTokens(context, tools, Object.keys(ext).length ? ext : undefined), 5_000)
672
+ : undefined;
673
+ promptMeasurement = recordPromptMeasurement(providerPlan, counted ?? {
674
+ inputTokens: estimateProviderPromptTokens(context, tools),
675
+ source: { kind: "heuristic" },
676
+ confidence: "low_confidence",
677
+ });
678
+ }
679
+ catch {
680
+ promptMeasurement = recordPromptMeasurement(providerPlan, {
681
+ inputTokens: estimateProviderPromptTokens(context, tools),
682
+ source: { kind: "heuristic" },
683
+ confidence: "low_confidence",
684
+ });
685
+ }
686
+ recordedMeasurements.set(providerPlan.fingerprint, promptMeasurement);
687
+ await this.opts.sessionLog.append(sessionId, { kind: "prompt_measured", turn: runtime.turn(), measurement: promptMeasurement });
688
+ }
689
+ const reservedPromptTokens = (this.opts.promptBudget?.promptOverheadTokens ?? 0)
690
+ + (this.opts.promptBudget?.outputReserveTokens ?? 0)
691
+ + (this.opts.promptBudget?.safetyMarginTokens ?? 0);
692
+ const measuredOverflow = promptMeasurement
693
+ && promptMeasurement.source.kind !== "heuristic"
694
+ && promptMeasurement.inputTokens + reservedPromptTokens > this.opts.maxTokens;
695
+ if (context.budgetOverflow || measuredOverflow) {
696
+ action = await this.commitKernelAction(runtime, this.pendingObservations, {
697
+ kind: "provider_error", effect_id: providerEffectId,
698
+ message: "provider-visible prompt exceeds the configured context budget",
699
+ error_kind: "context_overflow", retryable: false,
700
+ });
701
+ continue;
702
+ }
654
703
  const abortSignal = this.abortController?.signal;
655
704
  try {
656
705
  for await (const evt of this.opts.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState, abortSignal)) {
@@ -690,6 +739,8 @@ export class RuntimeRunner {
690
739
  this.cancellationReason ??= "user";
691
740
  }
692
741
  else {
742
+ const descriptor = this.opts.provider.descriptor?.();
743
+ const providerError = classifyProviderError(descriptor?.provider ?? "unknown", err);
693
744
  // Reactive recovery is now a kernel decision. Forward the raw provider error and
694
745
  // dispatch whatever the kernel returns: `call_provider` to retry with a freshly
695
746
  // compacted context, or `done` to terminate with an honest `ContextOverflow`. The
@@ -698,7 +749,8 @@ export class RuntimeRunner {
698
749
  action = await this.commitKernelAction(runtime, this.pendingObservations, {
699
750
  kind: "provider_error",
700
751
  effect_id: providerEffectId,
701
- message: formatToolError(err),
752
+ message: providerError.message,
753
+ ...providerErrorEventFields(providerError),
702
754
  });
703
755
  // Withholding (query.ts parity): surface the raw provider error only when the kernel
704
756
  // could NOT recover (it returned a terminal). On a recovered retry (`call_provider`)
@@ -706,7 +758,7 @@ export class RuntimeRunner {
706
758
  // compaction archive via the loop-top appendObservations, and a terminal `done` exits
707
759
  // through `isTerminal()`.
708
760
  if (action.kind === "done") {
709
- yield { type: "error", message: formatToolError(err) };
761
+ yield { type: "error", message: providerError.message };
710
762
  }
711
763
  continue;
712
764
  }
@@ -784,9 +836,9 @@ export class RuntimeRunner {
784
836
  else if (action.kind === "persist_memory") {
785
837
  let error;
786
838
  try {
787
- if (!this.opts.dreamStore || !this.opts.agentId)
788
- throw new Error("WASM memory persistence requires dreamStore and agentId");
789
- await this.opts.dreamStore.upsert(this.opts.agentId, action.memory);
839
+ if (!this.opts.memoryStore || !this.opts.agentId)
840
+ throw new Error("WASM memory persistence requires memoryStore and agentId");
841
+ await this.opts.memoryStore.put(this.opts.agentId, action.memory);
790
842
  }
791
843
  catch (cause) {
792
844
  error = formatToolError(cause);
@@ -801,9 +853,9 @@ export class RuntimeRunner {
801
853
  let hits = [];
802
854
  let error;
803
855
  try {
804
- if (!this.opts.dreamStore || !this.opts.agentId)
805
- throw new Error("WASM memory queries require dreamStore and agentId");
806
- hits = await this.opts.dreamStore.search(this.opts.agentId, {
856
+ if (!this.opts.memoryStore || !this.opts.agentId)
857
+ throw new Error("WASM memory queries require memoryStore and agentId");
858
+ hits = await this.opts.memoryStore.search(this.opts.agentId, {
807
859
  ...action.query, top_k: action.requestedK,
808
860
  });
809
861
  }
@@ -820,7 +872,7 @@ export class RuntimeRunner {
820
872
  // M3/M4: mirror the kernel's journaled recall lifecycle + surface promotion suggestions.
821
873
  for (const obs of this.pendingObservations.slice(obsStart)) {
822
874
  if (obs.kind === "memory_recalled" && obs.recalls?.length && this.opts.agentId) {
823
- await this.opts.dreamStore?.recordRecall?.(this.opts.agentId, obs.recalls);
875
+ await this.opts.memoryStore?.recordRecall?.(this.opts.agentId, obs.recalls);
824
876
  }
825
877
  if (obs.kind === "promotion_suggested" && obs.record_id) {
826
878
  this.opts.onPromotionSuggested?.({ recordId: obs.record_id, recallCount: obs.recall_count ?? 0 });
@@ -888,7 +940,7 @@ export class RuntimeRunner {
888
940
  agentId: this.opts.agentId,
889
941
  memoryScope: this.opts.memoryScope,
890
942
  skillContentMap: this.opts.skillContentMap,
891
- dreamStore: this.opts.dreamStore,
943
+ memoryStore: this.opts.memoryStore,
892
944
  knowledgeSource: this.opts.knowledgeSource,
893
945
  onToolSuspend: this.opts.onToolSuspend,
894
946
  onPermissionRequest: this.opts.onPermissionRequest,
@@ -1029,6 +1081,7 @@ export class RuntimeRunner {
1029
1081
  output: r.output,
1030
1082
  is_error: r.isError,
1031
1083
  token_count: r.tokenCount,
1084
+ content: { blocks: toolOutputBlocksToDurable(r.contentParts?.length ? r.contentParts : [{ type: "text", text: r.output }]) },
1032
1085
  })),
1033
1086
  });
1034
1087
  // Canonical provider-result reduction activates a successfully resolved `skill` call. The
@@ -1050,10 +1103,10 @@ export class RuntimeRunner {
1050
1103
  if (!name)
1051
1104
  continue;
1052
1105
  // With a lease configured, skip the Set optimization: an expired-then-reloaded skill
1053
- // must re-pin — only the kernel knows the lease state; its upsert dedupes anyway.
1106
+ // must re-pin — only the kernel knows the lease state; its put dedupes anyway.
1054
1107
  if (this.opts.skillLeaseTurns !== undefined || !this.knowledgePushedSkills.has(name)) {
1055
1108
  this.knowledgePushedSkills.add(name);
1056
- // K1: keyed `skill:<name>` — the kernel-side upsert dedupes across runner instances.
1109
+ // K1: keyed `skill:<name>` — the kernel-side put dedupes across runner instances.
1057
1110
  this.pushKnowledge({ role: "system", content: res.output }, undefined, { key: `skill:${name}` });
1058
1111
  }
1059
1112
  }
@@ -1071,7 +1124,6 @@ export class RuntimeRunner {
1071
1124
  this.lastEntropySample = {
1072
1125
  turn: obs.turn ?? 0,
1073
1126
  score: obs.score ?? 0,
1074
- scoreVersion: obs.score_version ?? 0,
1075
1127
  rho: obs.rho ?? 0,
1076
1128
  repeatPressure: obs.repeat_pressure ?? 0,
1077
1129
  failureRate: obs.failure_rate ?? 0,
@@ -1201,7 +1253,7 @@ export class RuntimeRunner {
1201
1253
  turnsUsed,
1202
1254
  totalTokens,
1203
1255
  }));
1204
- if (this.opts.dreamStore && this.opts.agentId) {
1256
+ if (this.opts.memoryStore && this.opts.agentId) {
1205
1257
  const newMsgs = runtime.drainNewMessages().map(m => ({
1206
1258
  role: m.role,
1207
1259
  content: m.content,
@@ -1218,9 +1270,9 @@ export class RuntimeRunner {
1218
1270
  createdAtMs: sessionStart,
1219
1271
  updatedAtMs: Date.now(),
1220
1272
  };
1221
- await this.opts.dreamStore.saveSession(completedSession);
1273
+ await this.opts.memoryStore.saveSession(completedSession);
1222
1274
  if (this.opts.memoryScope) {
1223
- const extracted = await extractSessionMemories(this.opts.dreamProvider ?? this.opts.provider, completedSession, this.opts.memoryScope, this.opts.dreamSystemPrompt);
1275
+ const extracted = await extractSessionMemories(this.opts.memoryProvider ?? this.opts.provider, completedSession, this.opts.memoryScope, this.opts.memorySystemPrompt);
1224
1276
  for (const memory of extracted)
1225
1277
  await this.writeMemory(memory, sessionId);
1226
1278
  }
@@ -1291,20 +1343,15 @@ export class RuntimeRunner {
1291
1343
  const winnerId = winner === "right" ? node.judge_match.right : node.judge_match.left;
1292
1344
  return withSignal(result, { tournamentWinner: winnerId });
1293
1345
  }
1294
- // A#2 v2 loop iteration: run the increment under the armed pacing trap (workflowNodeToSpec set
1346
+ // loop-control loop iteration: run the increment under the armed pacing trap (workflowNodeToSpec set
1295
1347
  // `loopRound`, and the iteration resumes the loop's stable session — transcript-as-carry).
1296
- // DW-3 one vocabulary: the kernel-adjudicated `pace` verb IS the continuation signal
1297
- // (stop → loopContinue=false); the legacy text-sniffed JSON blob survives only as the fallback
1298
- // when no pace decision arrives (stub orchestrators, harness children), where no signal still
1299
- // means "run to max_iters" (v1).
1348
+ // The kernel-adjudicated `pace` verb is the only continuation signal. Ending without a pace
1349
+ // decision completes the loop.
1300
1350
  if (node.loop_max_iters != null) {
1301
1351
  const iteration = Number(/-i(\d+)$/.exec(node.agent_id)?.[1] ?? "0");
1302
1352
  const result = await orchestrator.run(mkCtx(`${baseSpec.goal}\n\n${loopInstruction(node.loop_max_iters, iteration)}`));
1303
1353
  const pace = result.result.paceDecision;
1304
- if (pace)
1305
- return withSignal(result, { loopContinue: pace.action !== "stop" });
1306
- const cont = extractLoopContinue(textOf(result));
1307
- return cont === undefined ? result : withSignal(result, { loopContinue: cont });
1354
+ return withSignal(result, { loopContinue: pace?.action === "continue" });
1308
1355
  }
1309
1356
  // A#2 classify: run the classifier, then extract the chosen branch label (kernel prunes the rest).
1310
1357
  if (node.classify_labels && node.classify_labels.length) {
@@ -1384,10 +1431,9 @@ export class RuntimeRunner {
1384
1431
  const { kind: _govKind, ...governance } = governancePolicyToKernelEvent(governancePolicy);
1385
1432
  const config = { governance };
1386
1433
  if (this.opts.contextPolicy) {
1387
- config.context_policy = normalizeContextPolicyV1(contextPolicyV1(this.opts.contextPolicy));
1434
+ config.context_policy = normalizeContextPolicy(contextPolicy(this.opts.contextPolicy));
1388
1435
  }
1389
1436
  config.signal_policy = {
1390
- version: 1,
1391
1437
  queue_max: signalPolicy.queueMax,
1392
1438
  ...(signalPolicy.ttlMs !== undefined ? { ttl_ms: signalPolicy.ttlMs } : {}),
1393
1439
  ...(signalPolicy.deadlineEscalation !== undefined
@@ -1429,11 +1475,6 @@ export class RuntimeRunner {
1429
1475
  if (this.opts.criteriaGate !== undefined) {
1430
1476
  config.criteria_gate = this.opts.criteriaGate;
1431
1477
  }
1432
- // P1: fail-closed dispatch selector (absent ⇒ kernel default "exposed"). "registered" is the
1433
- // escape hatch back to permissive dispatch; the kernel rejects any other value.
1434
- if (this.opts.toolDispatchGate !== undefined) {
1435
- config.tool_dispatch_gate = this.opts.toolDispatchGate;
1436
- }
1437
1478
  // K2: knowledge budget ratio (absent ⇒ kernel default 0.25; 0 disables).
1438
1479
  if (this.opts.knowledgeBudgetRatio !== undefined) {
1439
1480
  config.knowledge_budget_ratio = this.opts.knowledgeBudgetRatio;
@@ -1744,7 +1785,7 @@ export class RuntimeRunner {
1744
1785
  * re-fired after each sprint renewal (renewal drops the old history INCLUDING earlier memory
1745
1786
  * hits). Errs-open throughout. */
1746
1787
  async prefetchMemoryIntoHistory(runtime, phase) {
1747
- if (!this.opts.dreamStore || !this.opts.agentId || !this.opts.memoryScope)
1788
+ if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
1748
1789
  return;
1749
1790
  // P10: recall is default-on (CC session-start recall) — with no hook configured,
1750
1791
  // the goal itself is the query. preQueryMemory stays as the targeting override.
@@ -1756,7 +1797,7 @@ export class RuntimeRunner {
1756
1797
  for (const q of queries ?? []) {
1757
1798
  if (!q.query.trim())
1758
1799
  continue;
1759
- const hits = await this.opts.dreamStore.search(this.opts.agentId, q);
1800
+ const hits = await this.opts.memoryStore.search(this.opts.agentId, q);
1760
1801
  for (const hit of hits) {
1761
1802
  lines.push(`[memory record_id=${hit.record.record_id} trust=${hit.record.provenance.trust} score=${hit.score.toFixed(3)}] ${hit.record.content}`);
1762
1803
  }
@@ -1771,12 +1812,12 @@ export class RuntimeRunner {
1771
1812
  catch { /* errs-open */ }
1772
1813
  }
1773
1814
  async archiveSemanticPageOut(archived, action) {
1774
- if (!this.opts.dreamStore || !this.opts.agentId || !this.opts.memoryScope)
1815
+ if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
1775
1816
  return;
1776
1817
  try {
1777
- const summary = this.opts.dreamSummarizer
1778
- ? await this.opts.dreamSummarizer.summarize(archived, { action })
1779
- : await summarizeForLongTermMemory(this.opts.dreamProvider ?? this.opts.provider, archived, this.opts.dreamSystemPrompt);
1818
+ const summary = this.opts.memorySummarizer
1819
+ ? await this.opts.memorySummarizer.summarize(archived, { action })
1820
+ : await summarizeForLongTermMemory(this.opts.memoryProvider ?? this.opts.provider, archived, this.opts.memorySystemPrompt);
1780
1821
  const now = Date.now();
1781
1822
  const name = `page-out-${now}`;
1782
1823
  await this.writeMemory({
@@ -1823,7 +1864,7 @@ function compressionAction(action) {
1823
1864
  }
1824
1865
  return undefined;
1825
1866
  }
1826
- async function replayMessages(events, maxBytes, archiveStore) {
1867
+ export async function replayMessages(events, maxBytes, archiveStore) {
1827
1868
  // Build upgraded-summary index: compressed_seq -> upgraded summary
1828
1869
  const upgradedSummaries = new Map();
1829
1870
  for (const { event: e } of events) {
@@ -1893,10 +1934,16 @@ async function replayMessages(events, maxBytes, archiveStore) {
1893
1934
  }
1894
1935
  else if (e.kind === "tool_completed") {
1895
1936
  for (const r of e.results) {
1937
+ const durable = decodeDurableToolResult({
1938
+ call_id: r.call_id,
1939
+ is_error: r.is_error ?? false,
1940
+ blocks: decodeDurableContent(r.content).blocks,
1941
+ });
1896
1942
  messages.push({
1897
1943
  role: "tool",
1898
- content: sanitizeReplayText(r.output, maxBytes),
1944
+ content: "",
1899
1945
  toolCalls: [],
1946
+ contentParts: [{ type: "tool_result", callId: durable.call_id, output: sanitizeReplayText(r.output, maxBytes), isError: durable.is_error, ...(durable.blocks.length ? { contentParts: durableBlocksToToolOutput(durable.blocks) } : {}) }],
1900
1947
  tokenCount: r.token_count,
1901
1948
  });
1902
1949
  }
@@ -1926,6 +1973,19 @@ export async function collectText(stream) {
1926
1973
  }
1927
1974
  return text;
1928
1975
  }
1976
+ async function withTimeout(promise, timeoutMs) {
1977
+ let timer;
1978
+ try {
1979
+ return await Promise.race([
1980
+ promise,
1981
+ new Promise((_, reject) => { timer = setTimeout(() => reject(new Error("provider token measurement timed out")), timeoutMs); }),
1982
+ ]);
1983
+ }
1984
+ finally {
1985
+ if (timer !== undefined)
1986
+ clearTimeout(timer);
1987
+ }
1988
+ }
1929
1989
  /** Parse `update_plan` meta-tool args into a task update (snake_case aliases accepted, mirroring
1930
1990
  * the node/python runners). Malformed payload → an empty update (a no-op `update_task`). */
1931
1991
  function parseUpdatePlanArgs(argsStr) {
@@ -2,6 +2,7 @@ import type { ProviderReplay, ToolCall, ToolErrorKind } from "../types.js";
2
2
  import type { MemoryRecall, MemoryScope } from "../memory/index.js";
3
3
  import type { KernelPrimitive } from "./kernel-event-log.js";
4
4
  import type { KernelJournal } from "./kernel-journal.js";
5
+ import type { RecordedPromptMeasurement } from "../providers/request-plan.js";
5
6
  export type RollbackReason = {
6
7
  kind: "fatal_tool_error";
7
8
  tool_name: string;
@@ -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;
@@ -6,7 +6,7 @@ export { REPLAY_CONTENT_MAX_BYTES as RECOVERY_CONTENT_MAX_BYTES } from "./replay
6
6
  * Normalize a persisted llm_completed event for recovery. Content is sanitized
7
7
  * and token_count backfilled, but the stored `provider_replay` envelope is
8
8
  * passed through verbatim — this layer is provider-neutral and never
9
- * synthesizes protocol-specific replay shapes. Legacy reconstruction is the
9
+ * synthesizes protocol-specific replay shapes. Canonical replay seeding is the
10
10
  * responsibility of the target provider's `seedProviderReplay`.
11
11
  */
12
12
  export declare function normalizeLlmCompleted(event: Extract<SessionEvent, {
@@ -7,7 +7,7 @@ function estimateTokenCount(text) {
7
7
  * Normalize a persisted llm_completed event for recovery. Content is sanitized
8
8
  * and token_count backfilled, but the stored `provider_replay` envelope is
9
9
  * passed through verbatim — this layer is provider-neutral and never
10
- * synthesizes protocol-specific replay shapes. Legacy reconstruction is the
10
+ * synthesizes protocol-specific replay shapes. Canonical replay seeding is the
11
11
  * responsibility of the target provider's `seedProviderReplay`.
12
12
  */
13
13
  export function normalizeLlmCompleted(event, maxBytes) {
@@ -0,0 +1,2 @@
1
+ /** Small synchronous SHA-256 for Worker/browser hosts (no node:crypto). */
2
+ export declare function sha256Hex(value: string): string;
@@ -0,0 +1,38 @@
1
+ /** Small synchronous SHA-256 for Worker/browser hosts (no node:crypto). */
2
+ export function sha256Hex(value) {
3
+ const input = new TextEncoder().encode(value);
4
+ const bitLength = input.length * 8;
5
+ const length = ((input.length + 9 + 63) >> 6) << 6;
6
+ const data = new Uint8Array(length);
7
+ data.set(input);
8
+ data[input.length] = 0x80;
9
+ new DataView(data.buffer).setUint32(length - 4, bitLength >>> 0, false);
10
+ const h = new Uint32Array([0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]);
11
+ const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
12
+ const ror = (x, n) => (x >>> n) | (x << (32 - n));
13
+ for (let offset = 0; offset < data.length; offset += 64) {
14
+ const w = new Uint32Array(64);
15
+ const view = new DataView(data.buffer, offset, 64);
16
+ for (let i = 0; i < 16; i++)
17
+ w[i] = view.getUint32(i * 4, false);
18
+ for (let i = 16; i < 64; i++) {
19
+ w[i] = (w[i - 16] + (ror(w[i - 15], 7) ^ ror(w[i - 15], 18) ^ (w[i - 15] >>> 3)) + w[i - 7] + (ror(w[i - 2], 17) ^ ror(w[i - 2], 19) ^ (w[i - 2] >>> 10))) >>> 0;
20
+ }
21
+ let [a, b, c, d, e, f, g, hh] = h;
22
+ for (let i = 0; i < 64; i++) {
23
+ const t1 = (hh + (ror(e, 6) ^ ror(e, 11) ^ ror(e, 25)) + ((e & f) ^ ((~e) & g)) + k[i] + w[i]) >>> 0;
24
+ const t2 = ((ror(a, 2) ^ ror(a, 13) ^ ror(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
25
+ hh = g;
26
+ g = f;
27
+ f = e;
28
+ e = (d + t1) >>> 0;
29
+ d = c;
30
+ c = b;
31
+ b = a;
32
+ a = (t1 + t2) >>> 0;
33
+ }
34
+ for (let i = 0; i < 8; i++)
35
+ h[i] = (h[i] + [a, b, c, d, e, f, g, hh][i]) >>> 0;
36
+ }
37
+ return `sha256:${Array.from(h, word => word.toString(16).padStart(8, "0")).join("")}`;
38
+ }
@@ -7,7 +7,7 @@ export interface SubAgentRunContext {
7
7
  spec: AgentRunSpec;
8
8
  manifest: AgentProcessChangedObservation;
9
9
  sessionLog: SessionLog;
10
- /** M5 v2.1: set when this child is a workflow node — propagated so a nested `start_workflow`
10
+ /** workflow-node: set when this child is a workflow node — propagated so a nested `start_workflow`
11
11
  * FLATTENS to the parent kernel rather than auto-pivoting into its own bootstrap. */
12
12
  isWorkflowNode?: boolean;
13
13
  /** W-N1 tool exposure. The kernel omits an EMPTY `permitted_capability_ids` on the wire, so a
@@ -39,7 +39,7 @@ function deriveMetaTools(permitted, opts) {
39
39
  const metaTools = new Set();
40
40
  if (permitted.has("skill") && opts.skillContentMap?.size)
41
41
  metaTools.add("skill");
42
- if (permitted.has("memory") && opts.dreamStore)
42
+ if (permitted.has("memory") && opts.memoryStore)
43
43
  metaTools.add("memory");
44
44
  if (permitted.has("knowledge") && opts.knowledgeSource)
45
45
  metaTools.add("knowledge");
@@ -53,7 +53,7 @@ function availableMetaTools(opts) {
53
53
  const metaTools = new Set();
54
54
  if (opts.skillContentMap?.size)
55
55
  metaTools.add("skill");
56
- if (opts.dreamStore)
56
+ if (opts.memoryStore)
57
57
  metaTools.add("memory");
58
58
  if (opts.knowledgeSource)
59
59
  metaTools.add("knowledge");
@@ -116,7 +116,7 @@ export class SubAgentOrchestrator {
116
116
  systemPrompt,
117
117
  sessionLog: ctx.sessionLog,
118
118
  skillContentMap: metaTools.has("skill") ? ctx.parentOpts.skillContentMap : undefined,
119
- dreamStore: metaTools.has("memory") ? ctx.parentOpts.dreamStore : undefined,
119
+ memoryStore: metaTools.has("memory") ? ctx.parentOpts.memoryStore : undefined,
120
120
  knowledgeSource: metaTools.has("knowledge") ? ctx.parentOpts.knowledgeSource : undefined,
121
121
  enablePlanTool: metaTools.has("update_plan") ? ctx.parentOpts.enablePlanTool : undefined,
122
122
  // The child runs under ITS OWN spec, never the parent's: the spread above would otherwise
@@ -45,7 +45,7 @@ export interface AgentRunSpec {
45
45
  * The ceiling bounds what this run may EVER expose; the baseline selects which of those are
46
46
  * advertised before any skill activates, so `exposed = meta ∪ ((baseline ∪ stableCore ∪
47
47
  * ⋃ activeSkills.allowed_tools) ∩ ceiling)`. That makes narrow→wide progressive disclosure
48
- * expressible. Absent ⇒ legacy behavior. `[]` is meaningful and distinct from absent: the minimal
48
+ * expressible. Absent and `[]` both mean the minimal
49
49
  * surface (meta-tools + stable-core only). Entries outside the ceiling silently intersect away.
50
50
  * Lowered from `RuntimeOptions.baselineToolIds`. */
51
51
  exposureBaseline?: string[];
@@ -84,7 +84,7 @@ export interface LoopResult {
84
84
  finalMessage?: Message;
85
85
  turnsUsed: number;
86
86
  totalTokensUsed: number;
87
- /** A#2 v2 loop stop signal: a loop iteration sets `false` to end the loop before `max_iters`.
87
+ /** loop-control loop stop signal: a loop iteration sets `false` to end the loop before `max_iters`.
88
88
  * `undefined` (every non-loop result) ⇒ no opinion → run to the cap. Sent only when set. */
89
89
  loopContinue?: boolean;
90
90
  /** A#2 classify routing: a classifier node reports the chosen branch label here; the kernel runs
@@ -94,7 +94,7 @@ export interface LoopResult {
94
94
  tournamentWinner?: string;
95
95
  /** ③ loop-agent pacing: the kernel-adjudicated after-round decision, surfaced by the orchestrator
96
96
  * from the child's done event. For a loop-node iteration this is the PRIMARY continuation
97
- * vocabulary (stop → loopContinue=false); the legacy text-sniffed signal is the fallback.
97
+ * vocabulary (stop → loopContinue=false).
98
98
  * SDK-internal — stripped by `subAgentResultToKernel`. */
99
99
  paceDecision?: import("../kernel-step.js").PaceDecision;
100
100
  }
@@ -149,6 +149,14 @@ export type WorkflowTaskSpec = {
149
149
  export type NodeTrust = "trusted" | "quarantined";
150
150
  export type WorkflowDependencyPolicy = "all_success" | "accept_partial" | "all_terminal" | "optional";
151
151
  export type WorkflowNodeStatus = "completed" | "completed_partial" | "failed" | "skipped_upstream_failed";
152
+ /** Host-observed, deterministic scheduling inputs for one workflow node. They never originate
153
+ * from model-authored workflow tools. */
154
+ export interface SchedulingFactors {
155
+ deadlineUrgency?: number;
156
+ processPriority?: number;
157
+ resourcePressure?: number;
158
+ budgetPressure?: number;
159
+ }
152
160
  export declare function workflowNodeStatusFromTermination(termination: TerminationReason | string): WorkflowNodeStatus;
153
161
  export interface WorkflowNodeSpec {
154
162
  task: WorkflowTaskSpec;
@@ -163,7 +171,7 @@ export interface WorkflowNodeSpec {
163
171
  /** G2: make this a deterministic reduce node — runs no LLM; the runner routes it to the registered
164
172
  * reducer of this name over its `dependsOn` nodes' outputs. */
165
173
  reducer?: string;
166
- /** A#2 v2: make this a *loop* node — re-run its agent up to `maxIters` times. An iteration may end
174
+ /** loop-control: make this a *loop* node — re-run its agent up to `maxIters` times. An iteration may end
167
175
  * the loop early by reporting `loopContinue: false` (the runner solicits this from the agent). */
168
176
  loop?: {
169
177
  maxIters: number;
@@ -187,6 +195,8 @@ export interface WorkflowNodeSpec {
187
195
  maxTurns?: number;
188
196
  /** O3: cap this node's child run at `maxWallMs` wall-clock milliseconds. */
189
197
  maxWallMs?: number;
198
+ /** Host-only scheduling facts used with the configured deterministic scheduler policy. */
199
+ schedulingFactors?: SchedulingFactors;
190
200
  /** Indices of nodes this node depends on. */
191
201
  dependsOn?: number[];
192
202
  /** How dependency terminal states gate this node. Defaults to `all_success`. */
@@ -251,7 +261,7 @@ export interface WorkflowSpawnInfo {
251
261
  left: string;
252
262
  right: string;
253
263
  };
254
- /** A#2 v2: present only for a *loop* iteration spawn — the loop's `max_iters`. Marks the spawn as a
264
+ /** loop-control: present only for a *loop* iteration spawn — the loop's `max_iters`. Marks the spawn as a
255
265
  * loop iteration so the runner solicits + reports a `loopContinue` stop signal. */
256
266
  loop_max_iters?: number;
257
267
  /** A#2: present only for a *classify* spawn — the branch labels the classifier must choose among.
@@ -286,9 +296,9 @@ export declare function workflowBudgetNote(budget: WorkflowBudget | undefined):
286
296
  export declare function workflowNodeSpecToKernel(n: WorkflowNodeSpec): Record<string, unknown>;
287
297
  export declare function workflowSpecToKernel(spec: WorkflowSpec): Record<string, unknown>;
288
298
  export declare const submitWorkflowNodesTool: ToolSchema;
289
- /** M5 v1 (flatten): the tool an agent calls to author a sub-workflow — a cohesive DAG of nodes
299
+ /** workflow authoring: the tool an agent calls to author a sub-workflow — a cohesive DAG of nodes
290
300
  * composed onto the running workflow. Lowers to the same append path as `submit_workflow_nodes`
291
- * (a `WorkflowSpec` is a node batch). v2 adds top-level bootstrap (the `LoadWorkflow` syscall). */
301
+ * (a `WorkflowSpec` is a node batch). Top-level bootstrap uses (the `LoadWorkflow` syscall). */
292
302
  export declare const startWorkflowTool: ToolSchema;
293
303
  /** Build a sub-agent run spec for a kernel-generated workflow node. */
294
304
  export declare function workflowNodeToSpec(node: WorkflowSpawnInfo, parentSessionId: string): AgentRunSpec;