@deepstrike/sdk 0.2.49 → 0.2.51

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 (41) hide show
  1. package/README.md +83 -60
  2. package/dist/harness/manifest.d.ts +1 -1
  3. package/dist/harness/manifest.js +43 -29
  4. package/dist/index.d.ts +5 -7
  5. package/dist/index.js +3 -3
  6. package/dist/kernel.d.ts +61 -31
  7. package/dist/runtime/canonical-kernel-step.d.ts +143 -0
  8. package/dist/runtime/canonical-kernel-step.js +1444 -0
  9. package/dist/runtime/execution-plane.d.ts +0 -3
  10. package/dist/runtime/execution-plane.js +0 -24
  11. package/dist/runtime/facade.js +3 -0
  12. package/dist/runtime/kernel-event-log.js +7 -13
  13. package/dist/runtime/kernel-journal.d.ts +264 -0
  14. package/dist/runtime/kernel-journal.js +741 -0
  15. package/dist/runtime/kernel-primitives-dashboard.d.ts +0 -2
  16. package/dist/runtime/kernel-primitives-dashboard.js +1 -8
  17. package/dist/runtime/kernel-step.d.ts +29 -109
  18. package/dist/runtime/kernel-step.js +47 -317
  19. package/dist/runtime/os-snapshot.d.ts +2 -2
  20. package/dist/runtime/os-snapshot.js +2 -6
  21. package/dist/runtime/payload-store.d.ts +16 -0
  22. package/dist/runtime/payload-store.js +80 -0
  23. package/dist/runtime/runner.d.ts +80 -119
  24. package/dist/runtime/runner.js +706 -779
  25. package/dist/runtime/session-log.d.ts +34 -32
  26. package/dist/runtime/session-log.js +21 -131
  27. package/dist/runtime/session-repair.d.ts +2 -36
  28. package/dist/runtime/session-repair.js +2 -47
  29. package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
  30. package/dist/runtime/sub-agent-orchestrator.js +42 -40
  31. package/dist/types/agent.d.ts +31 -19
  32. package/dist/types/agent.js +31 -42
  33. package/dist/workflow/public.d.ts +1 -1
  34. package/dist/workflow/public.js +1 -1
  35. package/package.json +2 -2
  36. package/dist/runtime/kernel-rebuild.d.ts +0 -13
  37. package/dist/runtime/kernel-rebuild.js +0 -75
  38. package/dist/runtime/kernel-transaction-log.d.ts +0 -61
  39. package/dist/runtime/kernel-transaction-log.js +0 -149
  40. package/dist/runtime/large-result-spool.d.ts +0 -93
  41. package/dist/runtime/large-result-spool.js +0 -214
@@ -1,22 +1,4 @@
1
1
  import { getKernel } from "../kernel.js";
2
- /** Map kernel spawn observation → host manifest. */
3
- export function spawnObservationToManifest(obs, spec, parentSessionId) {
4
- const o = obs;
5
- return {
6
- kind: "agent_process_changed",
7
- turn: o.turn,
8
- agent_id: String(o.agent_id ?? spec.identity.agentId),
9
- parent_session_id: String(o.parent_session_id ?? parentSessionId),
10
- role: String(o.role ?? spec.role),
11
- isolation: String(o.isolation ?? spec.isolation ?? "shared"),
12
- context_inheritance: String(o.context_inheritance ?? "none"),
13
- permitted_capability_ids: o.permitted_capability_ids ?? [],
14
- };
15
- }
16
- export function findSpawnProcessObservation(observations) {
17
- const hit = observations.find(o => o.kind === "agent_process_changed" && typeof o.agent_id === "string");
18
- return hit;
19
- }
20
2
  export function agentIdentitySub(agentId, sessionId, parentSessionId) {
21
3
  return {
22
4
  agentId,
@@ -54,6 +36,11 @@ export function agentRunSpecToKernel(spec) {
54
36
  ...(spec.loopRound.defaultAction !== undefined ? { default_action: spec.loopRound.defaultAction } : {}),
55
37
  };
56
38
  }
39
+ // Exposure baseline: `undefined` ⇒ omit the field entirely (kernel `None` = legacy behavior);
40
+ // `[]` ⇒ send `[]` (kernel `Some([])` = the minimal surface). The unset/minimal distinction is
41
+ // load-bearing, so this is deliberately NOT the `length > 0` idiom `allowedToolIds` uses.
42
+ if (spec.exposureBaseline !== undefined)
43
+ out.exposure_baseline = [...spec.exposureBaseline];
57
44
  return out;
58
45
  }
59
46
  export function milestoneContractToKernel(contract) {
@@ -92,6 +79,9 @@ export function subAgentResultToKernel(result) {
92
79
  const attempt = result.result.attempt;
93
80
  return {
94
81
  agent_id: result.agentId,
82
+ ...(result.submittedNodes?.length
83
+ ? { submitted_nodes: result.submittedNodes.map(workflowNodeSpecToKernel) }
84
+ : {}),
95
85
  result: {
96
86
  termination: result.result.termination,
97
87
  final_message: finalMessage
@@ -146,6 +136,18 @@ export function milestoneCheckPass(phaseId) {
146
136
  export function milestoneCheckFail(phaseId, reason) {
147
137
  return { phaseId, passed: false, reason };
148
138
  }
139
+ /**
140
+ * R-B27: the conservative resolution the runner feeds back when an `evaluate_milestone` effect
141
+ * arrives with no phase `verifier` and no host `onMilestoneEvaluate` hook. Nothing can attest the
142
+ * phase, but the kernel is already holding the effect in its pending table — returning without an
143
+ * answer leaves a dangling effect that a logical-checkpoint recovery cannot resolve. The current
144
+ * `MilestoneResult` wire has no error field, so "could not be verified" is expressed with the
145
+ * shape the wire does have: `passed: false` (the phase does not advance — fail-closed).
146
+ *
147
+ * The string is part of the cross-SDK contract: WASM (`wasm/src/runtime/types/agent.ts`),
148
+ * Python (`deepstrike/types/agent.py`) and Rust must feed back the byte-identical reason.
149
+ */
150
+ export const MILESTONE_UNVERIFIED_REASON = "milestone unverified: no verifier configured and no host evaluation hook (fail-closed)";
149
151
  export function workflowNodeStatusFromTermination(termination) {
150
152
  if (termination === "completed")
151
153
  return "completed";
@@ -191,6 +193,15 @@ export function workflowBudgetNote(budget) {
191
193
  if (budget.tokens_remaining != null && budget.tokens_max != null) {
192
194
  parts.push(`tokens ${budget.tokens_used ?? 0}/${budget.tokens_max} used, ${budget.tokens_remaining} remaining`);
193
195
  }
196
+ if (budget.max_total_tokens != null) {
197
+ parts.push(`tokens capped at ${budget.max_total_tokens}`);
198
+ }
199
+ if (budget.max_turns != null) {
200
+ parts.push(`turns capped at ${budget.max_turns}`);
201
+ }
202
+ if (budget.max_concurrency != null) {
203
+ parts.push(`concurrency capped at ${budget.max_concurrency}`);
204
+ }
194
205
  if (parts.length === 0)
195
206
  return "";
196
207
  return (`[workflow budget] ${parts.join(" · ")}. ` +
@@ -225,7 +236,7 @@ function nodeKindToKernel(n) {
225
236
  return { type: "tournament", entrants: n.tournament.entrants.map(workflowTaskToKernel) };
226
237
  return undefined;
227
238
  }
228
- /** Map one host `WorkflowNodeSpec` to its snake_case kernel JSON. Shared by `load_workflow` (the
239
+ /** Map one host `WorkflowNodeSpec` to its snake_case canonical JSON. Shared by the workflow root (the
229
240
  * whole spec) and `submit_workflow_nodes` (R3-1 runtime append) so the two encodings never drift. */
230
241
  export function workflowNodeSpecToKernel(n) {
231
242
  const kind = nodeKindToKernel(n);
@@ -249,32 +260,10 @@ export function workflowNodeSpecToKernel(n) {
249
260
  dep_policy: n.depPolicy ?? "all_success",
250
261
  };
251
262
  }
252
- /** Map a host `WorkflowSpec` to the snake_case kernel JSON (`load_workflow.spec`). */
263
+ /** Map a host `WorkflowSpec` to the canonical workflow-root JSON. */
253
264
  export function workflowSpecToKernel(spec) {
254
265
  return { nodes: spec.nodes.map(workflowNodeSpecToKernel) };
255
266
  }
256
- /** R3-1: map a batch of host nodes to the `submit_workflow_nodes` kernel event body. G1: pass
257
- * `submitterAgentId` (the node that requested the append) so the kernel can enforce no-privilege-
258
- * escalation — a quarantined submitter's nodes are coerced to quarantined. Omitted ⇒ no coercion. */
259
- export function submitWorkflowNodesToKernel(nodes, submitterAgentId) {
260
- return {
261
- kind: "submit_workflow_nodes",
262
- nodes: nodes.map(workflowNodeSpecToKernel),
263
- ...(submitterAgentId ? { submitter_agent_id: submitterAgentId } : {}),
264
- };
265
- }
266
- /** M5/G1: map an agent-authored spec to the `submit_workflow` kernel event body (the agent-reachable
267
- * `Syscall::LoadWorkflow`). The kernel bootstraps the DAG when none is active, else flattens onto it.
268
- * `parentSessionId` seeds child session ids on bootstrap; `submitterAgentId` carries G1 trust coercion
269
- * on the flatten case (a quarantined author's nodes are coerced quarantined). */
270
- export function submitWorkflowToKernel(spec, parentSessionId, submitterAgentId) {
271
- return {
272
- kind: "submit_workflow",
273
- spec: workflowSpecToKernel(spec),
274
- parent_session_id: parentSessionId,
275
- ...(submitterAgentId ? { submitter_agent_id: submitterAgentId } : {}),
276
- };
277
- }
278
267
  /** Shared JSON-Schema for a workflow-node batch (a DAG). Used by both `submit_workflow_nodes`
279
268
  * (append) and `start_workflow` (M5 v1: author a sub-workflow), so the two tools never drift. */
280
269
  const workflowNodesArraySchema = {
@@ -3,7 +3,7 @@ export type { SubAgentRunContext } from "../runtime/sub-agent-orchestrator.js";
3
3
  export { builtinReducers, resolveReducer } from "../runtime/reducers.js";
4
4
  export type { Reducer, ReducerRegistry, ReducerInput } from "../runtime/reducers.js";
5
5
  export { FileWorkflowStore } from "../runtime/workflow-store.js";
6
- export { submitWorkflowNodesTool, startWorkflowTool, generateAndFilter, verifyRules, genEval, milestoneCheckPass, milestoneCheckFail, } from "../types/agent.js";
6
+ export { submitWorkflowNodesTool, startWorkflowTool, generateAndFilter, verifyRules, genEval, milestoneCheckPass, milestoneCheckFail, MILESTONE_UNVERIFIED_REASON, } from "../types/agent.js";
7
7
  export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec, AgentProcessChangedObservation, ContextInheritance, KernelAgentRole, LoopResult, MilestoneCheckResult, MilestoneContract, MilestonePhase, MilestonePolicy, SubAgentResult, TerminationReason, WorkflowSpawnInfo, WorkflowTaskSpec, WorkflowDependencyPolicy, WorkflowNodeStatus, WorkflowNodeOutcome, WorkflowOutcome, } from "../types/agent.js";
8
8
  export type { AcceptanceCriterion, VerificationContract, ContractCheckResult } from "../collaboration/contract.js";
9
9
  export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings } from "../collaboration/contract.js";
@@ -5,7 +5,7 @@
5
5
  export { SubAgentOrchestrator, defaultSubAgentOrchestrator, spawnStandalone } from "../runtime/sub-agent-orchestrator.js";
6
6
  export { builtinReducers, resolveReducer } from "../runtime/reducers.js";
7
7
  export { FileWorkflowStore } from "../runtime/workflow-store.js";
8
- export { submitWorkflowNodesTool, startWorkflowTool, generateAndFilter, verifyRules, genEval, milestoneCheckPass, milestoneCheckFail, } from "../types/agent.js";
8
+ export { submitWorkflowNodesTool, startWorkflowTool, generateAndFilter, verifyRules, genEval, milestoneCheckPass, milestoneCheckFail, MILESTONE_UNVERIFIED_REASON, } from "../types/agent.js";
9
9
  export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings } from "../collaboration/contract.js";
10
10
  export { HandoffBus } from "../collaboration/handoff.js";
11
11
  export { CreatorVerifierMode, OrchestrationMode } from "../collaboration/modes/creator-verifier.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.2.49",
3
+ "version": "0.2.51",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@anthropic-ai/sdk": "^0.99.0",
75
- "@deepstrike/core": "0.2.49",
75
+ "@deepstrike/core": "0.2.51",
76
76
  "@google/generative-ai": "^0.24.1",
77
77
  "openai": "^5.23.2"
78
78
  },
@@ -1,13 +0,0 @@
1
- import type { KernelRuntimeHandle } from "./kernel-step.js";
2
- import { type KernelOperationCursor, type KernelOperationGenesis, type KernelTransaction } from "./kernel-transaction-log.js";
3
- export interface KernelRebuildResult {
4
- runtime: KernelRuntimeHandle;
5
- cursor: KernelOperationCursor;
6
- }
7
- /**
8
- * Deterministically fold an authoritative operation stream into a fresh runtime.
9
- *
10
- * The caller owns runtime construction, but its initial policy and replay-affecting defaults must
11
- * exactly match genesis. A failure leaves the supplied runtime unusable; callers must discard it.
12
- */
13
- export declare function rebuildKernelRuntime(runtime: KernelRuntimeHandle, genesis: KernelOperationGenesis, transactions: readonly KernelTransaction[]): KernelRebuildResult;
@@ -1,75 +0,0 @@
1
- import { KernelLogIntegrityError, kernelRecordDigest, verifyKernelTransactionStream, } from "./kernel-transaction-log.js";
2
- /**
3
- * Deterministically fold an authoritative operation stream into a fresh runtime.
4
- *
5
- * The caller owns runtime construction, but its initial policy and replay-affecting defaults must
6
- * exactly match genesis. A failure leaves the supplied runtime unusable; callers must discard it.
7
- */
8
- export function rebuildKernelRuntime(runtime, genesis, transactions) {
9
- const cursor = verifyKernelTransactionStream(genesis, transactions);
10
- assertFreshRuntimeMatchesGenesis(runtime, genesis);
11
- for (const transaction of transactions) {
12
- const prepared = JSON.parse(runtime.prepareStep(JSON.stringify(transaction.input)));
13
- const token = prepared.prepare_token;
14
- try {
15
- if (prepared.status !== "prepared" || !token) {
16
- throw new KernelLogIntegrityError(`kernel rebuild step ${transaction.step_seq} was not accepted as a new transition`);
17
- }
18
- if (prepared.base_generation !== transaction.base_generation) {
19
- throw new KernelLogIntegrityError(`kernel rebuild generation ${prepared.base_generation} does not match transaction ${transaction.base_generation}`);
20
- }
21
- if (prepared.step.step_seq !== transaction.step_seq) {
22
- throw new KernelLogIntegrityError(`kernel rebuild step_seq ${prepared.step.step_seq} does not match transaction ${transaction.step_seq}`);
23
- }
24
- if (kernelRecordDigest(prepared.input) !== transaction.input_digest) {
25
- throw new KernelLogIntegrityError(`kernel rebuild normalized input diverged at step ${transaction.step_seq}`);
26
- }
27
- if (kernelRecordDigest(prepared.step) !== transaction.step_digest) {
28
- throw new KernelLogIntegrityError(`kernel rebuild planned step diverged at step ${transaction.step_seq}`);
29
- }
30
- const committed = JSON.parse(runtime.commitPrepared(token));
31
- if (kernelRecordDigest(committed) !== transaction.step_digest) {
32
- throw new KernelLogIntegrityError(`kernel rebuild committed step diverged at step ${transaction.step_seq}`);
33
- }
34
- }
35
- catch (error) {
36
- if (token && prepared.status === "prepared") {
37
- try {
38
- runtime.abortPrepared(token);
39
- }
40
- catch {
41
- // The caller must discard a failed rebuild runtime; preserve the primary integrity error.
42
- }
43
- }
44
- throw error;
45
- }
46
- }
47
- return { runtime, cursor };
48
- }
49
- function assertFreshRuntimeMatchesGenesis(runtime, genesis) {
50
- const snapshot = JSON.parse(runtime.snapshot());
51
- if (snapshot.abi_version !== genesis.abi_version) {
52
- throw new KernelLogIntegrityError("kernel runtime ABI version does not match operation genesis");
53
- }
54
- if (genesis.default_policy_version !== 1) {
55
- throw new KernelLogIntegrityError("kernel operation uses an unsupported default policy version");
56
- }
57
- if (snapshot.operation_id || snapshot.next_step_seq !== 1 || snapshot.accepted_inputs.length !== 0) {
58
- throw new KernelLogIntegrityError("kernel rebuild requires a fresh runtime");
59
- }
60
- if (kernelRecordDigest(snapshot.initial_policy) !== kernelRecordDigest(genesis.initial_scheduler_policy)) {
61
- throw new KernelLogIntegrityError("kernel runtime initial policy does not match operation genesis");
62
- }
63
- const defaults = resolvedRuntimeDefaults(snapshot);
64
- if (kernelRecordDigest(defaults) !== kernelRecordDigest(genesis.resolved_runtime_defaults)) {
65
- throw new KernelLogIntegrityError("kernel runtime defaults do not match operation genesis");
66
- }
67
- }
68
- function resolvedRuntimeDefaults(snapshot) {
69
- return {
70
- snapshot_version: snapshot.snapshot_version,
71
- snapshot_input_limit: snapshot.snapshot_input_limit,
72
- max_input_bytes: snapshot.max_input_bytes,
73
- snapshot_journal_bytes_limit: snapshot.snapshot_journal_bytes_limit,
74
- };
75
- }
@@ -1,61 +0,0 @@
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): 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): void;
58
- export declare function verifyKernelTransaction(transaction: KernelTransaction): 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[]): KernelOperationCursor;
@@ -1,149 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- export const KERNEL_LOG_RECORD_VERSION = 1;
3
- export class KernelLogConflictError extends Error {
4
- constructor(message) {
5
- super(message);
6
- this.name = "KernelLogConflictError";
7
- }
8
- }
9
- export class KernelLogIntegrityError extends Error {
10
- constructor(message) {
11
- super(message);
12
- this.name = "KernelLogIntegrityError";
13
- }
14
- }
15
- export function canonicalKernelJson(value) {
16
- if (value === null)
17
- return "null";
18
- if (typeof value === "string" || typeof value === "boolean")
19
- return JSON.stringify(value);
20
- if (typeof value === "number") {
21
- if (!Number.isFinite(value))
22
- throw new KernelLogIntegrityError("canonical records require finite numbers");
23
- if (Number.isSafeInteger(value))
24
- return JSON.stringify(Object.is(value, -0) ? 0 : value);
25
- if (Number.isInteger(value)) {
26
- throw new KernelLogIntegrityError("canonical record integer exceeds the cross-SDK safe range");
27
- }
28
- const bytes = new Uint8Array(8);
29
- new DataView(bytes.buffer).setFloat64(0, value, false);
30
- return `f64:${Array.from(bytes, byte => byte.toString(16).padStart(2, "0")).join("")}`;
31
- }
32
- if (Array.isArray(value))
33
- return `[${value.map(canonicalKernelJson).join(",")}]`;
34
- if (typeof value === "object") {
35
- const object = value;
36
- const keys = Object.keys(object).sort();
37
- return `{${keys.map(key => `${JSON.stringify(key)}:${canonicalKernelJson(object[key])}`).join(",")}}`;
38
- }
39
- throw new KernelLogIntegrityError(`unsupported canonical record value: ${typeof value}`);
40
- }
41
- export function kernelRecordDigest(value) {
42
- return createHash("sha256").update(canonicalKernelJson(value), "utf8").digest("hex");
43
- }
44
- export async function createKernelOperationGenesis(input) {
45
- const body = {
46
- record_version: KERNEL_LOG_RECORD_VERSION,
47
- ...input,
48
- };
49
- validateGenesisBody(body);
50
- return { ...body, genesis_digest: kernelRecordDigest(body) };
51
- }
52
- export async function createKernelTransaction(input) {
53
- const body = {
54
- record_version: KERNEL_LOG_RECORD_VERSION,
55
- operation_id: input.operation_id,
56
- step_seq: input.step_seq,
57
- base_generation: input.base_generation,
58
- input: input.input,
59
- input_digest: kernelRecordDigest(input.input),
60
- previous_transaction_digest: input.previous_transaction_digest,
61
- step_digest: kernelRecordDigest(input.step),
62
- };
63
- validateTransactionBody(body);
64
- return { ...body, transaction_digest: kernelRecordDigest(body) };
65
- }
66
- export function verifyKernelOperationGenesis(genesis) {
67
- const { genesis_digest, ...body } = genesis;
68
- validateGenesisBody(body);
69
- if (kernelRecordDigest(body) !== genesis_digest) {
70
- throw new KernelLogIntegrityError("kernel genesis digest does not match its canonical body");
71
- }
72
- }
73
- export function verifyKernelTransaction(transaction) {
74
- const { transaction_digest, ...body } = transaction;
75
- validateTransactionBody(body);
76
- if (kernelRecordDigest(body.input) !== body.input_digest) {
77
- throw new KernelLogIntegrityError("kernel transaction input digest does not match its input");
78
- }
79
- if (kernelRecordDigest(body) !== transaction_digest) {
80
- throw new KernelLogIntegrityError("kernel transaction digest does not match its canonical body");
81
- }
82
- }
83
- export function verifyKernelTransactionSuccessor(previous, transaction) {
84
- const expectedStepSeq = previous ? previous.step_seq + 1 : 1;
85
- const expectedGeneration = previous ? previous.base_generation + 1 : 0;
86
- if (transaction.step_seq !== expectedStepSeq) {
87
- throw new KernelLogIntegrityError(`kernel transaction step_seq ${transaction.step_seq} does not follow ${expectedStepSeq - 1}`);
88
- }
89
- if (transaction.base_generation !== expectedGeneration) {
90
- throw new KernelLogIntegrityError(`kernel transaction base_generation ${transaction.base_generation} does not match ${expectedGeneration}`);
91
- }
92
- if (transaction.input.operation_id !== transaction.operation_id) {
93
- throw new KernelLogIntegrityError("kernel transaction input operation_id does not match its envelope");
94
- }
95
- }
96
- /** Validate one complete authoritative operation stream and derive its next wire cursor. */
97
- export function verifyKernelTransactionStream(genesis, transactions) {
98
- verifyKernelOperationGenesis(genesis);
99
- let previous;
100
- let head = genesis.genesis_digest;
101
- for (const transaction of transactions) {
102
- verifyKernelTransaction(transaction);
103
- if (transaction.operation_id !== genesis.operation_id) {
104
- throw new KernelLogIntegrityError("kernel transaction operation_id does not match genesis");
105
- }
106
- if (transaction.previous_transaction_digest !== head) {
107
- throw new KernelLogIntegrityError("kernel transaction digest chain is not continuous");
108
- }
109
- verifyKernelTransactionSuccessor(previous, transaction);
110
- previous = transaction;
111
- head = transaction.transaction_digest;
112
- }
113
- const nextSequence = (previous?.step_seq ?? 0) + 1;
114
- return {
115
- operation_id: genesis.operation_id,
116
- next_event_sequence: nextSequence,
117
- next_step_seq: nextSequence,
118
- transaction_head_digest: head,
119
- };
120
- }
121
- function validateGenesisBody(genesis) {
122
- if (genesis.record_version !== KERNEL_LOG_RECORD_VERSION) {
123
- throw new KernelLogIntegrityError("unsupported kernel genesis record version");
124
- }
125
- if (!Number.isSafeInteger(genesis.abi_version) || genesis.abi_version <= 0) {
126
- throw new KernelLogIntegrityError("kernel genesis abi_version must be a positive safe integer");
127
- }
128
- if (!genesis.operation_id)
129
- throw new KernelLogIntegrityError("kernel genesis operation_id is required");
130
- if (!Number.isSafeInteger(genesis.default_policy_version) || genesis.default_policy_version <= 0) {
131
- throw new KernelLogIntegrityError("kernel genesis default_policy_version must be a positive safe integer");
132
- }
133
- }
134
- function validateTransactionBody(transaction) {
135
- if (transaction.record_version !== KERNEL_LOG_RECORD_VERSION) {
136
- throw new KernelLogIntegrityError("unsupported kernel transaction record version");
137
- }
138
- if (!transaction.operation_id)
139
- throw new KernelLogIntegrityError("kernel transaction operation_id is required");
140
- if (!Number.isSafeInteger(transaction.step_seq) || transaction.step_seq <= 0) {
141
- throw new KernelLogIntegrityError("kernel transaction step_seq must be a positive safe integer");
142
- }
143
- if (!Number.isSafeInteger(transaction.base_generation) || transaction.base_generation < 0) {
144
- throw new KernelLogIntegrityError("kernel transaction base_generation must be a non-negative safe integer");
145
- }
146
- if (!transaction.previous_transaction_digest) {
147
- throw new KernelLogIntegrityError("kernel transaction previous_transaction_digest is required");
148
- }
149
- }
@@ -1,93 +0,0 @@
1
- /**
2
- * Large result spool (Layer 1 of 5-layer compression pyramid).
3
- *
4
- * When a single tool result exceeds 50KB, write the full content to disk
5
- * and keep only a 2KB preview in the message. Zero API overhead.
6
- *
7
- * Design principles:
8
- * - Kernel defines policy (thresholds)
9
- * - SDK performs I/O (disk write/read)
10
- * - Model can retrieve full content via Read tool when needed
11
- */
12
- export interface ToolResult {
13
- callId: string;
14
- tool: string;
15
- output: string;
16
- isError?: boolean;
17
- }
18
- export interface SpooledToolResult {
19
- originalOutput: string;
20
- preview: string;
21
- spoolRef: string;
22
- wasSpooled: boolean;
23
- }
24
- /**
25
- * Large result spool configuration (mirrors kernel ContextConfig).
26
- */
27
- export interface SpoolConfig {
28
- /** Single result size threshold (bytes) */
29
- spoolThresholdBytes: number;
30
- /** Preview token count (~2KB) */
31
- previewTokens: number;
32
- /** Total message limit (bytes) */
33
- totalMessageLimitBytes: number;
34
- /** Custom spool directory path */
35
- spoolDir?: string;
36
- /** Maximum age of spooled files (default 7 days) */
37
- maxAgeMs?: number;
38
- }
39
- export declare const DEFAULT_SPOOL_CONFIG: SpoolConfig;
40
- /**
41
- * Large result spool manager.
42
- */
43
- export declare class LargeResultSpool {
44
- private config;
45
- private spoolDir;
46
- private activeWrites;
47
- constructor(config?: Partial<SpoolConfig>);
48
- /**
49
- * Check if a tool result needs spooling.
50
- */
51
- private needsSpool;
52
- /**
53
- * Hash content for spool reference.
54
- */
55
- private hashContent;
56
- /**
57
- * Get spool file path for a hash.
58
- */
59
- private getSpoolPath;
60
- private callKey;
61
- private atomicWrite;
62
- /**
63
- * Write large result to disk.
64
- */
65
- private writeToDisk;
66
- /**
67
- * Generate preview for a tool result.
68
- */
69
- private generatePreview;
70
- /**
71
- * Process a tool result: spool if large, return spooled result.
72
- */
73
- processToolResult(result: ToolResult): Promise<SpooledToolResult>;
74
- /**
75
- * Persist a kernel-spooled tool output to disk. Returns the on-disk path ref.
76
- */
77
- persistOutput(sessionId: string, callId: string, content: string): Promise<string>;
78
- /**
79
- * Read a spooled result back from disk.
80
- */
81
- readSpooledResult(spoolRef: string): Promise<string>;
82
- /**
83
- * O7: locate a spooled output by the tool call's id (the `read_result` meta-tool only knows
84
- * `call_id`, not the content-hashed file name `persistOutput` chose). Scans the spool directory
85
- * for the hashed call-key prefix; returns `undefined` if nothing was ever spooled
86
- * for that call (e.g. it never actually exceeded the threshold, or the spool dir was cleaned up).
87
- */
88
- findByCallId(sessionId: string, callId: string): Promise<string | undefined>;
89
- /**
90
- * Clean up old spool files (optional maintenance).
91
- */
92
- cleanup(maxAgeMs?: number): Promise<number>;
93
- }