@deepstrike/sdk 0.2.39 → 0.2.41

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 (102) hide show
  1. package/README.md +64 -34
  2. package/dist/collaboration/contract.d.ts +2 -2
  3. package/dist/collaboration/contract.js +2 -2
  4. package/dist/collaboration/handoff.d.ts +2 -14
  5. package/dist/collaboration/handoff.js +1 -17
  6. package/dist/collaboration/harness.d.ts +16 -47
  7. package/dist/collaboration/harness.js +57 -158
  8. package/dist/collaboration/index.d.ts +2 -2
  9. package/dist/collaboration/index.js +1 -2
  10. package/dist/collaboration/modes/creator-verifier.js +42 -6
  11. package/dist/collaboration/pool.d.ts +8 -0
  12. package/dist/collaboration/pool.js +56 -3
  13. package/dist/harness/harness.d.ts +97 -97
  14. package/dist/harness/harness.js +190 -144
  15. package/dist/harness/judge.d.ts +3 -2
  16. package/dist/harness/judge.js +7 -3
  17. package/dist/harness/public.d.ts +5 -3
  18. package/dist/harness/public.js +3 -2
  19. package/dist/index.d.ts +22 -7
  20. package/dist/index.js +8 -1
  21. package/dist/kernel.d.ts +12 -39
  22. package/dist/memory/agent.d.ts +8 -41
  23. package/dist/memory/agent.js +34 -117
  24. package/dist/memory/extraction.d.ts +4 -0
  25. package/dist/memory/extraction.js +79 -0
  26. package/dist/memory/in-memory-store.d.ts +28 -15
  27. package/dist/memory/in-memory-store.js +74 -25
  28. package/dist/memory/protocols.d.ts +56 -56
  29. package/dist/memory/protocols.js +1 -0
  30. package/dist/memory/public.d.ts +6 -1
  31. package/dist/memory/public.js +3 -0
  32. package/dist/memory/ranking.d.ts +32 -0
  33. package/dist/memory/ranking.js +77 -0
  34. package/dist/memory/retention.d.ts +17 -0
  35. package/dist/memory/retention.js +54 -0
  36. package/dist/os/public.d.ts +5 -4
  37. package/dist/os/public.js +2 -1
  38. package/dist/providers/base.d.ts +8 -0
  39. package/dist/providers/base.js +0 -0
  40. package/dist/providers/gemini.js +12 -0
  41. package/dist/providers/ollama.js +3 -1
  42. package/dist/providers/openai-responses.js +9 -2
  43. package/dist/providers/profiles.d.ts +5 -3
  44. package/dist/providers/profiles.js +3 -3
  45. package/dist/runtime/context-policy.d.ts +35 -0
  46. package/dist/runtime/context-policy.js +66 -0
  47. package/dist/runtime/eval.d.ts +6 -2
  48. package/dist/runtime/eval.js +2 -2
  49. package/dist/runtime/event-stream.d.ts +9 -0
  50. package/dist/runtime/event-stream.js +25 -11
  51. package/dist/runtime/execution-plane.d.ts +5 -1
  52. package/dist/runtime/execution-plane.js +9 -3
  53. package/dist/runtime/facade.js +2 -1
  54. package/dist/runtime/kernel-event-log.d.ts +0 -2
  55. package/dist/runtime/kernel-event-log.js +61 -13
  56. package/dist/runtime/kernel-primitives-dashboard.js +1 -1
  57. package/dist/runtime/kernel-rebuild.d.ts +13 -0
  58. package/dist/runtime/kernel-rebuild.js +75 -0
  59. package/dist/runtime/kernel-step.d.ts +157 -8
  60. package/dist/runtime/kernel-step.js +220 -7
  61. package/dist/runtime/kernel-transaction-log.d.ts +61 -0
  62. package/dist/runtime/kernel-transaction-log.js +149 -0
  63. package/dist/runtime/large-result-spool.d.ts +3 -1
  64. package/dist/runtime/large-result-spool.js +24 -5
  65. package/dist/runtime/loop-driver.d.ts +1 -1
  66. package/dist/runtime/loop-driver.js +2 -7
  67. package/dist/runtime/mcp-proxy-plane.d.ts +1 -0
  68. package/dist/runtime/mcp-proxy-plane.js +23 -6
  69. package/dist/runtime/os-profile.d.ts +9 -10
  70. package/dist/runtime/os-profile.js +14 -10
  71. package/dist/runtime/os-snapshot.d.ts +19 -0
  72. package/dist/runtime/os-snapshot.js +33 -3
  73. package/dist/runtime/process-sandbox-plane.js +16 -11
  74. package/dist/runtime/reaction-checkpoint.d.ts +51 -0
  75. package/dist/runtime/reaction-checkpoint.js +83 -0
  76. package/dist/runtime/reactive-session.d.ts +9 -3
  77. package/dist/runtime/reactive-session.js +44 -14
  78. package/dist/runtime/reliability.d.ts +48 -0
  79. package/dist/runtime/reliability.js +86 -0
  80. package/dist/runtime/remote-vpc-plane.js +4 -3
  81. package/dist/runtime/run-group.d.ts +38 -35
  82. package/dist/runtime/run-group.js +97 -54
  83. package/dist/runtime/runner.d.ts +117 -78
  84. package/dist/runtime/runner.js +1516 -1197
  85. package/dist/runtime/session-log.d.ts +71 -12
  86. package/dist/runtime/session-log.js +192 -32
  87. package/dist/runtime/session-repair.d.ts +11 -7
  88. package/dist/runtime/session-repair.js +11 -8
  89. package/dist/runtime/sub-agent-orchestrator.d.ts +6 -2
  90. package/dist/runtime/sub-agent-orchestrator.js +45 -18
  91. package/dist/signals/gateway.d.ts +23 -10
  92. package/dist/signals/gateway.js +81 -17
  93. package/dist/signals/scheduled.js +0 -1
  94. package/dist/signals/types.d.ts +21 -13
  95. package/dist/skills/loader.js +12 -2
  96. package/dist/tools/index.d.ts +2 -0
  97. package/dist/types/agent.d.ts +40 -1
  98. package/dist/types/agent.js +61 -1
  99. package/dist/types.d.ts +6 -1
  100. package/dist/workflow/public.d.ts +2 -3
  101. package/dist/workflow/public.js +0 -1
  102. package/package.json +2 -2
@@ -1,11 +1,27 @@
1
+ /**
2
+ * L1 (RunGroup) — a governance domain shared by N peer agent sessions of one logical run.
3
+ *
4
+ * The kernel (execution vehicle) is ephemeral and torn down between stateless turns, so the
5
+ * cumulative budget + membership that must span the whole group live outside any vehicle: in a
6
+ * `GroupBudgetStore`. Every store atomically reserves capacity and settles actual consumption.
7
+ * Per spec §2.5, only *cumulative* budget is shared this way; instantaneous concurrency stays
8
+ * vehicle-scoped.
9
+ *
10
+ * `InMemoryGroupBudgetStore` provides process-local atomic reservations for one replica / tests.
11
+ */
12
+ import { randomUUID } from "node:crypto";
1
13
  /** Process-local default store. One ledger + member set per group id. */
2
14
  export class InMemoryGroupBudgetStore {
3
15
  ledgers = new Map();
4
16
  memberships = new Map();
17
+ reservations = new Map();
5
18
  read(groupId) {
6
- return this.ledgers.get(groupId) ?? { tokensSpent: 0, subagentsSpawned: 0, roundsCompleted: 0 };
19
+ const ledger = this.ledgers.get(groupId);
20
+ return ledger
21
+ ? { ...ledger }
22
+ : { tokensSpent: 0, subagentsSpawned: 0, roundsCompleted: 0 };
7
23
  }
8
- charge(groupId, delta) {
24
+ applyCharge(groupId, delta) {
9
25
  const cur = this.read(groupId);
10
26
  this.ledgers.set(groupId, {
11
27
  tokensSpent: cur.tokensSpent + Math.max(0, delta.tokens ?? 0),
@@ -16,8 +32,8 @@ export class InMemoryGroupBudgetStore {
16
32
  join(groupId, member) {
17
33
  if (!this.memberships.has(groupId))
18
34
  this.memberships.set(groupId, new Map());
19
- // First join wins (idempotent by sessionId) the same contract as SessionLogGroupBudgetStore.
20
- // A persona registered as "peer" then re-joining through its own run() as "vehicle" must not
35
+ // First join wins (idempotent by sessionId). A persona registered as "peer" then re-joining
36
+ // through its own run() as "vehicle" must not
21
37
  // lose its peer tag (W-N5), and the two stores must agree on which record survives.
22
38
  const members = this.memberships.get(groupId);
23
39
  if (!members.has(member.sessionId))
@@ -26,61 +42,88 @@ export class InMemoryGroupBudgetStore {
26
42
  members(groupId) {
27
43
  return [...(this.memberships.get(groupId)?.values() ?? [])];
28
44
  }
29
- }
30
- /**
31
- * Persists the group ledger + membership to a `SessionLog`, keyed by a group-anchor session whose id
32
- * is the group id. Budget/membership rebuild by folding `group_budget_charged` / `group_member_joined`
33
- * events on read (spec §2.4). Durable + replica-spanning when the underlying `SessionLog` is.
34
- */
35
- export class SessionLogGroupBudgetStore {
36
- log;
37
- constructor(log) {
38
- this.log = log;
45
+ reserve(groupId, request) {
46
+ const settled = this.read(groupId);
47
+ const held = [...(this.reservations.get(groupId)?.values() ?? [])].reduce((sum, reservation) => ({
48
+ tokensSpent: sum.tokensSpent + (reservation.granted.tokens ?? 0),
49
+ subagentsSpawned: sum.subagentsSpawned + (reservation.granted.subagents ?? 0),
50
+ roundsCompleted: (sum.roundsCompleted ?? 0) + (reservation.granted.rounds ?? 0),
51
+ }), { tokensSpent: 0, subagentsSpawned: 0, roundsCompleted: 0 });
52
+ const ledger = {
53
+ tokensSpent: settled.tokensSpent + held.tokensSpent,
54
+ subagentsSpawned: settled.subagentsSpawned + held.subagentsSpawned,
55
+ roundsCompleted: (settled.roundsCompleted ?? 0) + (held.roundsCompleted ?? 0),
56
+ };
57
+ const grant = (requested = 0, limit, used) => Math.max(0, Math.min(Math.max(0, requested), limit === undefined ? requested : limit - used));
58
+ const reservation = {
59
+ id: randomUUID(),
60
+ groupId,
61
+ memberId: request.memberId,
62
+ granted: {
63
+ ...(request.requested.tokens !== undefined
64
+ ? { tokens: grant(request.requested.tokens, request.limits.tokens, ledger.tokensSpent) }
65
+ : {}),
66
+ ...(request.requested.subagents !== undefined
67
+ ? { subagents: grant(request.requested.subagents, request.limits.subagents, ledger.subagentsSpawned) }
68
+ : {}),
69
+ ...(request.requested.rounds !== undefined
70
+ ? { rounds: grant(request.requested.rounds, request.limits.rounds, ledger.roundsCompleted ?? 0) }
71
+ : {}),
72
+ },
73
+ };
74
+ if (!this.reservations.has(groupId))
75
+ this.reservations.set(groupId, new Map());
76
+ this.reservations.get(groupId).set(reservation.id, reservation);
77
+ return reservation;
39
78
  }
40
- async read(groupId) {
41
- let tokensSpent = 0;
42
- let subagentsSpawned = 0;
43
- let roundsCompleted = 0;
44
- for (const { event } of await this.log.read(groupId)) {
45
- if (event.kind === "group_budget_charged") {
46
- roundsCompleted += event.rounds ?? 0;
47
- tokensSpent += event.tokens;
48
- subagentsSpawned += event.subagents;
49
- }
50
- }
51
- return { tokensSpent, subagentsSpawned, roundsCompleted };
79
+ settle(groupId, reservationId, actual) {
80
+ const reservations = this.reservations.get(groupId);
81
+ if (!reservations?.delete(reservationId))
82
+ return;
83
+ if (reservations.size === 0)
84
+ this.reservations.delete(groupId);
85
+ this.applyCharge(groupId, actual);
52
86
  }
53
- async charge(groupId, delta) {
54
- await this.log.append(groupId, {
55
- kind: "group_budget_charged",
56
- ...(delta.rounds !== undefined ? { rounds: delta.rounds } : {}),
57
- tokens: Math.max(0, delta.tokens ?? 0),
58
- subagents: Math.max(0, delta.subagents ?? 0),
87
+ release(groupId, reservationId) {
88
+ const reservations = this.reservations.get(groupId);
89
+ if (!reservations?.delete(reservationId))
90
+ return;
91
+ if (reservations.size === 0)
92
+ this.reservations.delete(groupId);
93
+ }
94
+ }
95
+ /** One member's reservation lifecycle. */
96
+ export class GroupBudgetScope {
97
+ group;
98
+ granted;
99
+ reservationId;
100
+ closed = false;
101
+ constructor(group, granted, reservationId) {
102
+ this.group = group;
103
+ this.granted = granted;
104
+ this.reservationId = reservationId;
105
+ }
106
+ static async open(group, member, request) {
107
+ await group.budgetStore.join(group.id, member);
108
+ const reservation = await group.budgetStore.reserve(group.id, {
109
+ ...request,
110
+ memberId: member.sessionId,
59
111
  });
112
+ return new GroupBudgetScope(group, reservation.granted, reservation.id);
60
113
  }
61
- async join(groupId, member) {
62
- // Idempotent: don't grow the log with duplicate joins for the same session.
63
- const existing = await this.members(groupId);
64
- if (existing.some(m => m.sessionId === member.sessionId))
114
+ async settle(actual) {
115
+ if (this.closed)
65
116
  return;
66
- await this.log.append(groupId, {
67
- kind: "group_member_joined",
68
- session_id: member.sessionId,
69
- ...(member.role ? { role: member.role } : {}),
70
- ...(member.kind ? { member_kind: member.kind } : {}),
71
- });
117
+ await this.group.budgetStore.settle(this.group.id, this.reservationId, actual);
118
+ this.closed = true;
119
+ }
120
+ get isClosed() {
121
+ return this.closed;
72
122
  }
73
- async members(groupId) {
74
- const seen = new Map();
75
- for (const { event } of await this.log.read(groupId)) {
76
- if (event.kind === "group_member_joined") {
77
- seen.set(event.session_id, {
78
- sessionId: event.session_id,
79
- role: event.role,
80
- ...(event.member_kind ? { kind: event.member_kind } : {}),
81
- });
82
- }
83
- }
84
- return [...seen.values()];
123
+ async release() {
124
+ if (this.closed)
125
+ return;
126
+ await this.group.budgetStore.release(this.group.id, this.reservationId);
127
+ this.closed = true;
85
128
  }
86
129
  }
@@ -1,21 +1,34 @@
1
1
  import type { LLMProvider, Message, ContentPart, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse, AsyncSummarizer, DreamSummarizer, EntropySample, EntropyWatchOptions } from "../types.js";
2
- import type { DreamStore, MemoryEntry, MemoryQuery, MemoryWriteRequest } from "../memory/protocols.js";
2
+ import type { DreamStore, MemoryRecord, MemoryRecall, MemoryScope, MemoryQuery } from "../memory/protocols.js";
3
3
  import type { KnowledgeSource } from "../knowledge/source.js";
4
- import type { SignalSource, RuntimeSignalUrgency } from "../signals/types.js";
4
+ import type { RuntimeSignalUrgency, SignalSource } from "../signals/types.js";
5
5
  import type { SessionLog, SessionEvent } from "./session-log.js";
6
6
  import type { ArchiveStore } from "./archive.js";
7
7
  import type { ExecutionPlane } from "./execution-plane.js";
8
8
  import type { RunGroup } from "./run-group.js";
9
9
  import { type MemoryPolicy, type ResourceQuota } from "../kernel.js";
10
- import { type RecoveredNodeCompletion } from "./session-repair.js";
11
- import type { AgentRunSpec, MilestoneCheckResult, MilestoneContract, MilestonePolicy, WorkflowSpec } from "../types/agent.js";
10
+ import { type RecoveredNodeOutcome } from "./session-repair.js";
11
+ import type { AgentRunSpec, MilestoneCheckResult, MilestoneContract, MilestonePolicy, WorkflowSpec, WorkflowOutcome } from "../types/agent.js";
12
12
  import { type SubAgentOrchestrator } from "./sub-agent-orchestrator.js";
13
13
  import { type ReducerRegistry } from "./reducers.js";
14
14
  import { type GovernancePolicy } from "../governance.js";
15
- import { type NativeOsProfile, type OsProfileId } from "./os-profile.js";
15
+ import { type NativeOsProfile, type OsProfileId, type SignalPolicy } from "./os-profile.js";
16
16
  import { LargeResultSpool } from "./large-result-spool.js";
17
- export interface SchedulerBudget {
18
- maxWallMs?: number;
17
+ import type { BackgroundTaskErrorHandler } from "./reliability.js";
18
+ import { type ContextPolicyOverridesV1 } from "./context-policy.js";
19
+ export interface SchedulerPolicy {
20
+ version: 1;
21
+ criticalPathWeight: number;
22
+ fanoutWeight: number;
23
+ ageWeight: number;
24
+ tokenCostWeight: number;
25
+ }
26
+ export declare function schedulerPolicyToKernel(policy: SchedulerPolicy): Record<string, number>;
27
+ /** Host-counted provider envelope and response reserves deducted from the model context window. */
28
+ export interface PromptBudget {
29
+ promptOverheadTokens: number;
30
+ outputReserveTokens: number;
31
+ safetyMarginTokens: number;
19
32
  }
20
33
  /** P0-C tool-gating telemetry: per-LLM-turn metrics, emitted via `RuntimeOptions.onTurnMetrics`.
21
34
  * Pure observation — no behavior change. Feeds the go/no-go analysis for epoch skill gating (P1-B):
@@ -63,6 +76,30 @@ export interface ToolResultHookDecision {
63
76
  replaceOutput?: string;
64
77
  note?: string;
65
78
  }
79
+ /** Bounded kernel reliability policy. Omitted fields retain kernel defaults. */
80
+ export interface KernelReliabilityOptions {
81
+ /** Deduplicated input-event replay window, 1..65536. */
82
+ eventReplayCapacity?: number;
83
+ /** Completed effect-result replay window, 1..65536. */
84
+ completedEffectReplayCapacity?: number;
85
+ /** Provider overflow recovery retries, 0..16. */
86
+ providerRecoveryAttempts?: number;
87
+ /** Truncated-output recovery retries, 0..16. */
88
+ outputRecoveryAttempts?: number;
89
+ /** Host durability-effect retries, 0..16. */
90
+ hostEffectRetryAttempts?: number;
91
+ /** Tool-result spool threshold in bytes; must be positive. */
92
+ spoolThresholdBytes?: number;
93
+ /** Inline spool preview bytes; positive and no larger than the threshold. */
94
+ spoolPreviewBytes?: number;
95
+ /** Max accepted ABI transactions retained for a portable KernelSnapshot rebuild. */
96
+ snapshotInputLimit?: number;
97
+ /** Max canonical JSON bytes accepted for one kernel input, 256..64MiB. */
98
+ maxInputBytes?: number;
99
+ /** Max canonical JSON bytes retained by the snapshot journal, 256..1GiB. */
100
+ snapshotJournalBytesLimit?: number;
101
+ }
102
+ export type OperationCancellationReason = "user" | "deadline" | "lease_lost" | "host_shutdown";
66
103
  export interface RuntimeOptions {
67
104
  provider: LLMProvider;
68
105
  /** M4/G5: cumulative token cap for this run (the kernel's `max_total_tokens`). A workflow node's
@@ -80,13 +117,17 @@ export interface RuntimeOptions {
80
117
  worktreeManager?: import("./worktree-plane.js").WorktreeManager;
81
118
  sessionLog: SessionLog;
82
119
  executionPlane: ExecutionPlane;
120
+ /** Receives failures from run-owned best-effort tasks after their semantic owner has committed. */
121
+ onBackgroundTaskError?: BackgroundTaskErrorHandler;
83
122
  maxTokens: number;
84
123
  maxTurns?: number;
85
124
  timeoutMs?: number;
86
125
  agentId?: string;
126
+ /** Required by host-generated memory queries and page-out writes. */
127
+ memoryScope?: MemoryScope;
87
128
  /** I4: optional run-start memory pre-fetch hook. The runner calls this ONCE per run, before the
88
- * first LLM turn, with the request's goal and (optional) run-spec. Each returned query string
89
- * becomes a `dreamStore.search(agentId, q, 5)` and the resulting hits land in decaying
129
+ * first LLM turn, with the request's goal and (optional) run-spec. Each returned scoped query
130
+ * becomes a `dreamStore.search(agentId, query)` and the resulting hits land in decaying
90
131
  * HISTORY as an ordinary user turn before turn 1 (single-use retrieval content — never a
91
132
  * permanent knowledge pin; `initialMemory` is the curated CLAUDE.md-analog seed). Returning
92
133
  * `undefined` / empty array is a no-op. Requires `dreamStore` + `agentId`; missing either ⇒
@@ -99,11 +140,17 @@ export interface RuntimeOptions {
99
140
  * renewal (renewal drops the old history INCLUDING earlier memory hits, so the new sprint
100
141
  * gets a fresh recall pass). Hooks that ignore it keep the pre-K4 behavior. */
101
142
  phase?: "initial" | "renewal";
102
- }) => Promise<string[] | undefined> | string[] | undefined;
143
+ }) => Promise<MemoryQuery[] | undefined> | MemoryQuery[] | undefined;
103
144
  systemPrompt?: string;
104
145
  initialMemory?: string[];
105
146
  skillDir?: string;
106
147
  dreamStore?: DreamStore;
148
+ /** M4: advisory callback when a recalled record crosses the promotion threshold. The host/model
149
+ * decides whether to pin the record or promote its content into knowledge. */
150
+ onPromotionSuggested?: (info: {
151
+ recordId: string;
152
+ recallCount: number;
153
+ }) => void;
107
154
  knowledgeSource?: KnowledgeSource;
108
155
  signalSource?: SignalSource;
109
156
  extensions?: Record<string, unknown>;
@@ -115,27 +162,24 @@ export interface RuntimeOptions {
115
162
  * AskUser calls surface as `tool_gated` and run through `onPermissionRequest`.
116
163
  */
117
164
  governancePolicy?: GovernancePolicy;
118
- /**
119
- * Enable in-kernel signal routing (`set_attention_policy`). When set, inbound
120
- * signals are dispatched through the kernel attention policy (dedup + disposition
121
- * + queue) and surface as `signal_disposed` observations, instead of the legacy
122
- * SDK-side router. `maxQueueSize` defaults to 64.
123
- */
124
- attentionPolicy?: {
125
- maxQueueSize?: number;
126
- };
127
- /**
128
- * Optional scheduler budget overrides. `maxWallMs` is the wall-clock run budget
129
- * in milliseconds; when set, the kernel terminates the run when exceeded.
130
- * Other axes (maxTurns, maxTokens) are set via RuntimeOptions directly.
131
- */
132
- schedulerBudget?: SchedulerBudget;
165
+ /** Version-1 in-kernel signal admission, queue, and expiry policy. */
166
+ signalPolicy?: SignalPolicy;
167
+ /** Provider-envelope overhead plus output and safety reserves journaled before start. */
168
+ promptBudget?: PromptBudget;
169
+ /** Stable replayable context behavior; SDK ratios are normalized to integer ppm on the ABI wire. */
170
+ contextPolicy?: ContextPolicyOverridesV1;
171
+ /** Versioned deterministic DAG scheduling policy installed atomically through ConfigureRun. */
172
+ schedulerPolicy?: SchedulerPolicy;
133
173
  /**
134
174
  * Optional declarative resource quotas (`set_resource_quota`). Bounds spawn concurrency /
135
175
  * nesting depth and memory-write rate at the kernel's single syscall trap. When unset, spawn
136
176
  * and memory-write syscalls are admitted unconditionally (pre-M2 behavior).
137
177
  */
138
178
  resourceQuota?: ResourceQuota;
179
+ /** Host-selectable bounded replay/recovery/durability policy. */
180
+ kernelReliability?: KernelReliabilityOptions;
181
+ /** Attempts allowed for a workflow node to satisfy its output schema, 1..16. Default: 2. */
182
+ workflowSchemaValidationAttempts?: number;
139
183
  /**
140
184
  * O6: the in-kernel repeat fuse — the hard rungs above the soft no-progress STOP. When the model
141
185
  * re-issues the IDENTICAL tool call (same name AND args) `denyAfter` turns in a row, the kernel
@@ -181,13 +225,15 @@ export interface RuntimeOptions {
181
225
  * executes. Return `{ block: true, reason }` to veto — the call never runs and the reason is fed
182
226
  * back to the model as a denied tool result. This is the seam for STATEFUL host policy (count
183
227
  * repeats, budget writes per resource, project-specific rules); keep static allow/deny in
184
- * `governancePolicy`. Errs-open: a throwing hook never blocks the run.
228
+ * `governancePolicy`. A throwing decision hook fails closed by default.
185
229
  */
186
230
  onToolCall?: (call: {
187
231
  callId: string;
188
232
  name: string;
189
233
  arguments: string;
190
234
  }) => Promise<ToolCallHookDecision | undefined | void> | ToolCallHookDecision | undefined | void;
235
+ /** Failure policy for `onToolCall`. Default `closed`; set `open` only for advisory hooks. */
236
+ onToolCallFailure?: "closed" | "open";
191
237
  /**
192
238
  * O5 (the PostToolUse-hook analog): called for each executed tool result before it reaches the
193
239
  * kernel. Return `{ replaceOutput }` to swap the result the model sees (redact / annotate), and/or
@@ -203,9 +249,9 @@ export interface RuntimeOptions {
203
249
  }) => Promise<ToolResultHookDecision | undefined | void> | ToolResultHookDecision | undefined | void;
204
250
  /**
205
251
  * L1 (RunGroup): bind this runner to a governance domain shared by N peer sessions of one logical
206
- * run. Members pass the same `id` + `budgetStore`; the kernel's run-level token cap is then enforced
207
- * against the group's cumulative spend (seeded at boot, charged at run end) rather than per-vehicle.
208
- * Unset ⇒ N=1, pre-L1 per-run budget (byte-identical). Only cumulative budget is shared; instantaneous
252
+ * run. Members pass the same `id` + `budgetStore`; reservable stores enforce the kernel's run-level
253
+ * cap against settled + in-flight usage. Stores must implement atomic reserve/settle/release.
254
+ * Unset ⇒ N=1. Only cumulative budget is shared; instantaneous
209
255
  * concurrency stays vehicle-scoped (spec §2.5).
210
256
  */
211
257
  runGroup?: RunGroup;
@@ -261,7 +307,7 @@ export interface RuntimeOptions {
261
307
  * nested `start_workflow` flattens rather than recursing. */
262
308
  isWorkflowNode?: boolean;
263
309
  /**
264
- * When set, sub-agents run through a HarnessLoop with this config.
310
+ * When set, sub-agents run through AttemptLoop with a RuntimeAttemptBody and LLM judge.
265
311
  * The eval provider evaluates the sub-agent's output against the criteria
266
312
  * from the AgentRunSpec, retrying up to maxAttempts times.
267
313
  */
@@ -294,10 +340,11 @@ export interface RuntimeOptions {
294
340
  export declare class RuntimeRunner {
295
341
  private readonly opts;
296
342
  private interrupted;
297
- /** #2-B-ii: aborts the in-flight provider stream when the run is interrupted/preempted. Recreated
298
- * per `execute`; `interrupt()` fires it so a Critical `InterruptNow` cancels the live LLM call. */
343
+ private cancellationReason;
344
+ /** Aborts host-owned provider I/O before `cancel_operation` commits the kernel terminal fact. */
299
345
  private abortController;
300
346
  private activeKernel;
347
+ private activeGroupBudgetScope;
301
348
  private pendingObservations;
302
349
  private currentSessionId;
303
350
  /** O2 (system-reminder channel): host-pushed notes awaiting the next turn-boundary drain. */
@@ -307,29 +354,38 @@ export declare class RuntimeRunner {
307
354
  * an already-active skill (loading is idempotent; the knowledge push should be too). */
308
355
  private knowledgePushedSkills;
309
356
  private nextArchiveStart;
357
+ private pendingPageOutArchives;
358
+ private activePageOutArchive;
310
359
  /** K4: the active run's goal, kept for the renewal-boundary memory re-query. */
311
360
  private currentGoal;
312
- /** Full tool outputs keyed by call_id until Layer-1 spool observations are logged. */
313
- private pendingSpoolOutputs;
314
361
  /** M5 v2.1: sub-workflow specs a top-level agent authored via `start_workflow`, awaiting auto-drive
315
362
  * at the next safe point (after the tool turn resolves, kernel back in Reason — not suspended). */
316
363
  private pendingAuthoredWorkflows;
364
+ private workflowContinuation;
317
365
  private dashboard;
318
366
  /** Most recent kernel entropy sample of the active/last run (see `latestEntropy`). */
319
367
  private lastEntropySample;
320
368
  constructor(opts: RuntimeOptions);
321
369
  /** Host configuration (for coordinator / sub-agent spawn). */
322
370
  get hostOptions(): RuntimeOptions;
323
- writeMemory(memory: MemoryWriteRequest, opts?: {
371
+ private durableSessionId;
372
+ private commitKernelApply;
373
+ private commitKernelMaybeAction;
374
+ private commitKernelAction;
375
+ private persistMemoryToStore;
376
+ private retrieveMemoryFromStore;
377
+ writeMemory(memory: MemoryRecord, opts?: {
324
378
  sessionId?: string;
325
379
  agentId?: string;
326
380
  }): Promise<void>;
327
381
  queryMemory(query: MemoryQuery, opts?: {
328
382
  sessionId?: string;
329
383
  agentId?: string;
330
- }): Promise<MemoryEntry[]>;
384
+ }): Promise<MemoryRecall[]>;
331
385
  private logMemoryRetrievalResult;
332
386
  private createSyscallRuntime;
387
+ private groupBudgetRequest;
388
+ private settleGroupBudget;
333
389
  /**
334
390
  * Lower the declarative governance / attention / scheduler-budget / resource-quota policies into a
335
391
  * freshly-created kernel. Shared by `execute()` (full agent run) and `bootstrapWorkflowKernel()`
@@ -340,13 +396,13 @@ export declare class RuntimeRunner {
340
396
  private applyKernelPolicies;
341
397
  private appendMemorySyscallObservations;
342
398
  /** Mount a tool capability on the currently-running kernel runtime. No-op if not running. */
343
- mountTool(schema: ToolSchema): void;
399
+ mountTool(schema: ToolSchema): Promise<void>;
344
400
  /** Mount a skill capability on the currently-running kernel runtime. No-op if not running. */
345
- mountSkill(name: string, description: string): void;
401
+ mountSkill(name: string, description: string): Promise<void>;
346
402
  /** Mount a generic marker capability (e.g. MCP server, agent) on the active run. No-op if not running. */
347
- mountMarker(kind: string, id: string, description: string): void;
403
+ mountMarker(kind: string, id: string, description: string): Promise<void>;
348
404
  /** Unmount a capability by kind + id from the active run. No-op if not running. */
349
- unmountCapability(kind: string, id: string): void;
405
+ unmountCapability(kind: string, id: string): Promise<void>;
350
406
  /** Push content into the Knowledge slot (memory retrievals, skill definitions, artifacts).
351
407
  * K1: `opts.key` gives the entry identity — a same-key push upserts (applied at the next
352
408
  * compaction/renewal boundary, where the cached system[1] block is rewritten anyway) instead
@@ -354,15 +410,15 @@ export declare class RuntimeRunner {
354
410
  pushKnowledge(message: Message, tokens?: number, opts?: {
355
411
  key?: string;
356
412
  pinned?: boolean;
357
- }): void;
413
+ }): Promise<void>;
358
414
  /** K1: mark a keyed knowledge entry for removal at the next compaction/renewal boundary.
359
415
  * Errs-open: an unknown key is a kernel-side no-op. */
360
- removeKnowledge(key: string): void;
416
+ removeKnowledge(key: string): Promise<void>;
361
417
  /** K3: host-driven skill deactivation (there is deliberately no model-facing unload — it
362
418
  * invites thrash). The toolset re-widens at the next provider call; the skill's knowledge pin
363
419
  * drops at the next compaction/renewal boundary. A later `skill(name)` call re-activates and
364
420
  * re-pins fresh content. Errs-open: not-active is a kernel-side no-op. */
365
- deactivateSkill(name: string): void;
421
+ deactivateSkill(name: string): Promise<void>;
366
422
  /**
367
423
  * Spawn an isolated sub-agent via the kernel, run it on the host, and feed the result back.
368
424
  * Requires an active parent run (`run()` / `wake()` in progress or paused at milestone).
@@ -388,32 +444,23 @@ export declare class RuntimeRunner {
388
444
  * W0-ABI: run a declarative workflow DAG. The kernel owns the DAG and gates every node spawn
389
445
  * through the syscall trap; this driver runs each kernel-emitted batch of nodes in parallel,
390
446
  * feeds their results back, and loops until the kernel reports the workflow complete.
391
- * Returns the completed / failed node agent-ids.
447
+ * Returns one typed terminal outcome for every node in the DAG.
392
448
  */
393
449
  runWorkflow(spec: WorkflowSpec, opts?: {
394
- resumedCompleted?: string[];
395
- /** W-1: recovered completions WITH control signals (classify branch / loop stop) — lowered to
396
- * the kernel's `resumed_results` so control flow replays faithfully. Supersedes
397
- * `resumedCompleted` for ids present in both. */
398
- resumedResults?: RecoveredNodeCompletion[];
450
+ /** Typed recovered terminal outcomes, including control signals and output. */
451
+ resumedOutcomes?: RecoveredNodeOutcome[];
399
452
  resumedSubmissions?: Record<string, unknown>[][];
400
453
  /** R3-1: original base index per submission batch (parallel to resumedSubmissions). */
401
454
  resumedSubmissionBases?: number[];
402
- /** W-1: recovered node outputs (agent id → output text) to pre-seed the driver's outputs map. */
403
- resumedOutputs?: Map<string, string>;
404
455
  /** Standalone session id when bootstrapping (no active parent run). Defaults to a fresh uuid. */
405
456
  sessionId?: string;
406
- }): Promise<{
407
- completed: string[];
408
- failed: string[];
409
- outputs: Record<string, string>;
410
- }>;
457
+ }): Promise<WorkflowOutcome>;
411
458
  /**
412
459
  * Bootstrap a standalone kernel for a host-driven workflow with NO active parent run — the path a
413
460
  * stateless request handler takes when it calls `runWorkflow(spec)` directly. Mirrors `execute()`'s
414
461
  * pre-run kernel setup (governance / attention / quota via `applyKernelPolicies`, then `start_run`)
415
- * and records a `run_started` event so the standalone run is resumable from the session log. Sets
416
- * `activeKernel` / `currentSessionId`; `runWorkflow` is responsible for tearing them down.
462
+ * after `runWorkflow` has durably recorded `run_started`. Sets `activeKernel` / `currentSessionId`;
463
+ * `runWorkflow` is responsible for tearing them down.
417
464
  */
418
465
  private bootstrapWorkflowKernel;
419
466
  /**
@@ -427,11 +474,7 @@ export declare class RuntimeRunner {
427
474
  */
428
475
  bootstrapWorkflow(spec: WorkflowSpec, opts?: {
429
476
  submitterAgentId?: string;
430
- }): Promise<{
431
- completed: string[];
432
- failed: string[];
433
- outputs: Record<string, string>;
434
- }>;
477
+ }): Promise<WorkflowOutcome>;
435
478
  /**
436
479
  * M5 v2.1: drive the sub-workflow(s) a top-level agent authored via `start_workflow`. Called at the
437
480
  * verified-safe point (right after the tool turn resolved to `call_provider` — kernel in Reason, not
@@ -455,7 +498,7 @@ export declare class RuntimeRunner {
455
498
  * Shared workflow driver for `runWorkflow` (host `load_workflow`) and `bootstrapWorkflow` (agent
456
499
  * `submit_workflow`): given the observations from the initial load/bootstrap, run each kernel-emitted
457
500
  * batch in parallel, feed completions back (appending any agent-submitted nodes first), and loop
458
- * until the kernel reports the workflow complete. Returns the completed / failed node agent-ids.
501
+ * until the kernel reports the workflow complete. Returns typed terminal node outcomes.
459
502
  */
460
503
  private driveWorkflow;
461
504
  /**
@@ -466,14 +509,11 @@ export declare class RuntimeRunner {
466
509
  */
467
510
  resumeWorkflow(spec: WorkflowSpec, opts?: {
468
511
  sessionId?: string;
469
- }): Promise<{
470
- completed: string[];
471
- failed: string[];
472
- }>;
473
- interrupt(): void;
512
+ }): Promise<WorkflowOutcome>;
513
+ interrupt(reason?: OperationCancellationReason): void;
474
514
  /** Push a contextual note into the run's signal stream (the system-reminder channel): it drains at
475
- * the next turn boundary, routes through the kernel attention policy, and once acted on — renders
476
- * as a `[SIGNAL] <text>` line in the volatile state turn plus a durable directive. Use it to feed
515
+ * the next turn boundary, routes through the kernel attention policy, and renders once as a
516
+ * `[SIGNAL] <text>` line in the volatile state turn. Use it to feed
477
517
  * host-detected events back to the model mid-run (e.g. "that write was a no-op — stop repeating it")
478
518
  * without wiring a full `SignalSource`. `urgency` maps to the kernel disposition ladder: `"normal"`
479
519
  * queues for the next boundary (default), `"high"` soft-interrupts, `"critical"` preempts. */
@@ -485,6 +525,7 @@ export declare class RuntimeRunner {
485
525
  /** Injected-note drain shared by the main loop's per-turn poll: injected notes first (FIFO), then
486
526
  * the configured `signalSource`. Keeps the two inbound channels on one code path so they never drift. */
487
527
  private nextInboundSignal;
528
+ private consumeInboundSignal;
488
529
  run(req: {
489
530
  sessionId: string;
490
531
  goal: string;
@@ -499,15 +540,13 @@ export declare class RuntimeRunner {
499
540
  }>;
500
541
  }): AsyncIterable<StreamEvent>;
501
542
  wake(sessionId: string, extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
502
- dream(agentId: string, nowMs?: number): AsyncIterable<StreamEvent>;
503
- /** Resolve in-kernel AskUser suspend; returns resume lists and stream events to yield. */
504
- private resolveKernelSuspend;
543
+ /** Execute a kernel-owned approval effect and return the correlated decision lists. */
544
+ private resolveApprovalRequests;
505
545
  /**
506
546
  * O7: resolve a `read_result` meta-tool call to the full text of a previously-evicted tool
507
- * output. Resolution order: (a) this turn's in-memory `pendingSpoolOutputs` map (a call spooled
508
- * earlier in the SAME tool-turn, before the session-log write lands), (b) the on-disk result
509
- * spool (persisted once the kernel observation `large_result_spooled` was processed), (c) a
510
- * session-log scan for the original `tool_completed` event carrying that `call_id`. Slices the
547
+ * output. Resolution order: (a) the on-disk result spool committed by the explicit
548
+ * `spool_large_result` host effect, then (b) a session-log scan for the original
549
+ * `tool_completed` event carrying that `call_id`. Slices the
511
550
  * resolved text by `[offset, offset + maxBytes)` (plain string slice — "bytes-ish").
512
551
  */
513
552
  private resolveReadResult;