@deepstrike/sdk 0.2.16 → 0.2.18

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.
@@ -84,7 +84,6 @@ export class HarnessLoop {
84
84
  }
85
85
  async *stream(request) {
86
86
  const kernel = getKernel();
87
- const pipeline = new kernel.EvalPipeline({ extractSkillOnPass: true });
88
87
  const criteria = request.criteria ?? [];
89
88
  let currentGoal = request.goal;
90
89
  let lastIterations = 0;
@@ -126,11 +125,10 @@ export class HarnessLoop {
126
125
  }
127
126
  }
128
127
  yield { type: "supervising" };
129
- const evalAction = pipeline.feedOutcome(request.goal, criteria, lastResult, attempt);
130
- if (evalAction.kind !== "evaluate")
131
- break;
128
+ // #6 (0.5.0): the eval/verdict compute is the kernel's stateless free functions (was the
129
+ // EvalPipeline state machine). Build the eval prompt, call the eval LLM, parse the verdict.
130
+ const evalMsgs = kernel.buildEvalMessages(request.goal, criteria, lastResult, attempt, true);
132
131
  let evalText = "";
133
- const evalMsgs = evalAction.messages ?? [];
134
132
  const evalContext = {
135
133
  systemText: evalMsgs.filter((m) => m.role === "system").map((m) => m.content).join("\n\n"),
136
134
  turns: evalMsgs.filter((m) => m.role !== "system"),
@@ -139,18 +137,16 @@ export class HarnessLoop {
139
137
  if (evt.type === "text_delta")
140
138
  evalText += evt.delta;
141
139
  }
142
- const doneAction = pipeline.feedEvalResult(evalText);
143
- if (doneAction.kind !== "done")
144
- break;
140
+ const parsed = kernel.parseVerdict(evalText);
145
141
  const verdict = {
146
- passed: doneAction.passed ?? false,
147
- overallScore: doneAction.overallScore ?? 0,
148
- feedback: doneAction.feedback ?? "",
149
- details: doneAction.details ?? [],
142
+ passed: parsed.passed,
143
+ overallScore: parsed.overallScore,
144
+ feedback: parsed.feedback,
145
+ details: parsed.details ?? [],
150
146
  };
151
147
  if (verdict.passed) {
152
- if (doneAction.skillCandidate && this.skillDir) {
153
- const { name, description, whenToUse, content } = doneAction.skillCandidate;
148
+ if (parsed.skillCandidate && this.skillDir) {
149
+ const { name, description, whenToUse, content } = parsed.skillCandidate;
154
150
  const fm = ["---", `name: ${name}`, `description: ${description}`,
155
151
  whenToUse ? `when_to_use: ${whenToUse}` : null, "---", ""]
156
152
  .filter(Boolean).join("\n");
@@ -162,7 +158,6 @@ export class HarnessLoop {
162
158
  yield { type: "revising", verdict };
163
159
  currentGoal = `${request.goal}\n\n[Attempt ${attempt} feedback: ${verdict.feedback}]`;
164
160
  lastResult = "";
165
- pipeline.reset();
166
161
  }
167
162
  yield { type: "max_attempts_reached" };
168
163
  }
package/dist/index.d.ts CHANGED
@@ -2,6 +2,10 @@ export { RuntimeRunner, collectText } from "./runtime/runner.js";
2
2
  export type { RuntimeOptions, SchedulerBudget } from "./runtime/runner.js";
3
3
  export { builtinReducers, resolveReducer } from "./runtime/reducers.js";
4
4
  export type { Reducer, ReducerRegistry, ReducerInput } from "./runtime/reducers.js";
5
+ export { loopInstruction, classifyInstruction, judgeGoal, extractLoopContinue, extractClassifyBranch, extractJudgeWinner, } from "./runtime/workflow-control-flow.js";
6
+ export { WorktreeExecutionPlane, GitWorktreeManager } from "./runtime/worktree-plane.js";
7
+ export type { WorktreeManager } from "./runtime/worktree-plane.js";
8
+ export { FileWorkflowStore } from "./runtime/workflow-store.js";
5
9
  export type { MemoryPolicy, MemoryWriteRateLimit, ResourceQuota } from "./kernel.js";
6
10
  export { KernelPrimitivesDashboard } from "./runtime/kernel-primitives-dashboard.js";
7
11
  export { FilteredExecutionPlane } from "./runtime/filtered-plane.js";
@@ -64,7 +68,7 @@ export { SinglePassHarness, EvalLoopHarness, HarnessLoop } from "./harness/harne
64
68
  export type { HarnessRequest, HarnessOutcome, HarnessLoopOptions, QualityGate } from "./harness/harness.js";
65
69
  export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolChunk, ToolDeltaEvent, ToolSuspendEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, LLMProvider, RetryConfig, TokenUsage, ProviderToolSpec, ProviderRunState, ProviderReplay, RenderedContext, ReplayabilityAssessment, } from "./types.js";
66
70
  export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec, AgentProcessChangedObservation, ContextInheritance, KernelAgentRole, LoopResult, MilestoneCheckResult, MilestoneContract, MilestonePhase, MilestonePolicy, SubAgentResult, TerminationReason, WorkflowSpec, WorkflowNodeSpec, WorkflowTaskSpec, WorkflowSpawnInfo, } from "./types/agent.js";
67
- export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowNodesTool, fanoutSynthesize, generateAndFilter, verifyRules, } from "./types/agent.js";
71
+ export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, submitWorkflowNodesTool, startWorkflowTool, fanoutSynthesize, generateAndFilter, verifyRules, genEval, } from "./types/agent.js";
68
72
  export type { AcceptanceCriterion, VerificationContract, ContractCheckResult, } from "./collaboration/contract.js";
69
73
  export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./collaboration/contract.js";
70
74
  export { AgentPool } from "./collaboration/pool.js";
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  // ── Runtime (Layer 1.5) ────────────────────────────────────────────────────
2
2
  export { RuntimeRunner, collectText } from "./runtime/runner.js";
3
3
  export { builtinReducers, resolveReducer } from "./runtime/reducers.js";
4
+ export { loopInstruction, classifyInstruction, judgeGoal, extractLoopContinue, extractClassifyBranch, extractJudgeWinner, } from "./runtime/workflow-control-flow.js";
5
+ export { WorktreeExecutionPlane, GitWorktreeManager } from "./runtime/worktree-plane.js";
6
+ export { FileWorkflowStore } from "./runtime/workflow-store.js";
4
7
  export { KernelPrimitivesDashboard } from "./runtime/kernel-primitives-dashboard.js";
5
8
  export { FilteredExecutionPlane } from "./runtime/filtered-plane.js";
6
9
  export { SubAgentOrchestrator, defaultSubAgentOrchestrator, spawnStandalone } from "./runtime/sub-agent-orchestrator.js";
@@ -43,7 +46,7 @@ export { PermissionManager, PermissionMode } from "./safety/permissions.js";
43
46
  export { Governance, governancePolicyToKernelEvent } from "./governance.js";
44
47
  // ── Harness ────────────────────────────────────────────────────────────────
45
48
  export { SinglePassHarness, EvalLoopHarness, HarnessLoop } from "./harness/harness.js";
46
- export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowNodesTool, fanoutSynthesize, generateAndFilter, verifyRules, } from "./types/agent.js";
49
+ export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, submitWorkflowNodesTool, startWorkflowTool, fanoutSynthesize, generateAndFilter, verifyRules, genEval, } from "./types/agent.js";
47
50
  export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./collaboration/contract.js";
48
51
  export { AgentPool } from "./collaboration/pool.js";
49
52
  export { KERNEL_ROLE_MAP } from "./collaboration/pool.js";
package/dist/kernel.d.ts CHANGED
@@ -77,13 +77,11 @@ interface NativeCriterion {
77
77
  required: boolean;
78
78
  weight?: number;
79
79
  }
80
- interface EvalPipelineAction {
81
- kind: "evaluate" | "done";
82
- messages?: Message[];
83
- passed?: boolean;
84
- overallScore?: number;
85
- feedback?: string;
86
- details?: Array<{
80
+ export interface Verdict {
81
+ passed: boolean;
82
+ overallScore: number;
83
+ feedback: string;
84
+ details: Array<{
87
85
  criterion: string;
88
86
  passed: boolean;
89
87
  score: number;
@@ -96,11 +94,6 @@ interface EvalPipelineAction {
96
94
  content: string;
97
95
  };
98
96
  }
99
- interface EvalPipelineInstance {
100
- feedOutcome(goal: string, criteria: NativeCriterion[], result: string, attempt: number): EvalPipelineAction;
101
- feedEvalResult(content: string): EvalPipelineAction;
102
- reset(): void;
103
- }
104
97
  interface IdlePipelineAction {
105
98
  kind: "synthesize_insights" | "commit_memories" | "noop" | "aborted";
106
99
  messages?: Message[];
@@ -156,9 +149,9 @@ interface KernelModule {
156
149
  timeoutMs?: bigint;
157
150
  }) => KernelRuntimeInstance;
158
151
  SignalRouter: new (maxQueueSize: number) => SignalRouterInstance;
159
- EvalPipeline: new (options?: {
160
- extractSkillOnPass?: boolean;
161
- }) => EvalPipelineInstance;
152
+ buildEvalMessages(goal: string, criteria: NativeCriterion[], result: string, attempt: number, extractSkillOnPass: boolean): Message[];
153
+ parseVerdict(content: string): Verdict;
154
+ verdictOutputSchema(extractSkillOnPass: boolean): string;
162
155
  IdlePipeline: new (agentId: string) => IdlePipelineInstance;
163
156
  }
164
157
  export declare function getKernel(): KernelModule;
@@ -1,4 +1,4 @@
1
- import type { Message, ProviderDescriptor, ProviderReplay, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
1
+ import type { Message, ProviderDescriptor, ProviderReplay, ProviderRunState, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
2
2
  interface AnthropicProviderOptions {
3
3
  baseURL?: string;
4
4
  authMode?: "api-key" | "bearer";
@@ -29,7 +29,7 @@ export declare class AnthropicProvider implements LLMProvider {
29
29
  */
30
30
  private buildTools;
31
31
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
32
- stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
32
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, _state?: ProviderRunState, signal?: AbortSignal): AsyncIterable<StreamEvent>;
33
33
  private requestExtensions;
34
34
  private hasBetas;
35
35
  private createMessage;
@@ -128,7 +128,7 @@ export class AnthropicProvider {
128
128
  }
129
129
  throw lastErr;
130
130
  }
131
- async *stream(context, tools, extensions) {
131
+ async *stream(context, tools, extensions, _state, signal) {
132
132
  const system = this.buildSystem(context);
133
133
  const msgs = this.buildMessages(context);
134
134
  assertCacheBudget(system, tools.length);
@@ -144,7 +144,7 @@ export class AnthropicProvider {
144
144
  ...(system ? { system } : {}),
145
145
  messages: msgs,
146
146
  ...(tools.length ? { tools: this.buildTools(tools, !Array.isArray(system)) } : {}),
147
- }, extensions);
147
+ }, extensions, signal);
148
148
  let uncachedInput = 0;
149
149
  let cacheReadTokens = 0;
150
150
  let cacheCreationTokens = 0;
@@ -228,10 +228,12 @@ export class AnthropicProvider {
228
228
  ? this.client.beta.messages.create(params)
229
229
  : this.client.messages.create(params);
230
230
  }
231
- streamMessage(params, extensions) {
231
+ streamMessage(params, extensions, signal) {
232
+ // #2-B-ii: forward the abort signal as a request option so a preempt cancels the HTTP request.
233
+ const opts = signal ? { signal } : undefined;
232
234
  return (this.hasBetas(extensions)
233
- ? this.client.beta.messages.stream(params)
234
- : this.client.messages.stream(params));
235
+ ? this.client.beta.messages.stream(params, opts)
236
+ : this.client.messages.stream(params, opts));
235
237
  }
236
238
  buildSystem(context) {
237
239
  // B3 note: the system shape is content-driven — 0 blocks (string), 1 block
@@ -1,5 +1,5 @@
1
1
  import OpenAI from "openai";
2
- import type { Message, ProviderDescriptor, ProviderReplay, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
2
+ import type { Message, ProviderDescriptor, ProviderReplay, ProviderRunState, RenderedContext, ToolSchema, StreamEvent, LLMProvider, RuntimePolicy } from "../types.js";
3
3
  import { CircuitBreaker } from "./base.js";
4
4
  import { OpenAIChatAdapter } from "./openai-chat.js";
5
5
  import type { ReplayabilityAssessment } from "./replay-validator.js";
@@ -30,7 +30,7 @@ export declare class OpenAIChatProvider implements LLMProvider {
30
30
  peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
31
31
  seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
32
32
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
33
- stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
33
+ stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, _state?: ProviderRunState, signal?: AbortSignal): AsyncIterable<StreamEvent>;
34
34
  /**
35
35
  * Default `prompt_cache_key` derived from the cacheable prefix (system prompt +
36
36
  * tool names) so requests for the same agent config route to the same cache.
@@ -122,7 +122,7 @@ export class OpenAIChatProvider {
122
122
  }
123
123
  throw lastErr;
124
124
  }
125
- async *stream(context, tools, extensions) {
125
+ async *stream(context, tools, extensions, _state, signal) {
126
126
  const msgs = this.buildChatMessages(context, extensions);
127
127
  const toolCallBufs = {};
128
128
  const emittedToolCallIndexes = new Set();
@@ -137,7 +137,8 @@ export class OpenAIChatProvider {
137
137
  ...(tools.length ? { tools: this.chat.buildTools(tools) } : {}),
138
138
  stream: true,
139
139
  stream_options: { include_usage: true },
140
- });
140
+ // #2-B-ii: forward the abort signal so a preempt cancels the in-flight HTTP request.
141
+ }, signal ? { signal } : undefined);
141
142
  let totalTokens = 0;
142
143
  let inputTokens = 0;
143
144
  let outputTokens = 0;
@@ -11,6 +11,11 @@ export interface RunContext {
11
11
  onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
12
12
  onPermissionRequest?: (event: PermissionRequestEvent) => Promise<PermissionResponse | boolean> | PermissionResponse | boolean;
13
13
  resultSpool?: LargeResultSpool;
14
+ /** M3/G4 worktree isolation: the working directory a sub-agent's tools should run in (the git
15
+ * worktree created for an `isolation: "worktree"` node). Injected by `WorktreeExecutionPlane`; a
16
+ * cwd-aware execution plane / tool reads it to scope filesystem + subprocess work. Undefined ⇒
17
+ * the plane's own default cwd. */
18
+ cwd?: string;
14
19
  }
15
20
  export interface ExecutionPlane {
16
21
  register(...tools: RegisteredTool[]): this;
@@ -117,7 +117,9 @@ export class LocalExecutionPlane {
117
117
  repairedArguments: JSON.stringify(args),
118
118
  };
119
119
  }
120
- const output = await registered.execute(args);
120
+ // M3/G4: pass the run context (incl. `cwd`) so cwd-aware tools scope their work to the
121
+ // sub-agent's worktree. `RunContext` is structurally assignable to the tool's `ToolExecContext`.
122
+ const output = await registered.execute(args, ctx);
121
123
  if (isAsyncIterable(output)) {
122
124
  let combined = "";
123
125
  const iterator = output[Symbol.asyncIterator]();
@@ -38,7 +38,7 @@ export class ProcessSandboxPlane extends LocalExecutionPlane {
38
38
  }
39
39
  return env;
40
40
  }
41
- runSubprocess(cmd, argv) {
41
+ runSubprocess(cmd, argv, cwd) {
42
42
  return new Promise(resolve => {
43
43
  const chunks = [];
44
44
  let totalBytes = 0;
@@ -51,7 +51,7 @@ export class ProcessSandboxPlane extends LocalExecutionPlane {
51
51
  resolve({ output, isError });
52
52
  };
53
53
  const child = spawn(cmd, argv, {
54
- cwd: this.sandboxDir,
54
+ cwd,
55
55
  env: this.buildEnv(),
56
56
  stdio: ["ignore", "pipe", "pipe"],
57
57
  });
@@ -83,9 +83,12 @@ export class ProcessSandboxPlane extends LocalExecutionPlane {
83
83
  command: { type: "string", description: "The bash command to execute." },
84
84
  },
85
85
  required: ["command"],
86
- }, async (args) => {
87
- await mkdir(this.sandboxDir, { recursive: true });
88
- const { output, isError } = await this.runSubprocess("bash", ["-c", String(args.command)]);
86
+ }, async (args, ctx) => {
87
+ // M3/G4: run in the sub-agent's worktree when one was injected, else the sandbox dir.
88
+ const cwd = ctx?.cwd ?? this.sandboxDir;
89
+ if (!ctx?.cwd)
90
+ await mkdir(this.sandboxDir, { recursive: true });
91
+ const { output, isError } = await this.runSubprocess("bash", ["-c", String(args.command)], cwd);
89
92
  if (isError && !output.trim())
90
93
  return "Process exited with non-zero status and produced no output.";
91
94
  return output || "(no output)";
@@ -98,9 +101,12 @@ export class ProcessSandboxPlane extends LocalExecutionPlane {
98
101
  code: { type: "string", description: "The JavaScript code to evaluate." },
99
102
  },
100
103
  required: ["code"],
101
- }, async (args) => {
102
- await mkdir(this.sandboxDir, { recursive: true });
103
- const { output, isError } = await this.runSubprocess("node", ["-e", String(args.code)]);
104
+ }, async (args, ctx) => {
105
+ // M3/G4: run in the sub-agent's worktree when one was injected, else the sandbox dir.
106
+ const cwd = ctx?.cwd ?? this.sandboxDir;
107
+ if (!ctx?.cwd)
108
+ await mkdir(this.sandboxDir, { recursive: true });
109
+ const { output, isError } = await this.runSubprocess("node", ["-e", String(args.code)], cwd);
104
110
  if (isError && !output.trim())
105
111
  return "Script exited with non-zero status and produced no output.";
106
112
  return output || "(no output)";
@@ -17,6 +17,19 @@ export interface SchedulerBudget {
17
17
  }
18
18
  export interface RuntimeOptions {
19
19
  provider: LLMProvider;
20
+ /** M4/G5: cumulative token cap for this run (the kernel's `max_total_tokens`). A workflow node's
21
+ * `tokenBudget` flows here for its child run, so an expensive node self-terminates at the cap.
22
+ * Undefined ⇒ the kernel default. */
23
+ maxTotalTokens?: number;
24
+ /** M1/G3 intelligence routing: resolve a per-node provider from a workflow node's `modelHint`
25
+ * (e.g. "opus" / "sonnet" / "haiku"). Returns undefined ⇒ fall back to `provider`. A workflow
26
+ * node carrying `model_hint` runs against the resolved provider; without this hook the hint is a
27
+ * no-op (the kernel still carries it for audit). */
28
+ providerFor?: (modelHint: string) => LLMProvider | undefined;
29
+ /** M3/G4 worktree isolation: when set, an `isolation: "worktree"` sub-agent runs inside a git
30
+ * worktree this manager creates (and removes on completion), injected as `RunContext.cwd`.
31
+ * Undefined ⇒ worktree nodes fall back to the inherited plane (no isolation). */
32
+ worktreeManager?: import("./worktree-plane.js").WorktreeManager;
20
33
  sessionLog: SessionLog;
21
34
  executionPlane: ExecutionPlane;
22
35
  maxTokens: number;
@@ -89,6 +102,13 @@ export interface RuntimeOptions {
89
102
  milestoneContract?: MilestoneContract;
90
103
  /** Custom sub-agent host driver; defaults to SubAgentOrchestrator. */
91
104
  subAgentOrchestrator?: SubAgentOrchestrator;
105
+ /** M5 v2.1: marks this runner as executing AS a workflow node (a child spawned by the workflow
106
+ * driver). A workflow node's `start_workflow` FLATTENS to the parent kernel (emits
107
+ * `workflow_nodes_submitted` for `runWorkflow` to append). A top-level run (this flag unset)
108
+ * instead AUTO-PIVOTS: it bootstraps + drives the authored workflow in its own kernel and resumes
109
+ * the reason loop with the outcome. The orchestrator sets this on workflow-node children so a
110
+ * nested `start_workflow` flattens rather than recursing. */
111
+ isWorkflowNode?: boolean;
92
112
  /**
93
113
  * When set, sub-agents run through a HarnessLoop with this config.
94
114
  * The eval provider evaluates the sub-agent's output against the criteria
@@ -123,6 +143,9 @@ export interface RuntimeOptions {
123
143
  export declare class RuntimeRunner {
124
144
  private readonly opts;
125
145
  private interrupted;
146
+ /** #2-B-ii: aborts the in-flight provider stream when the run is interrupted/preempted. Recreated
147
+ * per `execute`; `interrupt()` fires it so a Critical `InterruptNow` cancels the live LLM call. */
148
+ private abortController;
126
149
  private activeKernel;
127
150
  private pendingObservations;
128
151
  private currentSessionId;
@@ -131,6 +154,9 @@ export declare class RuntimeRunner {
131
154
  private pendingSpoolOutputs;
132
155
  /** Local cache of paged-out/archived messages for priority memory retrieval. */
133
156
  private localPageOutCache;
157
+ /** M5 v2.1: sub-workflow specs a top-level agent authored via `start_workflow`, awaiting auto-drive
158
+ * at the next safe point (after the tool turn resolves, kernel back in Reason — not suspended). */
159
+ private pendingAuthoredWorkflows;
134
160
  private dashboard;
135
161
  constructor(opts: RuntimeOptions);
136
162
  /** Host configuration (for coordinator / sub-agent spawn). */
@@ -191,7 +217,50 @@ export declare class RuntimeRunner {
191
217
  }): Promise<{
192
218
  completed: string[];
193
219
  failed: string[];
220
+ outputs: Record<string, string>;
194
221
  }>;
222
+ /**
223
+ * M5/G1: bootstrap an **agent-authored** workflow ("the model writes its own harness"). Unlike
224
+ * `runWorkflow` (the host fires the privileged `load_workflow`), this routes the spec through the
225
+ * agent-reachable `Syscall::LoadWorkflow` (the `submit_workflow` event): with no workflow active the
226
+ * kernel **bootstraps** the DAG; if one is already active it **flattens** the spec's nodes onto it
227
+ * (bootstrap-or-flatten — one kernel, one quota, never a workflow stack). Gated by the same
228
+ * `max_workflow_nodes` backstop as runtime submission, so an authored harness can't overgrow the run.
229
+ * The resulting batches are driven by the same shared driver as `runWorkflow`.
230
+ */
231
+ bootstrapWorkflow(spec: WorkflowSpec, opts?: {
232
+ submitterAgentId?: string;
233
+ }): Promise<{
234
+ completed: string[];
235
+ failed: string[];
236
+ outputs: Record<string, string>;
237
+ }>;
238
+ /**
239
+ * M5 v2.1: drive the sub-workflow(s) a top-level agent authored via `start_workflow`. Called at the
240
+ * verified-safe point (right after the tool turn resolved to `call_provider` — kernel in Reason, not
241
+ * suspended). For each authored spec: `bootstrapWorkflow` runs it in THIS kernel (the kernel resumes
242
+ * the agent reason loop on `workflow_completed` — `finish_workflow` sets phase=Reason), then the
243
+ * outcome is injected as a user message so the agent's next turn sees the result. Returns a fresh
244
+ * `call_provider` synthesized from the updated context (the workflow drive consumed its own kernel
245
+ * actions, so we re-render — the same pattern as the reactive-compact retry path).
246
+ */
247
+ private driveAuthoredWorkflows;
248
+ /**
249
+ * #2-B-ii: while a workflow batch is in flight, poll the signal source. A Critical `InterruptNow`
250
+ * routes through the kernel (which, with the root suspended in `SubAgentAwait`, preempts — marks the
251
+ * running nodes `UserAbort`, tears the `WorkflowRun` down, emits `AgentPreempted`); we then abort the
252
+ * matching children's in-flight LLM calls (via their per-node `AbortController` → `interrupt()`).
253
+ * Returns the torn-down workflow's outcome on preemption, else `null`. No-op (null) without a signal
254
+ * source. Non-preempting signals (queue/observe/soft-interrupt) are still applied as they arrive.
255
+ */
256
+ private monitorWorkflowPreemption;
257
+ /**
258
+ * Shared workflow driver for `runWorkflow` (host `load_workflow`) and `bootstrapWorkflow` (agent
259
+ * `submit_workflow`): given the observations from the initial load/bootstrap, run each kernel-emitted
260
+ * batch in parallel, feed completions back (appending any agent-submitted nodes first), and loop
261
+ * until the kernel reports the workflow complete. Returns the completed / failed node agent-ids.
262
+ */
263
+ private driveWorkflow;
195
264
  /**
196
265
  * Resume a workflow from the parent session's completed nodes.
197
266
  * Reads the session log, extracts completed workflow node agent_ids, and