@deepstrike/wasm 0.2.41 → 0.2.42

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.
@@ -160,6 +160,8 @@ export type KernelRunnerAction = {
160
160
  };
161
161
  export interface KernelObservation {
162
162
  kind: string;
163
+ operation?: string;
164
+ subject?: string;
163
165
  action?: string;
164
166
  rho_after?: number;
165
167
  sprint?: number;
@@ -22,6 +22,8 @@ export interface ResourceQuota {
22
22
  maxConcurrentSubagents?: number;
23
23
  /** Max sub-agent nesting depth (direct children of the root loop are depth 1). */
24
24
  maxSpawnDepth?: number;
25
+ /** Max nodes in one in-kernel workflow DAG, including dynamically submitted nodes. */
26
+ maxWorkflowNodes?: number;
25
27
  /** Rolling-window memory-write rate limit: at most `maxWrites` per any `windowMs` span. */
26
28
  memoryWritesPerWindow?: MemoryWriteRateLimit;
27
29
  }
@@ -41,6 +41,17 @@ function pendingCallIds(action) {
41
41
  default: return "effectId" in action ? [action.effectId] : [];
42
42
  }
43
43
  }
44
+ function controlRequestRejection(observations, operation) {
45
+ const rejected = observations.find(observation => observation.kind === "control_request_rejected"
46
+ && (!operation || observation.operation === operation));
47
+ if (!rejected)
48
+ return undefined;
49
+ return {
50
+ operation: rejected.operation ?? operation ?? "control_request",
51
+ ...(rejected.subject ? { subject: rejected.subject } : {}),
52
+ reason: typeof rejected.reason === "string" ? rejected.reason : "request denied",
53
+ };
54
+ }
44
55
  export class RuntimeRunner {
45
56
  opts;
46
57
  interrupted = false;
@@ -869,7 +880,7 @@ export class RuntimeRunner {
869
880
  const spec = parseStartWorkflowSpec(call.arguments);
870
881
  if (spec) {
871
882
  this.pendingAuthoredWorkflows.push(spec);
872
- const out = "workflow authored; executing now";
883
+ const out = "workflow submitted for governance adjudication";
873
884
  toolResults.push({ callId: call.id, output: out, isError: false });
874
885
  yield { type: "tool_result", callId: call.id, content: out, isError: false };
875
886
  continue;
@@ -879,8 +890,9 @@ export class RuntimeRunner {
879
890
  ? parseStartWorkflowArgs(call.arguments)
880
891
  : parseSubmitWorkflowNodesArgs(call.arguments);
881
892
  yield { type: "workflow_nodes_submitted", nodes };
882
- toolResults.push({ callId: call.id, output: "submitted", isError: false });
883
- yield { type: "tool_result", callId: call.id, content: "submitted", isError: false };
893
+ const out = "workflow nodes submitted for parent governance adjudication";
894
+ toolResults.push({ callId: call.id, output: out, isError: false });
895
+ yield { type: "tool_result", callId: call.id, content: out, isError: false };
884
896
  }
885
897
  // O5 (PreToolUse-hook analog): stateful host veto over each kernel-approved call.
886
898
  // A blocked call never executes; its reason reaches the model as a denied result.
@@ -1189,8 +1201,25 @@ export class RuntimeRunner {
1189
1201
  });
1190
1202
  this.nextArchiveStart = await this.appendObservations(parentSessionId, runtime, this.nextArchiveStart);
1191
1203
  const spawned = findSpawnProcessObservation(observations);
1192
- if (!spawned)
1204
+ if (!spawned) {
1205
+ const rejected = controlRequestRejection(observations, "spawn_sub_agent");
1206
+ if (rejected) {
1207
+ return {
1208
+ agentId: rejected.subject ?? spec.identity.agentId,
1209
+ result: {
1210
+ termination: "error",
1211
+ finalMessage: {
1212
+ role: "assistant",
1213
+ content: `spawn_sub_agent denied: ${rejected.reason}`,
1214
+ toolCalls: [],
1215
+ },
1216
+ turnsUsed: 0,
1217
+ totalTokensUsed: 0,
1218
+ },
1219
+ };
1220
+ }
1193
1221
  throw new Error("spawn_sub_agent did not emit agent_process_changed");
1222
+ }
1194
1223
  const manifest = spawnObservationToManifest(spawned, spec, parentSessionId);
1195
1224
  const orchestrator = this.opts.subAgentOrchestrator ?? defaultSubAgentOrchestrator;
1196
1225
  const result = await orchestrator.run({
@@ -1392,6 +1421,7 @@ export class RuntimeRunner {
1392
1421
  config.resource_quota = {
1393
1422
  ...(q.maxConcurrentSubagents !== undefined ? { max_concurrent_subagents: q.maxConcurrentSubagents } : {}),
1394
1423
  ...(q.maxSpawnDepth !== undefined ? { max_spawn_depth: q.maxSpawnDepth } : {}),
1424
+ ...(q.maxWorkflowNodes !== undefined ? { max_workflow_nodes: q.maxWorkflowNodes } : {}),
1395
1425
  ...(q.memoryWritesPerWindow !== undefined
1396
1426
  ? { memory_writes_per_window: [q.memoryWritesPerWindow.maxWrites, q.memoryWritesPerWindow.windowMs] }
1397
1427
  : {}),
@@ -1641,6 +1671,11 @@ export class RuntimeRunner {
1641
1671
  }
1642
1672
  if (!initialAction)
1643
1673
  return { nodeOutcomes: [], outputs: {} };
1674
+ const workflowRejection = controlRequestRejection(observations);
1675
+ if (initialAction.kind === "call_provider" && workflowRejection) {
1676
+ this.workflowContinuation = initialAction;
1677
+ return { nodeOutcomes: [], outputs: {}, rejection: workflowRejection };
1678
+ }
1644
1679
  if (initialAction.kind !== "spawn_workflow") {
1645
1680
  throw new Error(`workflow load returned unexpected kernel effect: ${initialAction.kind}`);
1646
1681
  }
@@ -1687,6 +1722,22 @@ export class RuntimeRunner {
1687
1722
  const observationStart = this.pendingObservations.length;
1688
1723
  const submitAction = kernelMaybeAction(runtime, this.pendingObservations, submitEvent);
1689
1724
  const subObs = this.pendingObservations.slice(observationStart);
1725
+ const nodesRejected = subObs.find(observation => observation.kind === "nodes_rejected");
1726
+ const rejected = controlRequestRejection(subObs, "submit_workflow_nodes")
1727
+ ?? (nodesRejected
1728
+ ? { operation: "submit_workflow_nodes", reason: String(nodesRejected.reason ?? "request denied") }
1729
+ : undefined);
1730
+ if (rejected) {
1731
+ const denial = `workflow node submission denied: ${rejected.reason}`;
1732
+ result.result = {
1733
+ ...result.result,
1734
+ termination: "error",
1735
+ finalMessage: { role: "assistant", content: denial, toolCalls: [] },
1736
+ };
1737
+ outputs.set(result.agentId, denial);
1738
+ if (stableId !== result.agentId)
1739
+ outputs.set(stableId, denial);
1740
+ }
1690
1741
  if (submitAction?.kind === "spawn_workflow") {
1691
1742
  nextNodes.push(...submitAction.nodes);
1692
1743
  budget = submitAction.budget ?? budget;
@@ -196,9 +196,15 @@ export interface WorkflowNodeOutcome {
196
196
  termination?: TerminationReason;
197
197
  output?: Message;
198
198
  }
199
+ export interface ControlRequestRejection {
200
+ operation: string;
201
+ subject?: string;
202
+ reason: string;
203
+ }
199
204
  export interface WorkflowOutcome {
200
205
  nodeOutcomes: WorkflowNodeOutcome[];
201
206
  outputs: Record<string, string>;
207
+ rejection?: ControlRequestRejection;
202
208
  }
203
209
  export declare function workflowNodeOutcomeFromKernel(raw: KernelWorkflowNodeOutcome): WorkflowNodeOutcome;
204
210
  /** Per-node spawn descriptor carried in the `workflow_batch_spawned` observation. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/wasm",
3
- "version": "0.2.41",
3
+ "version": "0.2.42",
4
4
  "description": "DeepStrike WASM SDK — browser, Cloudflare Workers, Deno Deploy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "test": "node --experimental-vm-modules node_modules/.bin/jest"
16
16
  },
17
17
  "dependencies": {
18
- "@deepstrike/wasm-kernel": "0.2.41"
18
+ "@deepstrike/wasm-kernel": "0.2.42"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/jest": "^30.0.0",