@deepstrike/sdk 0.2.38 → 0.2.40

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 +61 -31
  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 +3 -1
  31. package/dist/memory/public.js +1 -0
  32. package/dist/memory/ranking.d.ts +33 -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 +3 -3
  37. package/dist/os/public.js +1 -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,5 +1,11 @@
1
1
  import type { KernelPrimitive } from "./kernel-event-log.js";
2
2
  import type { ContentPart, ProviderReplay, ToolCall, ToolErrorKind } from "../types.js";
3
+ import type { MemoryRecall, MemoryScope } from "../memory/protocols.js";
4
+ import type { DurableAppendReceipt, KernelGenesisReceipt, KernelOperationGenesis, KernelTransaction } from "./kernel-transaction-log.js";
5
+ export interface KernelTransactionEntry {
6
+ log_seq: number;
7
+ transaction: KernelTransaction;
8
+ }
3
9
  export type RollbackReason = {
4
10
  kind: "fatal_tool_error";
5
11
  tool_name: string;
@@ -79,7 +85,6 @@ export type SessionEvent = {
79
85
  action?: "snip_compact" | "micro_compact" | "context_collapse" | "auto_compact";
80
86
  summary?: string;
81
87
  summary_tokens?: number;
82
- archive_ref?: string;
83
88
  preserved_refs?: string[];
84
89
  } | {
85
90
  kind: "page_out";
@@ -88,6 +93,7 @@ export type SessionEvent = {
88
93
  summary?: string;
89
94
  tier_hint?: string;
90
95
  message_count?: number;
96
+ archive_ref?: string;
91
97
  } | {
92
98
  kind: "page_in";
93
99
  turn: number;
@@ -137,8 +143,11 @@ export type SessionEvent = {
137
143
  tool: string;
138
144
  reason: string;
139
145
  } | {
140
- kind: "signal_disposed";
146
+ kind: "signal_delivery_disposed";
141
147
  turn: number;
148
+ operation_id: string;
149
+ delivery_id: string;
150
+ attempt: number;
142
151
  signal_id: string;
143
152
  disposition: string;
144
153
  queue_depth: number;
@@ -146,6 +155,22 @@ export type SessionEvent = {
146
155
  kind: "budget_exceeded";
147
156
  turn: number;
148
157
  budget: string;
158
+ operation_id: string;
159
+ reservation_id?: string;
160
+ } | {
161
+ kind: "budget_usage_reported";
162
+ turn: number;
163
+ operation_id: string;
164
+ reservation_id: string;
165
+ tokens: number;
166
+ subagents: number;
167
+ rounds: number;
168
+ } | {
169
+ kind: "operation_cancelled";
170
+ turn: number;
171
+ operation_id: string;
172
+ reason: "user" | "deadline" | "lease_lost" | "host_shutdown";
173
+ pending_call_ids: string[];
149
174
  } | {
150
175
  kind: "milestone_advanced";
151
176
  turn: number;
@@ -189,37 +214,49 @@ export type SessionEvent = {
189
214
  } | {
190
215
  kind: "memory_written";
191
216
  turn: number;
192
- memory_id: string;
217
+ record_id: string;
218
+ scope: MemoryScope;
193
219
  memory_kind: string;
220
+ name: string;
194
221
  size_bytes: number;
195
222
  } | {
196
223
  kind: "memory_queried";
197
224
  turn: number;
198
- query_context: string;
225
+ scope: MemoryScope;
226
+ query: string;
199
227
  requested_k: number;
200
228
  requires_async_response: boolean;
201
229
  } | {
202
230
  kind: "memory_validation_failed";
203
231
  turn: number;
204
- memory_id: string;
232
+ record_id: string;
233
+ error: string;
234
+ } | {
235
+ kind: "memory_write_failed";
236
+ turn: number;
237
+ record_id: string;
238
+ error: string;
239
+ } | {
240
+ kind: "memory_query_failed";
241
+ turn: number;
242
+ scope: MemoryScope;
243
+ query: string;
205
244
  error: string;
206
245
  } | {
207
246
  kind: "memory_retrieval_result";
208
- selected_memory_ids: string[];
209
- selection_rationale: string;
247
+ hits: MemoryRecall[];
210
248
  } | {
211
249
  kind: "workflow_node_completed";
212
250
  turn: number;
213
251
  agent_id: string;
252
+ status: import("../types/agent.js").WorkflowNodeStatus;
214
253
  termination: string;
215
254
  /** W-1: result-borne control signals, persisted so resume replays control flow faithfully —
216
255
  * a classifier re-prunes its rejected branches, a recorded loop stop is honored. */
217
256
  classify_branch?: string;
218
257
  tournament_winner?: string;
219
258
  loop_continue?: boolean;
220
- /** W-1: the node's final output text — resume re-seeds the driver's outputs map from it so
221
- * post-resume reduce/judge/dependent nodes still see their dependencies' outputs. */
222
- output?: string;
259
+ output?: import("../types.js").Message;
223
260
  } | {
224
261
  kind: "workflow_nodes_submitted";
225
262
  turn: number;
@@ -239,8 +276,7 @@ export type SessionEvent = {
239
276
  } | {
240
277
  kind: "workflow_completed";
241
278
  turn: number;
242
- completed: string[];
243
- failed: string[];
279
+ node_outcomes: import("../types/agent.js").KernelWorkflowNodeOutcome[];
244
280
  total_nodes: number;
245
281
  } | {
246
282
  kind: "run_terminal";
@@ -283,19 +319,35 @@ export interface SessionLog {
283
319
  event: SessionEvent;
284
320
  }>>;
285
321
  latestSeq(sessionId: string): Promise<number>;
322
+ appendKernelGenesis(sessionId: string, genesis: KernelOperationGenesis): Promise<KernelGenesisReceipt>;
323
+ readKernelGenesis(sessionId: string, operationId: string): Promise<KernelOperationGenesis | undefined>;
324
+ compareAndAppendKernelTransaction(sessionId: string, expectedTransactionHead: string, transaction: KernelTransaction): Promise<DurableAppendReceipt>;
325
+ readKernelTransactions(sessionId: string, operationId: string, fromStepSeq?: number): Promise<KernelTransactionEntry[]>;
326
+ kernelTransactionHead(sessionId: string, operationId: string): Promise<string | undefined>;
286
327
  }
287
328
  export declare class InMemorySessionLog implements SessionLog {
288
329
  private store;
330
+ private seqCounters;
331
+ private genesisStore;
332
+ private transactionStore;
333
+ private operationKey;
334
+ private nextSeq;
289
335
  append(sessionId: string, event: SessionEvent): Promise<number>;
290
336
  read(sessionId: string, fromSeq?: number, primitiveFilter?: KernelPrimitive): Promise<Array<{
291
337
  seq: number;
292
338
  event: SessionEvent;
293
339
  }>>;
294
340
  latestSeq(sessionId: string): Promise<number>;
341
+ appendKernelGenesis(sessionId: string, genesis: KernelOperationGenesis): Promise<KernelGenesisReceipt>;
342
+ readKernelGenesis(sessionId: string, operationId: string): Promise<KernelOperationGenesis | undefined>;
343
+ compareAndAppendKernelTransaction(sessionId: string, expectedTransactionHead: string, transaction: KernelTransaction): Promise<DurableAppendReceipt>;
344
+ readKernelTransactions(sessionId: string, operationId: string, fromStepSeq?: number): Promise<KernelTransactionEntry[]>;
345
+ kernelTransactionHead(sessionId: string, operationId: string): Promise<string | undefined>;
295
346
  }
296
347
  export declare class FileSessionLog implements SessionLog {
297
348
  private dir;
298
349
  private seqCounters;
350
+ private readonly appends;
299
351
  constructor(dir: string);
300
352
  private path;
301
353
  private nextSeq;
@@ -305,4 +357,11 @@ export declare class FileSessionLog implements SessionLog {
305
357
  event: SessionEvent;
306
358
  }>>;
307
359
  latestSeq(sessionId: string): Promise<number>;
360
+ appendKernelGenesis(sessionId: string, genesis: KernelOperationGenesis): Promise<KernelGenesisReceipt>;
361
+ readKernelGenesis(sessionId: string, operationId: string): Promise<KernelOperationGenesis | undefined>;
362
+ compareAndAppendKernelTransaction(sessionId: string, expectedTransactionHead: string, transaction: KernelTransaction): Promise<DurableAppendReceipt>;
363
+ readKernelTransactions(sessionId: string, operationId: string, fromStepSeq?: number): Promise<KernelTransactionEntry[]>;
364
+ kernelTransactionHead(sessionId: string, operationId: string): Promise<string | undefined>;
365
+ private appendRecord;
366
+ private readRecords;
308
367
  }
@@ -1,15 +1,28 @@
1
- import { createWriteStream, createReadStream } from "node:fs";
2
- import { mkdir } from "node:fs/promises";
1
+ import { createReadStream } from "node:fs";
2
+ import { access, mkdir, open as openFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { createInterface } from "node:readline";
5
5
  import { primitiveForKind } from "./kernel-event-log.js";
6
+ import { KeyedSerialExecutor } from "./reliability.js";
7
+ import { KernelLogConflictError, KernelLogIntegrityError, verifyKernelOperationGenesis, verifyKernelTransaction, verifyKernelTransactionSuccessor, } from "./kernel-transaction-log.js";
6
8
  export class InMemorySessionLog {
7
9
  store = new Map();
10
+ seqCounters = new Map();
11
+ genesisStore = new Map();
12
+ transactionStore = new Map();
13
+ operationKey(sessionId, operationId) {
14
+ return `${sessionId}\u0000${operationId}`;
15
+ }
16
+ nextSeq(sessionId) {
17
+ const seq = this.seqCounters.get(sessionId) ?? 0;
18
+ this.seqCounters.set(sessionId, seq + 1);
19
+ return seq;
20
+ }
8
21
  async append(sessionId, event) {
9
22
  if (!this.store.has(sessionId))
10
23
  this.store.set(sessionId, []);
11
24
  const entries = this.store.get(sessionId);
12
- const seq = entries.length;
25
+ const seq = this.nextSeq(sessionId);
13
26
  entries.push({ seq, event });
14
27
  return seq;
15
28
  }
@@ -24,8 +37,53 @@ export class InMemorySessionLog {
24
37
  });
25
38
  }
26
39
  async latestSeq(sessionId) {
27
- const entries = this.store.get(sessionId);
28
- return entries ? entries.length - 1 : -1;
40
+ return (this.seqCounters.get(sessionId) ?? 0) - 1;
41
+ }
42
+ async appendKernelGenesis(sessionId, genesis) {
43
+ verifyKernelOperationGenesis(genesis);
44
+ const operationKey = this.operationKey(sessionId, genesis.operation_id);
45
+ const existing = this.genesisStore.get(operationKey);
46
+ if (existing) {
47
+ if (existing.genesis.genesis_digest !== genesis.genesis_digest) {
48
+ throw new KernelLogConflictError("session already has a different kernel operation genesis");
49
+ }
50
+ return { log_seq: existing.log_seq, genesis_digest: genesis.genesis_digest };
51
+ }
52
+ const log_seq = this.nextSeq(sessionId);
53
+ this.genesisStore.set(operationKey, { log_seq, genesis });
54
+ return { log_seq, genesis_digest: genesis.genesis_digest };
55
+ }
56
+ async readKernelGenesis(sessionId, operationId) {
57
+ return this.genesisStore.get(this.operationKey(sessionId, operationId))?.genesis;
58
+ }
59
+ async compareAndAppendKernelTransaction(sessionId, expectedTransactionHead, transaction) {
60
+ verifyKernelTransaction(transaction);
61
+ const operationKey = this.operationKey(sessionId, transaction.operation_id);
62
+ const genesis = this.genesisStore.get(operationKey)?.genesis;
63
+ if (!genesis)
64
+ throw new KernelLogIntegrityError("kernel transaction requires a durable genesis");
65
+ if (transaction.operation_id !== genesis.operation_id) {
66
+ throw new KernelLogIntegrityError("kernel transaction operation_id does not match genesis");
67
+ }
68
+ const head = await this.kernelTransactionHead(sessionId, transaction.operation_id);
69
+ if (head !== expectedTransactionHead || transaction.previous_transaction_digest !== head) {
70
+ throw new KernelLogConflictError("kernel transaction head changed before compare-and-append");
71
+ }
72
+ const entries = this.transactionStore.get(operationKey) ?? [];
73
+ verifyKernelTransactionSuccessor(entries.at(-1)?.transaction, transaction);
74
+ const log_seq = this.nextSeq(sessionId);
75
+ entries.push({ log_seq, transaction });
76
+ this.transactionStore.set(operationKey, entries);
77
+ return { log_seq, transaction_digest: transaction.transaction_digest };
78
+ }
79
+ async readKernelTransactions(sessionId, operationId, fromStepSeq = 1) {
80
+ return (this.transactionStore.get(this.operationKey(sessionId, operationId)) ?? []).filter(entry => entry.transaction.step_seq >= fromStepSeq);
81
+ }
82
+ async kernelTransactionHead(sessionId, operationId) {
83
+ const operationKey = this.operationKey(sessionId, operationId);
84
+ const entries = this.transactionStore.get(operationKey) ?? [];
85
+ return entries.at(-1)?.transaction.transaction_digest
86
+ ?? this.genesisStore.get(operationKey)?.genesis.genesis_digest;
29
87
  }
30
88
  }
31
89
  // Single-writer per session. Safe for concurrent appends within one instance.
@@ -34,6 +92,7 @@ export class FileSessionLog {
34
92
  dir;
35
93
  // Lazy-initialized per-session counter. Avoids re-reading the file on every append.
36
94
  seqCounters = new Map();
95
+ appends = new KeyedSerialExecutor();
37
96
  constructor(dir) {
38
97
  this.dir = dir;
39
98
  }
@@ -42,54 +101,155 @@ export class FileSessionLog {
42
101
  }
43
102
  async nextSeq(sessionId) {
44
103
  if (!this.seqCounters.has(sessionId)) {
45
- const existing = await this.read(sessionId);
46
- this.seqCounters.set(sessionId, existing.length);
104
+ const existing = await this.readRecords(sessionId);
105
+ this.seqCounters.set(sessionId, existing.reduce((next, record) => Math.max(next, record.seq + 1), 0));
47
106
  }
48
107
  const seq = this.seqCounters.get(sessionId);
49
108
  this.seqCounters.set(sessionId, seq + 1);
50
109
  return seq;
51
110
  }
52
111
  async append(sessionId, event) {
53
- await mkdir(this.dir, { recursive: true });
54
- const seq = await this.nextSeq(sessionId);
55
- await new Promise((resolve, reject) => {
56
- const ws = createWriteStream(this.path(sessionId), { flags: "a" });
57
- ws.write(JSON.stringify({ seq, event }) + "\n", err => {
58
- if (err)
59
- reject(err);
60
- else
61
- resolve();
62
- });
63
- ws.end();
112
+ return this.appends.run(sessionId, async () => {
113
+ const seq = await this.nextSeq(sessionId);
114
+ await this.appendRecord(sessionId, { seq, event });
115
+ return seq;
64
116
  });
65
- return seq;
66
117
  }
67
118
  async read(sessionId, fromSeq = 0, primitiveFilter) {
68
119
  const results = [];
120
+ for (const record of await this.readRecords(sessionId)) {
121
+ if (!("event" in record) || record.seq < fromSeq)
122
+ continue;
123
+ if (primitiveFilter && primitiveForKind(record.event.kind) !== primitiveFilter)
124
+ continue;
125
+ results.push({ seq: record.seq, event: record.event });
126
+ }
127
+ return results;
128
+ }
129
+ async latestSeq(sessionId) {
130
+ const records = await this.readRecords(sessionId);
131
+ return records.reduce((latest, record) => Math.max(latest, record.seq), -1);
132
+ }
133
+ async appendKernelGenesis(sessionId, genesis) {
134
+ return this.appends.run(sessionId, async () => {
135
+ verifyKernelOperationGenesis(genesis);
136
+ const existing = (await this.readRecords(sessionId)).find((record) => "record_type" in record
137
+ && record.record_type === "kernel_genesis"
138
+ && record.genesis.operation_id === genesis.operation_id);
139
+ if (existing) {
140
+ if (existing.genesis.genesis_digest !== genesis.genesis_digest) {
141
+ throw new KernelLogConflictError("session already has a different kernel operation genesis");
142
+ }
143
+ return { log_seq: existing.seq, genesis_digest: genesis.genesis_digest };
144
+ }
145
+ const log_seq = await this.nextSeq(sessionId);
146
+ await this.appendRecord(sessionId, {
147
+ seq: log_seq,
148
+ record_type: "kernel_genesis",
149
+ genesis,
150
+ });
151
+ return { log_seq, genesis_digest: genesis.genesis_digest };
152
+ });
153
+ }
154
+ async readKernelGenesis(sessionId, operationId) {
155
+ const record = (await this.readRecords(sessionId)).find((entry) => "record_type" in entry
156
+ && entry.record_type === "kernel_genesis"
157
+ && entry.genesis.operation_id === operationId);
158
+ return record?.genesis;
159
+ }
160
+ async compareAndAppendKernelTransaction(sessionId, expectedTransactionHead, transaction) {
161
+ return this.appends.run(sessionId, async () => {
162
+ verifyKernelTransaction(transaction);
163
+ const records = await this.readRecords(sessionId);
164
+ const genesisRecord = records.find((record) => "record_type" in record
165
+ && record.record_type === "kernel_genesis"
166
+ && record.genesis.operation_id === transaction.operation_id);
167
+ if (!genesisRecord)
168
+ throw new KernelLogIntegrityError("kernel transaction requires a durable genesis");
169
+ if (transaction.operation_id !== genesisRecord.genesis.operation_id) {
170
+ throw new KernelLogIntegrityError("kernel transaction operation_id does not match genesis");
171
+ }
172
+ const transactions = records.filter((record) => "record_type" in record
173
+ && record.record_type === "kernel_transaction"
174
+ && record.transaction.operation_id === transaction.operation_id);
175
+ const head = transactions.at(-1)?.transaction.transaction_digest
176
+ ?? genesisRecord.genesis.genesis_digest;
177
+ if (head !== expectedTransactionHead || transaction.previous_transaction_digest !== head) {
178
+ throw new KernelLogConflictError("kernel transaction head changed before compare-and-append");
179
+ }
180
+ verifyKernelTransactionSuccessor(transactions.at(-1)?.transaction, transaction);
181
+ const log_seq = await this.nextSeq(sessionId);
182
+ await this.appendRecord(sessionId, {
183
+ seq: log_seq,
184
+ record_type: "kernel_transaction",
185
+ transaction,
186
+ });
187
+ return { log_seq, transaction_digest: transaction.transaction_digest };
188
+ });
189
+ }
190
+ async readKernelTransactions(sessionId, operationId, fromStepSeq = 1) {
191
+ return (await this.readRecords(sessionId))
192
+ .filter((record) => "record_type" in record
193
+ && record.record_type === "kernel_transaction"
194
+ && record.transaction.operation_id === operationId
195
+ && record.transaction.step_seq >= fromStepSeq)
196
+ .map(record => ({ log_seq: record.seq, transaction: record.transaction }));
197
+ }
198
+ async kernelTransactionHead(sessionId, operationId) {
199
+ const records = await this.readRecords(sessionId);
200
+ const transaction = records.filter((record) => "record_type" in record
201
+ && record.record_type === "kernel_transaction"
202
+ && record.transaction.operation_id === operationId).at(-1);
203
+ if (transaction)
204
+ return transaction.transaction.transaction_digest;
205
+ return records.find((record) => "record_type" in record
206
+ && record.record_type === "kernel_genesis"
207
+ && record.genesis.operation_id === operationId)?.genesis.genesis_digest;
208
+ }
209
+ async appendRecord(sessionId, record) {
210
+ await mkdir(this.dir, { recursive: true });
211
+ const path = this.path(sessionId);
212
+ let isNewFile = false;
213
+ try {
214
+ await access(path);
215
+ }
216
+ catch {
217
+ isNewFile = true;
218
+ }
219
+ const file = await openFile(path, "a");
220
+ try {
221
+ await file.appendFile(`${JSON.stringify(record)}\n`, "utf8");
222
+ await file.sync();
223
+ }
224
+ finally {
225
+ await file.close();
226
+ }
227
+ if (isNewFile) {
228
+ const directory = await openFile(this.dir, "r");
229
+ try {
230
+ await directory.sync();
231
+ }
232
+ finally {
233
+ await directory.close();
234
+ }
235
+ }
236
+ }
237
+ async readRecords(sessionId) {
238
+ const records = [];
69
239
  try {
70
240
  const rl = createInterface({
71
241
  input: createReadStream(this.path(sessionId)),
72
242
  crlfDelay: Infinity,
73
243
  });
74
244
  for await (const line of rl) {
75
- if (!line.trim())
76
- continue;
77
- const entry = JSON.parse(line);
78
- if (entry.seq >= fromSeq) {
79
- if (primitiveFilter && primitiveForKind(entry.event.kind) !== primitiveFilter)
80
- continue;
81
- results.push(entry);
82
- }
245
+ if (line.trim())
246
+ records.push(JSON.parse(line));
83
247
  }
84
248
  }
85
249
  catch (err) {
86
250
  if (err.code !== "ENOENT")
87
251
  throw err;
88
252
  }
89
- return results;
90
- }
91
- async latestSeq(sessionId) {
92
- const entries = await this.read(sessionId);
93
- return entries.length - 1;
253
+ return records;
94
254
  }
95
255
  }
@@ -1,5 +1,6 @@
1
- import type { ProviderReplay, ToolCall } from "../types.js";
1
+ import type { Message, ProviderReplay, ToolCall } from "../types.js";
2
2
  import type { SessionEvent } from "./session-log.js";
3
+ import type { WorkflowNodeStatus } from "../types/agent.js";
3
4
  export { REPLAY_CONTENT_MAX_BYTES as RECOVERY_CONTENT_MAX_BYTES } from "./replay-sanitize.js";
4
5
  /**
5
6
  * Normalize a persisted llm_completed event for recovery.
@@ -46,33 +47,36 @@ export declare function buildRunTerminalEvent(input: {
46
47
  export declare function buildWorkflowNodeCompletedEvent(input: {
47
48
  turn: number;
48
49
  agentId: string;
50
+ status: WorkflowNodeStatus;
49
51
  termination: string;
50
52
  classifyBranch?: string;
51
53
  tournamentWinner?: string;
52
54
  loopContinue?: boolean;
53
- output?: string;
55
+ output?: Message;
54
56
  }): Extract<SessionEvent, {
55
57
  kind: "workflow_node_completed";
56
58
  }>;
57
59
  /** One recovered node completion: the agent id plus its persisted control signals and output. */
58
- export interface RecoveredNodeCompletion {
60
+ export interface RecoveredNodeOutcome {
59
61
  agentId: string;
62
+ status: WorkflowNodeStatus;
63
+ termination: string;
60
64
  classifyBranch?: string;
61
65
  tournamentWinner?: string;
62
66
  loopContinue?: boolean;
63
- output?: string;
67
+ output?: Message;
64
68
  }
65
69
  /**
66
70
  * Recover completed workflow node records from a session event stream. Scans for
67
71
  * workflow_node_completed events with termination "completed" and returns them WITH their
68
72
  * result-borne control signals (W-1) — resumeWorkflow lowers these to the kernel's
69
- * `resumed_results` so a classifier re-prunes and a loop stop is honored, and re-seeds the
73
+ * `resumed_outcomes` so a classifier re-prunes and a loop stop is honored, and re-seeds the
70
74
  * driver's outputs map from the persisted output text.
71
75
  */
72
- export declare function recoverCompletedWorkflowNodes(events: Array<{
76
+ export declare function recoverWorkflowNodeOutcomes(events: Array<{
73
77
  seq: number;
74
78
  event: SessionEvent;
75
- }>): RecoveredNodeCompletion[];
79
+ }>): RecoveredNodeOutcome[];
76
80
  /** R3-1: build workflow_nodes_submitted for persistence after a runtime submission, so resume can
77
81
  * re-apply it. `nodes` is the kernel-shape (snake_case) submitted node array. */
78
82
  export declare function buildWorkflowNodesSubmittedEvent(input: {
@@ -60,6 +60,7 @@ export function buildWorkflowNodeCompletedEvent(input) {
60
60
  kind: "workflow_node_completed",
61
61
  turn: input.turn,
62
62
  agent_id: input.agentId,
63
+ status: input.status,
63
64
  termination: input.termination,
64
65
  ...(input.classifyBranch !== undefined ? { classify_branch: input.classifyBranch } : {}),
65
66
  ...(input.tournamentWinner !== undefined ? { tournament_winner: input.tournamentWinner } : {}),
@@ -71,15 +72,17 @@ export function buildWorkflowNodeCompletedEvent(input) {
71
72
  * Recover completed workflow node records from a session event stream. Scans for
72
73
  * workflow_node_completed events with termination "completed" and returns them WITH their
73
74
  * result-borne control signals (W-1) — resumeWorkflow lowers these to the kernel's
74
- * `resumed_results` so a classifier re-prunes and a loop stop is honored, and re-seeds the
75
+ * `resumed_outcomes` so a classifier re-prunes and a loop stop is honored, and re-seeds the
75
76
  * driver's outputs map from the persisted output text.
76
77
  */
77
- export function recoverCompletedWorkflowNodes(events) {
78
+ export function recoverWorkflowNodeOutcomes(events) {
78
79
  const completed = [];
79
80
  for (const { event } of events) {
80
- if (event.kind === "workflow_node_completed" && event.termination === "completed") {
81
+ if (event.kind === "workflow_node_completed") {
81
82
  completed.push({
82
83
  agentId: event.agent_id,
84
+ status: event.status,
85
+ termination: event.termination,
83
86
  ...(event.classify_branch !== undefined ? { classifyBranch: event.classify_branch } : {}),
84
87
  ...(event.tournament_winner !== undefined ? { tournamentWinner: event.tournament_winner } : {}),
85
88
  ...(event.loop_continue !== undefined ? { loopContinue: event.loop_continue } : {}),
@@ -111,11 +114,11 @@ export function recoverSubmittedWorkflowNodes(events) {
111
114
  if (event.kind === "workflow_nodes_submitted") {
112
115
  submissions.push(event.nodes);
113
116
  submitters.push(event.submitter_agent_id);
114
- // Absent on legacy logs → order-only replay (bases array stays parallel-short only
115
- // if ALL records carry it; a mixed log degrades to order-only for safety).
116
- if (event.base_index !== undefined)
117
- bases.push(event.base_index);
117
+ if (event.base_index === undefined) {
118
+ throw new Error("workflow_nodes_submitted is missing required base_index");
119
+ }
120
+ bases.push(event.base_index);
118
121
  }
119
122
  }
120
- return { submissions, bases: bases.length === submissions.length ? bases : [], submitters };
123
+ return { submissions, bases, submitters };
121
124
  }
@@ -1,7 +1,8 @@
1
1
  import type { StreamEvent } from "../types.js";
2
- import type { AgentRunSpec, AgentProcessChangedObservation, SubAgentResult } from "../types/agent.js";
2
+ import type { AgentRunSpec, AgentProcessChangedObservation, LoopResult, SubAgentResult } from "../types/agent.js";
3
3
  import type { RuntimeOptions } from "./runner.js";
4
4
  import type { SessionLog } from "./session-log.js";
5
+ import type { AttemptOutcome } from "../harness/harness.js";
5
6
  export interface SubAgentRunContext {
6
7
  parentOpts: RuntimeOptions;
7
8
  parentSessionId: string;
@@ -27,6 +28,8 @@ export interface SubAgentRunContext {
27
28
  * `InterruptNow` → `AgentPreempted`), the orchestrator interrupts the child runner, cancelling its
28
29
  * in-flight LLM call. */
29
30
  abortSignal?: AbortSignal;
31
+ /** AttemptLoop carry material; injected through the child's journaled signal channel. */
32
+ contextInput?: string;
30
33
  }
31
34
  /** M1/G3 intelligence routing: resolve the provider for a sub-agent from its spec's `modelHint`.
32
35
  * Falls back to the parent provider when there is no hint or no `providerFor` hook resolves it. */
@@ -42,5 +45,6 @@ export declare class SubAgentOrchestrator {
42
45
  run(ctx: SubAgentRunContext): Promise<SubAgentResult>;
43
46
  }
44
47
  export declare const defaultSubAgentOrchestrator: SubAgentOrchestrator;
48
+ export declare function attemptOutcomeToLoopResult(outcome: AttemptOutcome): LoopResult;
45
49
  /** Kernel spawn without an active parent run loop (harness / coordinator use). */
46
- export declare function spawnStandalone(parentOpts: RuntimeOptions, parentSessionId: string, spec: AgentRunSpec, orchestrator?: SubAgentOrchestrator): Promise<SubAgentResult>;
50
+ export declare function spawnStandalone(parentOpts: RuntimeOptions, parentSessionId: string, spec: AgentRunSpec, orchestrator?: SubAgentOrchestrator, contextInput?: string): Promise<SubAgentResult>;