@deepstrike/wasm 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 (48) hide show
  1. package/README.md +14 -13
  2. package/dist/harness/index.d.ts +127 -61
  3. package/dist/harness/index.js +212 -83
  4. package/dist/index.d.ts +13 -6
  5. package/dist/index.js +7 -2
  6. package/dist/memory/extraction.d.ts +4 -0
  7. package/dist/memory/extraction.js +48 -0
  8. package/dist/memory/in-memory-store.d.ts +19 -9
  9. package/dist/memory/in-memory-store.js +68 -23
  10. package/dist/memory/index.d.ts +52 -24
  11. package/dist/memory/ranking.d.ts +32 -0
  12. package/dist/memory/ranking.js +77 -0
  13. package/dist/memory/retention.d.ts +17 -0
  14. package/dist/memory/retention.js +54 -0
  15. package/dist/providers/base.d.ts +5 -0
  16. package/dist/providers/base.js +32 -0
  17. package/dist/runtime/context-policy.d.ts +35 -0
  18. package/dist/runtime/context-policy.js +66 -0
  19. package/dist/runtime/eval.d.ts +2 -0
  20. package/dist/runtime/execution-plane.d.ts +2 -1
  21. package/dist/runtime/execution-plane.js +3 -3
  22. package/dist/runtime/facade.js +2 -1
  23. package/dist/runtime/index.d.ts +13 -4
  24. package/dist/runtime/index.js +6 -1
  25. package/dist/runtime/kernel-event-log.js +46 -13
  26. package/dist/runtime/kernel-rebuild.d.ts +8 -0
  27. package/dist/runtime/kernel-rebuild.js +65 -0
  28. package/dist/runtime/kernel-step.d.ts +139 -7
  29. package/dist/runtime/kernel-step.js +110 -10
  30. package/dist/runtime/kernel-transaction-log.d.ts +61 -0
  31. package/dist/runtime/kernel-transaction-log.js +140 -0
  32. package/dist/runtime/os-profile.d.ts +9 -10
  33. package/dist/runtime/os-profile.js +14 -10
  34. package/dist/runtime/os-snapshot.d.ts +19 -0
  35. package/dist/runtime/os-snapshot.js +16 -3
  36. package/dist/runtime/runner.d.ts +73 -41
  37. package/dist/runtime/runner.js +562 -290
  38. package/dist/runtime/session-log.d.ts +55 -10
  39. package/dist/runtime/session-log.js +60 -3
  40. package/dist/runtime/session-repair.d.ts +11 -7
  41. package/dist/runtime/session-repair.js +11 -8
  42. package/dist/runtime/sub-agent-orchestrator.js +1 -1
  43. package/dist/runtime/types/agent.d.ts +31 -0
  44. package/dist/runtime/types/agent.js +35 -0
  45. package/dist/signals/index.d.ts +21 -1
  46. package/dist/signals/index.js +1 -0
  47. package/dist/types.d.ts +7 -2
  48. package/package.json +2 -2
@@ -1,4 +1,25 @@
1
- export const KERNEL_ABI_VERSION = 1;
1
+ export const KERNEL_ABI_VERSION = 2;
2
+ export function readKernelDiagnostics(runtime) {
3
+ return JSON.parse(runtime.diagnostics());
4
+ }
5
+ export function snapshotKernelRuntime(runtime) {
6
+ return JSON.parse(runtime.snapshot());
7
+ }
8
+ export function restoreKernelRuntime(runtime, snapshot) {
9
+ runtime.restore(JSON.stringify(snapshot));
10
+ const operationId = snapshot.operation_id;
11
+ if (!operationId) {
12
+ kernelWireStates.delete(runtime);
13
+ return;
14
+ }
15
+ const nextEventSequence = snapshot.accepted_inputs.reduce((next, input) => {
16
+ const match = input.event_id.match(/-event-(\d+)$/);
17
+ return match ? Math.max(next, Number(match[1]) + 1) : next;
18
+ }, 1);
19
+ kernelWireStates.set(runtime, { operationId, nextEventSequence });
20
+ }
21
+ let nextOperationSequence = 1;
22
+ const kernelWireStates = new WeakMap();
2
23
  function tryParseJson(s) {
3
24
  try {
4
25
  return JSON.parse(s);
@@ -41,7 +62,27 @@ export function messageToKernelMessage(message) {
41
62
  if (message.tokenCount !== undefined) {
42
63
  out.token_count = message.tokenCount;
43
64
  }
44
- out.content = message.content;
65
+ // Multimodal: serialize typed content parts to the kernel `Content::Parts` shape when present
66
+ // (image/audio must survive the reconstruction→preload path, not just live ingress).
67
+ if (message.contentParts && message.contentParts.length > 0) {
68
+ out.content = message.contentParts.map(part => {
69
+ if (part.type === "text")
70
+ return { type: "text", text: part.text };
71
+ if (part.type === "tool_result") {
72
+ return { type: "tool_result", call_id: part.callId, output: part.output, is_error: part.isError };
73
+ }
74
+ if (part.type === "image") {
75
+ return { type: "image", url: part.url, data: part.data, media_type: part.mediaType, detail: part.detail };
76
+ }
77
+ if (part.type === "audio") {
78
+ return { type: "audio", data: part.data, media_type: part.mediaType };
79
+ }
80
+ return { type: "text", text: message.content };
81
+ });
82
+ }
83
+ else {
84
+ out.content = message.content;
85
+ }
45
86
  return out;
46
87
  }
47
88
  export function toolResultToKernel(result) {
@@ -130,10 +171,14 @@ function renderedContextToSdk(raw) {
130
171
  return ctx;
131
172
  }
132
173
  function mapKernelAction(raw) {
174
+ const effectId = String(raw.effect_id ?? "");
175
+ if (!effectId)
176
+ throw new Error(`kernel action ${String(raw.kind)} is missing effect_id`);
133
177
  switch (raw.kind) {
134
178
  case "call_provider":
135
179
  return {
136
180
  kind: "call_provider",
181
+ effectId,
137
182
  context: renderedContextToSdk(raw.context ?? {}),
138
183
  tools: (raw.tools ?? []).map(t => ({
139
184
  name: String(t.name ?? ""),
@@ -144,15 +189,49 @@ function mapKernelAction(raw) {
144
189
  case "execute_tool":
145
190
  return {
146
191
  kind: "execute_tool",
192
+ effectId,
147
193
  calls: (raw.calls ?? []).map(c => ({
148
194
  id: String(c.id ?? ""),
149
195
  name: String(c.name ?? ""),
150
196
  arguments: JSON.stringify(c.arguments ?? {}),
151
197
  })),
152
198
  };
199
+ case "request_approval":
200
+ return {
201
+ kind: "request_approval", effectId,
202
+ requests: (raw.requests ?? []).map(request => ({
203
+ callId: String(request.call_id ?? ""), tool: String(request.tool ?? ""),
204
+ arguments: JSON.stringify(request.arguments ?? {}), reason: String(request.reason ?? ""),
205
+ })),
206
+ };
207
+ case "spawn_workflow":
208
+ return {
209
+ kind: "spawn_workflow", effectId,
210
+ nodes: raw.nodes ?? [],
211
+ ...(raw.budget && typeof raw.budget === "object" ? { budget: raw.budget } : {}),
212
+ };
213
+ case "preempt_sub_agents":
214
+ return { kind: "preempt_sub_agents", effectId, agentIds: raw.agent_ids ?? [], reason: String(raw.reason ?? "") };
215
+ case "persist_memory":
216
+ return { kind: "persist_memory", effectId, memory: raw.memory ?? {} };
217
+ case "query_memory":
218
+ return { kind: "query_memory", effectId, query: raw.query ?? {}, requestedK: Number(raw.requested_k ?? 0) };
219
+ case "spool_large_result":
220
+ return {
221
+ kind: "spool_large_result", effectId, callId: String(raw.call_id ?? ""), tool: String(raw.tool ?? ""),
222
+ output: String(raw.output ?? ""), originalSize: Number(raw.original_size ?? 0), previewSize: Number(raw.preview_size ?? 0),
223
+ };
224
+ case "archive_page_out":
225
+ return {
226
+ kind: "archive_page_out", effectId, turn: Number(raw.turn ?? 0), action: String(raw.action ?? "auto_compact"),
227
+ ...(typeof raw.summary === "string" ? { summary: raw.summary } : {}),
228
+ archived: (raw.archived ?? []).map(kernelMessageToSdk),
229
+ tier: String(raw.tier ?? "durable"),
230
+ };
153
231
  case "evaluate_milestone":
154
232
  return {
155
233
  kind: "evaluate_milestone",
234
+ effectId,
156
235
  phaseId: String(raw.phase_id ?? ""),
157
236
  criteria: raw.criteria ?? [],
158
237
  requiredEvidence: raw.required_evidence ?? [],
@@ -162,6 +241,7 @@ function mapKernelAction(raw) {
162
241
  const pace = result.pace_decision;
163
242
  return {
164
243
  kind: "done",
244
+ effectId,
165
245
  result: {
166
246
  termination: String(result.termination ?? "error"),
167
247
  turnsUsed: Number(result.turns_used ?? 0),
@@ -184,16 +264,36 @@ function mapKernelAction(raw) {
184
264
  throw new Error(`unknown KernelAction kind: ${String(raw.kind)}`);
185
265
  }
186
266
  }
187
- function stepInput(event) {
188
- return JSON.stringify({ version: KERNEL_ABI_VERSION, event });
267
+ function stepInput(runtime, event) {
268
+ let state = kernelWireStates.get(runtime);
269
+ if (!state) {
270
+ state = { operationId: `wasm-operation-${nextOperationSequence++}`, nextEventSequence: 1 };
271
+ kernelWireStates.set(runtime, state);
272
+ }
273
+ const correlatedEvent = event.kind === "cancel_operation"
274
+ ? { ...event, operation_id: state.operationId }
275
+ : event;
276
+ return JSON.stringify({
277
+ version: KERNEL_ABI_VERSION,
278
+ operation_id: state.operationId,
279
+ event_id: `${state.operationId}-event-${state.nextEventSequence++}`,
280
+ observed_at_ms: Date.now(),
281
+ event: correlatedEvent,
282
+ });
189
283
  }
190
284
  export function kernelApply(runtime, pending, event) {
191
- const step = parseStep(runtime.step(stepInput(event)));
285
+ const step = parseStep(runtime.step(stepInput(runtime, event)));
286
+ const fault = step.faults?.[0];
287
+ if (fault)
288
+ throw new Error(`${fault.code ?? "kernel_fault"}: ${fault.message ?? "kernel transition failed"}`);
192
289
  pending.push(...step.observations);
193
290
  return step.observations;
194
291
  }
195
292
  export function kernelAction(runtime, pending, event) {
196
- const step = parseStep(runtime.step(stepInput(event)));
293
+ const step = parseStep(runtime.step(stepInput(runtime, event)));
294
+ const fault = step.faults?.[0];
295
+ if (fault)
296
+ throw new Error(`${fault.code ?? "kernel_fault"}: ${fault.message ?? "kernel transition failed"}`);
197
297
  pending.push(...step.observations);
198
298
  const raw = step.actions[0];
199
299
  if (!raw)
@@ -202,11 +302,11 @@ export function kernelAction(runtime, pending, event) {
202
302
  }
203
303
  /** Like kernelAction but tolerates zero-action steps (e.g. queued signals). */
204
304
  export function kernelMaybeAction(runtime, pending, event) {
205
- const step = parseStep(runtime.step(stepInput(event)));
305
+ const step = parseStep(runtime.step(stepInput(runtime, event)));
306
+ const fault = step.faults?.[0];
307
+ if (fault)
308
+ throw new Error(`${fault.code ?? "kernel_fault"}: ${fault.message ?? "kernel transition failed"}`);
206
309
  pending.push(...step.observations);
207
310
  const raw = step.actions[0];
208
311
  return raw ? mapKernelAction(raw) : null;
209
312
  }
210
- export function forceCompact(runtime, pending) {
211
- return kernelApply(runtime, pending, { kind: "force_compact" }).some(o => o.kind === "compressed");
212
- }
@@ -0,0 +1,61 @@
1
+ export declare const KERNEL_LOG_RECORD_VERSION: 1;
2
+ export interface KernelOperationGenesisBody {
3
+ record_version: typeof KERNEL_LOG_RECORD_VERSION;
4
+ abi_version: number;
5
+ operation_id: string;
6
+ initial_scheduler_policy: Record<string, unknown>;
7
+ resolved_runtime_defaults: Record<string, unknown>;
8
+ default_policy_version: number;
9
+ }
10
+ export interface KernelOperationGenesis extends KernelOperationGenesisBody {
11
+ genesis_digest: string;
12
+ }
13
+ export interface KernelTransactionBody {
14
+ record_version: typeof KERNEL_LOG_RECORD_VERSION;
15
+ operation_id: string;
16
+ step_seq: number;
17
+ base_generation: number;
18
+ input: Record<string, unknown>;
19
+ input_digest: string;
20
+ previous_transaction_digest: string;
21
+ step_digest: string;
22
+ }
23
+ export interface KernelTransaction extends KernelTransactionBody {
24
+ transaction_digest: string;
25
+ }
26
+ export interface KernelGenesisReceipt {
27
+ log_seq: number;
28
+ genesis_digest: string;
29
+ }
30
+ export interface DurableAppendReceipt {
31
+ log_seq: number;
32
+ transaction_digest: string;
33
+ }
34
+ export interface KernelOperationCursor {
35
+ operation_id: string;
36
+ next_event_sequence: number;
37
+ next_step_seq: number;
38
+ transaction_head_digest: string;
39
+ }
40
+ export declare class KernelLogConflictError extends Error {
41
+ constructor(message: string);
42
+ }
43
+ export declare class KernelLogIntegrityError extends Error {
44
+ constructor(message: string);
45
+ }
46
+ export declare function canonicalKernelJson(value: unknown): string;
47
+ export declare function kernelRecordDigest(value: unknown): Promise<string>;
48
+ export declare function createKernelOperationGenesis(input: Omit<KernelOperationGenesisBody, "record_version">): Promise<KernelOperationGenesis>;
49
+ export declare function createKernelTransaction(input: {
50
+ operation_id: string;
51
+ step_seq: number;
52
+ base_generation: number;
53
+ input: Record<string, unknown>;
54
+ step: Record<string, unknown>;
55
+ previous_transaction_digest: string;
56
+ }): Promise<KernelTransaction>;
57
+ export declare function verifyKernelOperationGenesis(genesis: KernelOperationGenesis): Promise<void>;
58
+ export declare function verifyKernelTransaction(transaction: KernelTransaction): Promise<void>;
59
+ export declare function verifyKernelTransactionSuccessor(previous: KernelTransaction | undefined, transaction: KernelTransaction): void;
60
+ /** Validate one complete authoritative operation stream and derive its next wire cursor. */
61
+ export declare function verifyKernelTransactionStream(genesis: KernelOperationGenesis, transactions: readonly KernelTransaction[]): Promise<KernelOperationCursor>;
@@ -0,0 +1,140 @@
1
+ export const KERNEL_LOG_RECORD_VERSION = 1;
2
+ export class KernelLogConflictError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "KernelLogConflictError";
6
+ }
7
+ }
8
+ export class KernelLogIntegrityError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "KernelLogIntegrityError";
12
+ }
13
+ }
14
+ export function canonicalKernelJson(value) {
15
+ if (value === null)
16
+ return "null";
17
+ if (typeof value === "string" || typeof value === "boolean")
18
+ return JSON.stringify(value);
19
+ if (typeof value === "number") {
20
+ if (!Number.isFinite(value))
21
+ throw new KernelLogIntegrityError("canonical records require finite numbers");
22
+ if (Number.isSafeInteger(value))
23
+ return JSON.stringify(Object.is(value, -0) ? 0 : value);
24
+ if (Number.isInteger(value)) {
25
+ throw new KernelLogIntegrityError("canonical record integer exceeds the cross-SDK safe range");
26
+ }
27
+ const bytes = new Uint8Array(8);
28
+ new DataView(bytes.buffer).setFloat64(0, value, false);
29
+ return `f64:${Array.from(bytes, byte => byte.toString(16).padStart(2, "0")).join("")}`;
30
+ }
31
+ if (Array.isArray(value))
32
+ return `[${value.map(canonicalKernelJson).join(",")}]`;
33
+ if (typeof value === "object") {
34
+ const object = value;
35
+ const keys = Object.keys(object).sort();
36
+ return `{${keys.map(key => `${JSON.stringify(key)}:${canonicalKernelJson(object[key])}`).join(",")}}`;
37
+ }
38
+ throw new KernelLogIntegrityError(`unsupported canonical record value: ${typeof value}`);
39
+ }
40
+ export async function kernelRecordDigest(value) {
41
+ const bytes = new TextEncoder().encode(canonicalKernelJson(value));
42
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
43
+ return Array.from(new Uint8Array(digest), byte => byte.toString(16).padStart(2, "0")).join("");
44
+ }
45
+ export async function createKernelOperationGenesis(input) {
46
+ const body = { record_version: KERNEL_LOG_RECORD_VERSION, ...input };
47
+ validateGenesisBody(body);
48
+ return { ...body, genesis_digest: await kernelRecordDigest(body) };
49
+ }
50
+ export async function createKernelTransaction(input) {
51
+ const body = {
52
+ record_version: KERNEL_LOG_RECORD_VERSION,
53
+ operation_id: input.operation_id,
54
+ step_seq: input.step_seq,
55
+ base_generation: input.base_generation,
56
+ input: input.input,
57
+ input_digest: await kernelRecordDigest(input.input),
58
+ previous_transaction_digest: input.previous_transaction_digest,
59
+ step_digest: await kernelRecordDigest(input.step),
60
+ };
61
+ validateTransactionBody(body);
62
+ return { ...body, transaction_digest: await kernelRecordDigest(body) };
63
+ }
64
+ export async function verifyKernelOperationGenesis(genesis) {
65
+ const { genesis_digest, ...body } = genesis;
66
+ validateGenesisBody(body);
67
+ if (await kernelRecordDigest(body) !== genesis_digest) {
68
+ throw new KernelLogIntegrityError("kernel genesis digest does not match its canonical body");
69
+ }
70
+ }
71
+ export async function verifyKernelTransaction(transaction) {
72
+ const { transaction_digest, ...body } = transaction;
73
+ validateTransactionBody(body);
74
+ if (await kernelRecordDigest(body.input) !== body.input_digest) {
75
+ throw new KernelLogIntegrityError("kernel transaction input digest does not match its input");
76
+ }
77
+ if (await kernelRecordDigest(body) !== transaction_digest) {
78
+ throw new KernelLogIntegrityError("kernel transaction digest does not match its canonical body");
79
+ }
80
+ }
81
+ export function verifyKernelTransactionSuccessor(previous, transaction) {
82
+ const expectedStepSeq = previous ? previous.step_seq + 1 : 1;
83
+ const expectedGeneration = previous ? previous.base_generation + 1 : 0;
84
+ if (transaction.step_seq !== expectedStepSeq) {
85
+ throw new KernelLogIntegrityError(`kernel transaction step_seq ${transaction.step_seq} does not follow ${expectedStepSeq - 1}`);
86
+ }
87
+ if (transaction.base_generation !== expectedGeneration) {
88
+ throw new KernelLogIntegrityError(`kernel transaction base_generation ${transaction.base_generation} does not match ${expectedGeneration}`);
89
+ }
90
+ if (transaction.input.operation_id !== transaction.operation_id) {
91
+ throw new KernelLogIntegrityError("kernel transaction input operation_id does not match its envelope");
92
+ }
93
+ }
94
+ /** Validate one complete authoritative operation stream and derive its next wire cursor. */
95
+ export async function verifyKernelTransactionStream(genesis, transactions) {
96
+ await verifyKernelOperationGenesis(genesis);
97
+ let previous;
98
+ let head = genesis.genesis_digest;
99
+ for (const transaction of transactions) {
100
+ await verifyKernelTransaction(transaction);
101
+ if (transaction.operation_id !== genesis.operation_id) {
102
+ throw new KernelLogIntegrityError("kernel transaction operation_id does not match genesis");
103
+ }
104
+ if (transaction.previous_transaction_digest !== head) {
105
+ throw new KernelLogIntegrityError("kernel transaction digest chain is not continuous");
106
+ }
107
+ verifyKernelTransactionSuccessor(previous, transaction);
108
+ previous = transaction;
109
+ head = transaction.transaction_digest;
110
+ }
111
+ const nextSequence = (previous?.step_seq ?? 0) + 1;
112
+ return {
113
+ operation_id: genesis.operation_id,
114
+ next_event_sequence: nextSequence,
115
+ next_step_seq: nextSequence,
116
+ transaction_head_digest: head,
117
+ };
118
+ }
119
+ function validateGenesisBody(genesis) {
120
+ if (genesis.record_version !== KERNEL_LOG_RECORD_VERSION)
121
+ throw new KernelLogIntegrityError("unsupported kernel genesis record version");
122
+ if (!Number.isSafeInteger(genesis.abi_version) || genesis.abi_version <= 0)
123
+ throw new KernelLogIntegrityError("kernel genesis abi_version must be a positive safe integer");
124
+ if (!genesis.operation_id)
125
+ throw new KernelLogIntegrityError("kernel genesis operation_id is required");
126
+ if (!Number.isSafeInteger(genesis.default_policy_version) || genesis.default_policy_version <= 0)
127
+ throw new KernelLogIntegrityError("kernel genesis default_policy_version must be a positive safe integer");
128
+ }
129
+ function validateTransactionBody(transaction) {
130
+ if (transaction.record_version !== KERNEL_LOG_RECORD_VERSION)
131
+ throw new KernelLogIntegrityError("unsupported kernel transaction record version");
132
+ if (!transaction.operation_id)
133
+ throw new KernelLogIntegrityError("kernel transaction operation_id is required");
134
+ if (!Number.isSafeInteger(transaction.step_seq) || transaction.step_seq <= 0)
135
+ throw new KernelLogIntegrityError("kernel transaction step_seq must be a positive safe integer");
136
+ if (!Number.isSafeInteger(transaction.base_generation) || transaction.base_generation < 0)
137
+ throw new KernelLogIntegrityError("kernel transaction base_generation must be a non-negative safe integer");
138
+ if (!transaction.previous_transaction_digest)
139
+ throw new KernelLogIntegrityError("kernel transaction previous_transaction_digest is required");
140
+ }
@@ -1,16 +1,17 @@
1
1
  import type { GovernancePolicy } from "../governance.js";
2
2
  export type OsProfileId = "native";
3
+ export interface SignalPolicy {
4
+ queueMax: number;
5
+ ttlMs?: number;
6
+ deadlineEscalation?: boolean;
7
+ }
3
8
  export interface NativeOsProfile {
4
9
  id: OsProfileId;
5
- attentionPolicy: {
6
- maxQueueSize?: number;
7
- };
10
+ signalPolicy: SignalPolicy;
8
11
  governancePolicy: GovernancePolicy;
9
12
  }
10
- /** Default attention policy for native profile smoke tests. */
11
- export declare const DEFAULT_NATIVE_ATTENTION_POLICY: {
12
- maxQueueSize: number;
13
- };
13
+ /** Default signal policy for native profile smoke tests. */
14
+ export declare const DEFAULT_NATIVE_SIGNAL_POLICY: SignalPolicy;
14
15
  /** Permissive governance policy for native runs that do not need AskUser. */
15
16
  export declare const DEFAULT_NATIVE_GOVERNANCE_POLICY: GovernancePolicy;
16
17
  /** Default restrictive sandbox policy template requiring confirmation for modification/execution. */
@@ -22,9 +23,7 @@ export declare function assertNativeProfile(profile?: OsProfileId | NativeOsProf
22
23
  /**
23
24
  * Validates the declarative policies statically to prevent runtime crashes when loaded into the microkernel.
24
25
  */
25
- export declare function validateDeclarativePolicy(govPolicy?: GovernancePolicy, attentionPolicy?: {
26
- maxQueueSize?: number;
27
- }): {
26
+ export declare function validateDeclarativePolicy(govPolicy?: GovernancePolicy, signalPolicy?: SignalPolicy): {
28
27
  valid: boolean;
29
28
  errors: string[];
30
29
  };
@@ -1,5 +1,5 @@
1
- /** Default attention policy for native profile smoke tests. */
2
- export const DEFAULT_NATIVE_ATTENTION_POLICY = { maxQueueSize: 64 };
1
+ /** Default signal policy for native profile smoke tests. */
2
+ export const DEFAULT_NATIVE_SIGNAL_POLICY = { queueMax: 64 };
3
3
  /** Permissive governance policy for native runs that do not need AskUser. */
4
4
  export const DEFAULT_NATIVE_GOVERNANCE_POLICY = {
5
5
  rules: [{ pattern: "*", action: "allow" }],
@@ -21,7 +21,7 @@ export function osProfile(profile = "native") {
21
21
  throw new Error(`Unsupported OS profile: ${profile}`);
22
22
  return {
23
23
  id: "native",
24
- attentionPolicy: DEFAULT_NATIVE_ATTENTION_POLICY,
24
+ signalPolicy: DEFAULT_NATIVE_SIGNAL_POLICY,
25
25
  governancePolicy: DEFAULT_NATIVE_GOVERNANCE_POLICY,
26
26
  };
27
27
  }
@@ -31,7 +31,7 @@ export function assertNativeProfile(profile = "native") {
31
31
  if (resolved.id !== "native") {
32
32
  throw new Error(`Unsupported OS profile: ${resolved.id}`);
33
33
  }
34
- const validation = validateDeclarativePolicy(resolved.governancePolicy, resolved.attentionPolicy);
34
+ const validation = validateDeclarativePolicy(resolved.governancePolicy, resolved.signalPolicy);
35
35
  if (!validation.valid) {
36
36
  throw new Error(`Invalid native OS profile: ${validation.errors.join("; ")}`);
37
37
  }
@@ -40,7 +40,7 @@ export function assertNativeProfile(profile = "native") {
40
40
  /**
41
41
  * Validates the declarative policies statically to prevent runtime crashes when loaded into the microkernel.
42
42
  */
43
- export function validateDeclarativePolicy(govPolicy, attentionPolicy) {
43
+ export function validateDeclarativePolicy(govPolicy, signalPolicy) {
44
44
  const errors = [];
45
45
  if (govPolicy) {
46
46
  if (!Array.isArray(govPolicy.rules)) {
@@ -57,11 +57,15 @@ export function validateDeclarativePolicy(govPolicy, attentionPolicy) {
57
57
  });
58
58
  }
59
59
  }
60
- if (attentionPolicy) {
61
- if (attentionPolicy.maxQueueSize !== undefined) {
62
- if (typeof attentionPolicy.maxQueueSize !== "number" || attentionPolicy.maxQueueSize <= 0) {
63
- errors.push("AttentionPolicy maxQueueSize must be a positive integer");
64
- }
60
+ if (signalPolicy) {
61
+ if (!Number.isInteger(signalPolicy.queueMax) || signalPolicy.queueMax <= 0) {
62
+ errors.push("SignalPolicy queueMax must be a positive integer");
63
+ }
64
+ if (signalPolicy.ttlMs !== undefined && (!Number.isInteger(signalPolicy.ttlMs) || signalPolicy.ttlMs <= 0)) {
65
+ errors.push("SignalPolicy ttlMs must be a positive integer");
66
+ }
67
+ if (signalPolicy.deadlineEscalation !== undefined && typeof signalPolicy.deadlineEscalation !== "boolean") {
68
+ errors.push("SignalPolicy deadlineEscalation must be a boolean");
65
69
  }
66
70
  }
67
71
  return {
@@ -14,10 +14,29 @@ export interface OsSnapshot {
14
14
  }>;
15
15
  budgetExceeded: Array<{
16
16
  turn: number;
17
+ operation_id: string;
18
+ reservation_id?: string;
17
19
  budget: string;
18
20
  }>;
21
+ budgetUsageReported: Array<{
22
+ turn: number;
23
+ operation_id: string;
24
+ reservation_id: string;
25
+ tokens: number;
26
+ subagents: number;
27
+ rounds: number;
28
+ }>;
29
+ cancellations: Array<{
30
+ turn: number;
31
+ operation_id: string;
32
+ reason: "user" | "deadline" | "lease_lost" | "host_shutdown";
33
+ pending_call_ids: string[];
34
+ }>;
19
35
  signals: Array<{
20
36
  turn: number;
37
+ operation_id: string;
38
+ delivery_id: string;
39
+ attempt: number;
21
40
  signal_id: string;
22
41
  disposition: string;
23
42
  queue_depth: number;
@@ -8,8 +8,10 @@ const KERNEL_KINDS = new Set([
8
8
  "suspended",
9
9
  "resumed",
10
10
  "tool_gated",
11
- "signal_disposed",
11
+ "signal_delivery_disposed",
12
12
  "budget_exceeded",
13
+ "budget_usage_reported",
14
+ "operation_cancelled",
13
15
  "checkpoint_taken",
14
16
  "rollbacked",
15
17
  "agent_process_changed",
@@ -20,6 +22,8 @@ export function rebuildOsSnapshotFromSessionEvents(events) {
20
22
  const snap = {
21
23
  processByAgent: [],
22
24
  budgetExceeded: [],
25
+ budgetUsageReported: [],
26
+ cancellations: [],
23
27
  signals: [],
24
28
  pageOutCount: 0,
25
29
  pageInCount: 0,
@@ -62,11 +66,20 @@ export function rebuildOsSnapshotFromSessionEvents(events) {
62
66
  break;
63
67
  }
64
68
  case "budget_exceeded":
65
- snap.budgetExceeded.push({ turn: event.turn, budget: event.budget });
69
+ snap.budgetExceeded.push({ turn: event.turn, operation_id: event.operation_id, ...(event.reservation_id ? { reservation_id: event.reservation_id } : {}), budget: event.budget });
66
70
  break;
67
- case "signal_disposed":
71
+ case "budget_usage_reported":
72
+ snap.budgetUsageReported.push({ turn: event.turn, operation_id: event.operation_id, reservation_id: event.reservation_id, tokens: event.tokens, subagents: event.subagents, rounds: event.rounds });
73
+ break;
74
+ case "operation_cancelled":
75
+ snap.cancellations.push({ turn: event.turn, operation_id: event.operation_id, reason: event.reason, pending_call_ids: event.pending_call_ids });
76
+ break;
77
+ case "signal_delivery_disposed":
68
78
  snap.signals.push({
69
79
  turn: event.turn,
80
+ operation_id: event.operation_id,
81
+ delivery_id: event.delivery_id,
82
+ attempt: event.attempt,
70
83
  signal_id: event.signal_id,
71
84
  disposition: event.disposition,
72
85
  queue_depth: event.queue_depth,