@deepstrike/sdk 0.2.39 → 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.
- package/README.md +61 -31
- package/dist/collaboration/contract.d.ts +2 -2
- package/dist/collaboration/contract.js +2 -2
- package/dist/collaboration/handoff.d.ts +2 -14
- package/dist/collaboration/handoff.js +1 -17
- package/dist/collaboration/harness.d.ts +16 -47
- package/dist/collaboration/harness.js +57 -158
- package/dist/collaboration/index.d.ts +2 -2
- package/dist/collaboration/index.js +1 -2
- package/dist/collaboration/modes/creator-verifier.js +42 -6
- package/dist/collaboration/pool.d.ts +8 -0
- package/dist/collaboration/pool.js +56 -3
- package/dist/harness/harness.d.ts +97 -97
- package/dist/harness/harness.js +190 -144
- package/dist/harness/judge.d.ts +3 -2
- package/dist/harness/judge.js +7 -3
- package/dist/harness/public.d.ts +5 -3
- package/dist/harness/public.js +3 -2
- package/dist/index.d.ts +22 -7
- package/dist/index.js +8 -1
- package/dist/kernel.d.ts +12 -39
- package/dist/memory/agent.d.ts +8 -41
- package/dist/memory/agent.js +34 -117
- package/dist/memory/extraction.d.ts +4 -0
- package/dist/memory/extraction.js +79 -0
- package/dist/memory/in-memory-store.d.ts +28 -15
- package/dist/memory/in-memory-store.js +74 -25
- package/dist/memory/protocols.d.ts +56 -56
- package/dist/memory/protocols.js +1 -0
- package/dist/memory/public.d.ts +3 -1
- package/dist/memory/public.js +1 -0
- package/dist/memory/ranking.d.ts +33 -0
- package/dist/memory/ranking.js +77 -0
- package/dist/memory/retention.d.ts +17 -0
- package/dist/memory/retention.js +54 -0
- package/dist/os/public.d.ts +3 -3
- package/dist/os/public.js +1 -1
- package/dist/providers/base.d.ts +8 -0
- package/dist/providers/base.js +0 -0
- package/dist/providers/gemini.js +12 -0
- package/dist/providers/ollama.js +3 -1
- package/dist/providers/openai-responses.js +9 -2
- package/dist/providers/profiles.d.ts +5 -3
- package/dist/providers/profiles.js +3 -3
- package/dist/runtime/context-policy.d.ts +35 -0
- package/dist/runtime/context-policy.js +66 -0
- package/dist/runtime/eval.d.ts +6 -2
- package/dist/runtime/eval.js +2 -2
- package/dist/runtime/event-stream.d.ts +9 -0
- package/dist/runtime/event-stream.js +25 -11
- package/dist/runtime/execution-plane.d.ts +5 -1
- package/dist/runtime/execution-plane.js +9 -3
- package/dist/runtime/facade.js +2 -1
- package/dist/runtime/kernel-event-log.d.ts +0 -2
- package/dist/runtime/kernel-event-log.js +61 -13
- package/dist/runtime/kernel-primitives-dashboard.js +1 -1
- package/dist/runtime/kernel-rebuild.d.ts +13 -0
- package/dist/runtime/kernel-rebuild.js +75 -0
- package/dist/runtime/kernel-step.d.ts +157 -8
- package/dist/runtime/kernel-step.js +220 -7
- package/dist/runtime/kernel-transaction-log.d.ts +61 -0
- package/dist/runtime/kernel-transaction-log.js +149 -0
- package/dist/runtime/large-result-spool.d.ts +3 -1
- package/dist/runtime/large-result-spool.js +24 -5
- package/dist/runtime/loop-driver.d.ts +1 -1
- package/dist/runtime/loop-driver.js +2 -7
- package/dist/runtime/mcp-proxy-plane.d.ts +1 -0
- package/dist/runtime/mcp-proxy-plane.js +23 -6
- package/dist/runtime/os-profile.d.ts +9 -10
- package/dist/runtime/os-profile.js +14 -10
- package/dist/runtime/os-snapshot.d.ts +19 -0
- package/dist/runtime/os-snapshot.js +33 -3
- package/dist/runtime/process-sandbox-plane.js +16 -11
- package/dist/runtime/reaction-checkpoint.d.ts +51 -0
- package/dist/runtime/reaction-checkpoint.js +83 -0
- package/dist/runtime/reactive-session.d.ts +9 -3
- package/dist/runtime/reactive-session.js +44 -14
- package/dist/runtime/reliability.d.ts +48 -0
- package/dist/runtime/reliability.js +86 -0
- package/dist/runtime/remote-vpc-plane.js +4 -3
- package/dist/runtime/run-group.d.ts +38 -35
- package/dist/runtime/run-group.js +97 -54
- package/dist/runtime/runner.d.ts +117 -78
- package/dist/runtime/runner.js +1516 -1197
- package/dist/runtime/session-log.d.ts +71 -12
- package/dist/runtime/session-log.js +192 -32
- package/dist/runtime/session-repair.d.ts +11 -7
- package/dist/runtime/session-repair.js +11 -8
- package/dist/runtime/sub-agent-orchestrator.d.ts +6 -2
- package/dist/runtime/sub-agent-orchestrator.js +45 -18
- package/dist/signals/gateway.d.ts +23 -10
- package/dist/signals/gateway.js +81 -17
- package/dist/signals/scheduled.js +0 -1
- package/dist/signals/types.d.ts +21 -13
- package/dist/skills/loader.js +12 -2
- package/dist/tools/index.d.ts +2 -0
- package/dist/types/agent.d.ts +40 -1
- package/dist/types/agent.js +61 -1
- package/dist/types.d.ts +6 -1
- package/dist/workflow/public.d.ts +2 -3
- package/dist/workflow/public.js +0 -1
- package/package.json +2 -2
package/dist/runtime/eval.d.ts
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Wraps the three kernel free functions `buildEvalMessages` / `parseVerdict` / `verdictOutputSchema`
|
|
5
5
|
* (folded out of the old EvalPipeline class in 0.5.0) into a small typed surface that's safe to
|
|
6
6
|
* call from a benchmark harness, a CI gate, or any caller that just wants "does this result meet
|
|
7
|
-
* the criteria?" without setting up `
|
|
7
|
+
* the criteria?" without setting up `AttemptLoop`.
|
|
8
8
|
*
|
|
9
9
|
* The judge is a single LLM call: build the eval prompt → stream → parse verdict. No retry loop,
|
|
10
|
-
* no skill extraction, no
|
|
10
|
+
* no skill extraction, no loop state. Use `AttemptLoop` if you want the retry/refine flow.
|
|
11
11
|
*/
|
|
12
12
|
import type { LLMProvider, Message } from "../types.js";
|
|
13
13
|
export interface Criterion {
|
|
@@ -17,6 +17,10 @@ export interface Criterion {
|
|
|
17
17
|
required?: boolean;
|
|
18
18
|
/** Optional weight for weighted scoring (kernel-defined semantics). */
|
|
19
19
|
weight?: number;
|
|
20
|
+
/** Stable host contract identifier, passed through to deterministic judges. */
|
|
21
|
+
id?: string;
|
|
22
|
+
/** Signals that the host can evaluate this criterion without an LLM. */
|
|
23
|
+
machineCheckable?: boolean;
|
|
20
24
|
}
|
|
21
25
|
export interface VerdictDetail {
|
|
22
26
|
criterion: string;
|
package/dist/runtime/eval.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Wraps the three kernel free functions `buildEvalMessages` / `parseVerdict` / `verdictOutputSchema`
|
|
5
5
|
* (folded out of the old EvalPipeline class in 0.5.0) into a small typed surface that's safe to
|
|
6
6
|
* call from a benchmark harness, a CI gate, or any caller that just wants "does this result meet
|
|
7
|
-
* the criteria?" without setting up `
|
|
7
|
+
* the criteria?" without setting up `AttemptLoop`.
|
|
8
8
|
*
|
|
9
9
|
* The judge is a single LLM call: build the eval prompt → stream → parse verdict. No retry loop,
|
|
10
|
-
* no skill extraction, no
|
|
10
|
+
* no skill extraction, no loop state. Use `AttemptLoop` if you want the retry/refine flow.
|
|
11
11
|
*/
|
|
12
12
|
import { getKernel } from "../kernel.js";
|
|
13
13
|
/**
|
|
@@ -7,10 +7,16 @@
|
|
|
7
7
|
* event to a subset of personas, enforced at the framework boundary (`readSince(seq, viewer)` + the
|
|
8
8
|
* `read_recent` tool) — context isolation, not convention.
|
|
9
9
|
*/
|
|
10
|
+
import type { ObserverErrorHandler } from "./reliability.js";
|
|
11
|
+
export interface EventStreamOptions {
|
|
12
|
+
onObserverError?: ObserverErrorHandler;
|
|
13
|
+
}
|
|
10
14
|
/** One entry on the shared blackboard. `channel`/`audience` are optional visibility scoping. */
|
|
11
15
|
export interface BlackboardEvent {
|
|
12
16
|
seq: number;
|
|
13
17
|
payload: unknown;
|
|
18
|
+
/** Stable external event key. Re-appending the same key returns the original event. */
|
|
19
|
+
idempotencyKey?: string;
|
|
14
20
|
/** Emitting persona id (or external source), for audit / `reactByMention`. */
|
|
15
21
|
source?: string;
|
|
16
22
|
/** Channel this event belongs to; only personas subscribed to it see it. Omit ⇒ all see it. */
|
|
@@ -36,8 +42,11 @@ export interface EventStream {
|
|
|
36
42
|
}
|
|
37
43
|
/** Process-local default blackboard. */
|
|
38
44
|
export declare class InMemoryEventStream implements EventStream {
|
|
45
|
+
private readonly opts;
|
|
39
46
|
private readonly events;
|
|
47
|
+
private readonly idempotentEvents;
|
|
40
48
|
private readonly listeners;
|
|
49
|
+
constructor(opts?: EventStreamOptions);
|
|
41
50
|
append(event: Omit<BlackboardEvent, "seq">): Promise<BlackboardEvent>;
|
|
42
51
|
readSince(seq: number, viewer?: EventViewer): Promise<BlackboardEvent[]>;
|
|
43
52
|
subscribe(cb: (e: BlackboardEvent) => void): () => void;
|
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* L2 (Blackboard) — a shared, append-only event stream that N peer agent sessions of one logical run
|
|
3
|
-
* observe. This is the pluggable storage seam (like `SessionLog`): the default `InMemoryEventStream`
|
|
4
|
-
* is process-local; back it with Postgres/Redis to span replicas/restarts.
|
|
5
|
-
*
|
|
6
|
-
* Visibility (spec §6.1): events are shared by default. Optional `channel` / `audience` tags scope an
|
|
7
|
-
* event to a subset of personas, enforced at the framework boundary (`readSince(seq, viewer)` + the
|
|
8
|
-
* `read_recent` tool) — context isolation, not convention.
|
|
9
|
-
*/
|
|
1
|
+
import { reportObserverFailure } from "./reliability.js";
|
|
10
2
|
/** Default full-share visibility rule (spec §6.1). */
|
|
11
3
|
export function isVisibleTo(event, viewer) {
|
|
12
4
|
if (event.audience === undefined && event.channel === undefined)
|
|
@@ -19,13 +11,35 @@ export function isVisibleTo(event, viewer) {
|
|
|
19
11
|
}
|
|
20
12
|
/** Process-local default blackboard. */
|
|
21
13
|
export class InMemoryEventStream {
|
|
14
|
+
opts;
|
|
22
15
|
events = [];
|
|
16
|
+
idempotentEvents = new Map();
|
|
23
17
|
listeners = new Set();
|
|
18
|
+
constructor(opts = {}) {
|
|
19
|
+
this.opts = opts;
|
|
20
|
+
}
|
|
24
21
|
async append(event) {
|
|
22
|
+
if (event.idempotencyKey) {
|
|
23
|
+
const existing = this.idempotentEvents.get(event.idempotencyKey);
|
|
24
|
+
if (existing)
|
|
25
|
+
return existing;
|
|
26
|
+
}
|
|
25
27
|
const stamped = { ...event, seq: this.events.length };
|
|
26
28
|
this.events.push(stamped);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
if (stamped.idempotencyKey)
|
|
30
|
+
this.idempotentEvents.set(stamped.idempotencyKey, stamped);
|
|
31
|
+
for (const listener of this.listeners) {
|
|
32
|
+
try {
|
|
33
|
+
listener(stamped);
|
|
34
|
+
}
|
|
35
|
+
catch (cause) {
|
|
36
|
+
reportObserverFailure(this.opts.onObserverError, {
|
|
37
|
+
component: "InMemoryEventStream",
|
|
38
|
+
operation: "event_stream_listener",
|
|
39
|
+
cause,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
29
43
|
return stamped;
|
|
30
44
|
}
|
|
31
45
|
async readSince(seq, viewer) {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { ToolCall, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse } from "../types.js";
|
|
2
2
|
import type { RegisteredTool } from "../tools/index.js";
|
|
3
|
-
import type { DreamStore } from "../memory/protocols.js";
|
|
3
|
+
import type { DreamStore, MemoryScope } from "../memory/protocols.js";
|
|
4
4
|
import type { KnowledgeSource } from "../knowledge/source.js";
|
|
5
5
|
import { LargeResultSpool } from "./large-result-spool.js";
|
|
6
|
+
import type { OperationContext } from "./reliability.js";
|
|
6
7
|
export interface RunContext {
|
|
8
|
+
/** Immutable identity, deadline, and cancellation boundary for this operation. */
|
|
9
|
+
operation?: OperationContext;
|
|
7
10
|
agentId?: string;
|
|
11
|
+
memoryScope?: MemoryScope;
|
|
8
12
|
skillDir?: string;
|
|
9
13
|
dreamStore?: DreamStore;
|
|
10
14
|
knowledgeSource?: KnowledgeSource;
|
|
@@ -30,11 +30,16 @@ export class LocalExecutionPlane {
|
|
|
30
30
|
for (const c of memoryCalls) {
|
|
31
31
|
const args = tryParseJson(c.arguments);
|
|
32
32
|
const topK = typeof args?.top_k === "number" ? args.top_k : 5;
|
|
33
|
-
const entries = (ctx.dreamStore && ctx.agentId)
|
|
34
|
-
? await ctx.dreamStore.search(ctx.agentId,
|
|
33
|
+
const entries = (ctx.dreamStore && ctx.agentId && ctx.memoryScope)
|
|
34
|
+
? await ctx.dreamStore.search(ctx.agentId, {
|
|
35
|
+
scope: ctx.memoryScope,
|
|
36
|
+
query: String(args?.query ?? ""),
|
|
37
|
+
top_k: topK,
|
|
38
|
+
kinds: [],
|
|
39
|
+
})
|
|
35
40
|
: [];
|
|
36
41
|
const content = entries.length
|
|
37
|
-
? entries.map(
|
|
42
|
+
? entries.map(e => `[memory record_id=${e.record.record_id} trust=${e.record.provenance.trust} score=${e.score.toFixed(3)}] ${e.record.content}`).join("\n---\n")
|
|
38
43
|
: "No relevant memories found.";
|
|
39
44
|
yield { type: "tool_result", callId: c.id, name: c.name, content, isError: false };
|
|
40
45
|
}
|
|
@@ -107,6 +112,7 @@ export class LocalExecutionPlane {
|
|
|
107
112
|
// best-effort failures recorded before the main throw.
|
|
108
113
|
const auditFailures = [];
|
|
109
114
|
const callCtx = {
|
|
115
|
+
...(ctx.operation !== undefined ? { operation: ctx.operation } : {}),
|
|
110
116
|
...(ctx.cwd !== undefined ? { cwd: ctx.cwd } : {}),
|
|
111
117
|
audit: async (label, fn) => {
|
|
112
118
|
try {
|
package/dist/runtime/facade.js
CHANGED
|
@@ -62,7 +62,8 @@ export async function runFanout(opts) {
|
|
|
62
62
|
// but fall back to the last completed node's output so a kernel id-scheme change can't silently
|
|
63
63
|
// return an empty synthesis.
|
|
64
64
|
const synthesisId = `wf-node${opts.tasks.length}`;
|
|
65
|
-
const
|
|
65
|
+
const completed = outcome.nodeOutcomes.filter(node => node.status === "completed" || node.status === "completed_partial");
|
|
66
|
+
const lastCompleted = completed[completed.length - 1]?.nodeId;
|
|
66
67
|
const synthesis = outcome.outputs[synthesisId] ?? (lastCompleted ? outcome.outputs[lastCompleted] : undefined) ?? "";
|
|
67
68
|
return { synthesis, outputs: outcome.outputs };
|
|
68
69
|
}
|
|
@@ -9,10 +9,8 @@ type CompressionAction = Extract<SessionEvent, {
|
|
|
9
9
|
export declare function kernelObservationToSessionEvent(obs: KernelObservation, turn: number, opts?: {
|
|
10
10
|
nextArchiveStart?: number;
|
|
11
11
|
latestSeq?: number;
|
|
12
|
-
archiveRef?: string;
|
|
13
12
|
preservedRefs?: string[];
|
|
14
13
|
compressionAction?: (action?: string) => CompressionAction;
|
|
15
|
-
spoolRef?: string;
|
|
16
14
|
}): SessionEvent | null;
|
|
17
15
|
export type KernelPrimitive = "syscall" | "sched" | "mm";
|
|
18
16
|
export declare function primitiveForCategory(category: KernelEventCategory): KernelPrimitive;
|
|
@@ -16,7 +16,7 @@ export function categoryForKind(kind) {
|
|
|
16
16
|
return "mm";
|
|
17
17
|
case "agent_process_changed":
|
|
18
18
|
return "proc";
|
|
19
|
-
case "
|
|
19
|
+
case "signal_delivery_disposed":
|
|
20
20
|
return "ipc";
|
|
21
21
|
default:
|
|
22
22
|
return "sched";
|
|
@@ -38,7 +38,6 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
|
38
38
|
action: compressionAction(obs.action),
|
|
39
39
|
summary: obs.summary,
|
|
40
40
|
summary_tokens: obs.summary ? Math.max(1, Math.ceil(obs.summary.length / 4)) : undefined,
|
|
41
|
-
archive_ref: opts.archiveRef,
|
|
42
41
|
preserved_refs: opts.preservedRefs ?? [],
|
|
43
42
|
};
|
|
44
43
|
}
|
|
@@ -130,10 +129,13 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
|
130
129
|
tool: obs.tool ?? "",
|
|
131
130
|
reason: typeof obs.reason === "string" ? obs.reason : "",
|
|
132
131
|
};
|
|
133
|
-
case "
|
|
132
|
+
case "signal_delivery_disposed":
|
|
134
133
|
return {
|
|
135
|
-
kind: "
|
|
134
|
+
kind: "signal_delivery_disposed",
|
|
136
135
|
turn: t,
|
|
136
|
+
operation_id: obs.operation_id ?? "",
|
|
137
|
+
delivery_id: obs.delivery_id ?? "",
|
|
138
|
+
attempt: obs.attempt ?? 0,
|
|
137
139
|
signal_id: obs.signal_id ?? "",
|
|
138
140
|
disposition: obs.disposition ?? "",
|
|
139
141
|
queue_depth: obs.queue_depth ?? 0,
|
|
@@ -143,6 +145,26 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
|
143
145
|
kind: "budget_exceeded",
|
|
144
146
|
turn: t,
|
|
145
147
|
budget: obs.budget ?? "",
|
|
148
|
+
operation_id: obs.operation_id ?? "",
|
|
149
|
+
...(obs.reservation_id ? { reservation_id: obs.reservation_id } : {}),
|
|
150
|
+
};
|
|
151
|
+
case "budget_usage_reported":
|
|
152
|
+
return {
|
|
153
|
+
kind: "budget_usage_reported",
|
|
154
|
+
turn: t,
|
|
155
|
+
operation_id: obs.operation_id ?? "",
|
|
156
|
+
reservation_id: obs.reservation_id ?? "",
|
|
157
|
+
tokens: obs.tokens ?? 0,
|
|
158
|
+
subagents: obs.subagents ?? 0,
|
|
159
|
+
rounds: obs.rounds ?? 0,
|
|
160
|
+
};
|
|
161
|
+
case "operation_cancelled":
|
|
162
|
+
return {
|
|
163
|
+
kind: "operation_cancelled",
|
|
164
|
+
turn: t,
|
|
165
|
+
operation_id: obs.operation_id ?? "",
|
|
166
|
+
reason: (obs.reason ?? "user"),
|
|
167
|
+
pending_call_ids: obs.pending_call_ids ?? [],
|
|
146
168
|
};
|
|
147
169
|
case "suspended":
|
|
148
170
|
return {
|
|
@@ -168,21 +190,34 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
|
168
190
|
tool: obs.tool ?? "",
|
|
169
191
|
original_size: obs.original_size ?? 0,
|
|
170
192
|
preview_size: obs.preview_size ?? 0,
|
|
171
|
-
spool_ref:
|
|
193
|
+
spool_ref: obs.spool_ref,
|
|
194
|
+
};
|
|
195
|
+
case "page_out_archived":
|
|
196
|
+
return {
|
|
197
|
+
kind: "page_out",
|
|
198
|
+
turn: t,
|
|
199
|
+
action: compressionAction(obs.action),
|
|
200
|
+
summary: obs.summary,
|
|
201
|
+
tier_hint: obs.tier,
|
|
202
|
+
message_count: obs.message_count ?? 0,
|
|
203
|
+
archive_ref: obs.archive_ref,
|
|
172
204
|
};
|
|
173
205
|
case "memory_written":
|
|
174
206
|
return {
|
|
175
207
|
kind: "memory_written",
|
|
176
208
|
turn: t,
|
|
177
|
-
|
|
209
|
+
record_id: obs.record_id ?? "",
|
|
210
|
+
scope: obs.scope ?? { tenant_id: "", namespace: "" },
|
|
178
211
|
memory_kind: obs.memory_kind ?? "",
|
|
212
|
+
name: obs.name ?? "",
|
|
179
213
|
size_bytes: obs.size_bytes ?? 0,
|
|
180
214
|
};
|
|
181
215
|
case "memory_queried":
|
|
182
216
|
return {
|
|
183
217
|
kind: "memory_queried",
|
|
184
218
|
turn: t,
|
|
185
|
-
|
|
219
|
+
scope: obs.scope ?? { tenant_id: "", namespace: "" },
|
|
220
|
+
query: obs.query ?? "",
|
|
186
221
|
requested_k: obs.requested_k ?? 0,
|
|
187
222
|
requires_async_response: obs.requires_async_response ?? false,
|
|
188
223
|
};
|
|
@@ -190,7 +225,22 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
|
190
225
|
return {
|
|
191
226
|
kind: "memory_validation_failed",
|
|
192
227
|
turn: t,
|
|
193
|
-
|
|
228
|
+
record_id: obs.record_id ?? "",
|
|
229
|
+
error: obs.error ?? "",
|
|
230
|
+
};
|
|
231
|
+
case "memory_write_failed":
|
|
232
|
+
return {
|
|
233
|
+
kind: "memory_write_failed",
|
|
234
|
+
turn: t,
|
|
235
|
+
record_id: obs.record_id ?? "",
|
|
236
|
+
error: obs.error ?? "",
|
|
237
|
+
};
|
|
238
|
+
case "memory_query_failed":
|
|
239
|
+
return {
|
|
240
|
+
kind: "memory_query_failed",
|
|
241
|
+
turn: t,
|
|
242
|
+
scope: obs.scope ?? { tenant_id: "", namespace: "" },
|
|
243
|
+
query: obs.query ?? "",
|
|
194
244
|
error: obs.error ?? "",
|
|
195
245
|
};
|
|
196
246
|
case "workflow_batch_spawned": {
|
|
@@ -205,14 +255,12 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
|
|
|
205
255
|
};
|
|
206
256
|
}
|
|
207
257
|
case "workflow_completed": {
|
|
208
|
-
const
|
|
209
|
-
const failed = obs.failed ?? [];
|
|
258
|
+
const nodeOutcomes = obs.node_outcomes ?? [];
|
|
210
259
|
return {
|
|
211
260
|
kind: "workflow_completed",
|
|
212
261
|
turn: t,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
total_nodes: completed.length + failed.length,
|
|
262
|
+
node_outcomes: nodeOutcomes,
|
|
263
|
+
total_nodes: nodeOutcomes.length,
|
|
216
264
|
};
|
|
217
265
|
}
|
|
218
266
|
default:
|
|
@@ -54,7 +54,7 @@ export class KernelPrimitivesDashboard {
|
|
|
54
54
|
else if (event.kind === "resumed") {
|
|
55
55
|
this.stats.sched.resumedCount++;
|
|
56
56
|
}
|
|
57
|
-
else if (event.kind === "
|
|
57
|
+
else if (event.kind === "signal_delivery_disposed") {
|
|
58
58
|
this.stats.sched.signalDisposedCount++;
|
|
59
59
|
}
|
|
60
60
|
else if (event.kind === "budget_exceeded") {
|
|
@@ -0,0 +1,13 @@
|
|
|
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;
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
}
|