@deepstrike/sdk 0.2.45 → 0.2.46

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.
@@ -255,6 +255,13 @@ export interface RuntimeOptions {
255
255
  * concurrency stays vehicle-scoped (spec §2.5).
256
256
  */
257
257
  runGroup?: RunGroup;
258
+ /**
259
+ * Set by the SubAgentOrchestrator for host-derived child runs: the child still joins the
260
+ * `runGroup` (lineage) and settles its actual terminal usage into the group ledger, but reserves
261
+ * no budget axes — group admission governs peer vehicles only. The child's caps stay local
262
+ * (kernel `maxTotalTokens` policy + `resourceQuota`). Never set this for a top-level run.
263
+ */
264
+ nestedGroupVehicle?: boolean;
258
265
  /**
259
266
  * Optional long-term memory policy (`set_memory_policy`). Tunes the kernel's memory subsystem
260
267
  * (retrieval top-k, stale-warning age, write validation, memory path). Unset leaves the kernel
@@ -559,6 +559,7 @@ export class RuntimeRunner {
559
559
  spec,
560
560
  manifest,
561
561
  sessionLog: this.opts.sessionLog,
562
+ toolAccess: spec.toolAccess,
562
563
  ...(this.opts.subAgentHarness ? { harness: this.opts.subAgentHarness } : {}),
563
564
  });
564
565
  await this.commitKernelApply(runtime, this.pendingObservations, {
@@ -1567,13 +1568,24 @@ export class RuntimeRunner {
1567
1568
  startPayload.run_spec = agentRunSpecToKernel(spec);
1568
1569
  }
1569
1570
  // Reserve capacity before start_run. The kernel enforces only this vehicle's grant and reports
1570
- // exact terminal usage against the same opaque reservation identity.
1571
+ // exact terminal usage against the same opaque reservation identity. A nested vehicle joins for
1572
+ // lineage/settlement only: it reserves no budget axes (group admission governs peer vehicles),
1573
+ // so the parent's held reservation cannot squeeze the child's grant to zero.
1571
1574
  if (this.opts.runGroup) {
1572
1575
  const g = this.opts.runGroup;
1573
- groupBudgetScope = await GroupBudgetScope.open(g, { sessionId, role: this.opts.agentId, kind: "vehicle" }, this.groupBudgetRequest());
1576
+ groupBudgetScope = await GroupBudgetScope.open(g, { sessionId, role: this.opts.agentId, kind: "vehicle" }, this.opts.nestedGroupVehicle ? { limits: {}, requested: {} } : this.groupBudgetRequest());
1574
1577
  this.activeGroupBudgetScope = groupBudgetScope;
1575
1578
  }
1576
- await this.applyKernelPolicies(runtime, groupBudgetScope);
1579
+ try {
1580
+ await this.applyKernelPolicies(runtime, groupBudgetScope);
1581
+ }
1582
+ catch (err) {
1583
+ // Admission failure (e.g. the kernel rejecting a zero-capacity grant): release the
1584
+ // reservation so it cannot linger in the group ledger, then surface the error.
1585
+ await groupBudgetScope?.release();
1586
+ this.activeGroupBudgetScope = undefined;
1587
+ throw err;
1588
+ }
1577
1589
  // Multimodal upload: seed the user's attachments (images/audio) as a history
1578
1590
  // message before start_run pushes the "[TASK STATE]" anchor. init_task does not
1579
1591
  // clear history, so order becomes [attachment user msg, "Proceed…"] — both land
@@ -89,6 +89,15 @@ export class SubAgentOrchestrator {
89
89
  const inherit = ctx.toolAccess === "inherit";
90
90
  const permitted = new Set(ctx.manifest.permitted_capability_ids ?? []);
91
91
  const metaTools = inherit ? availableMetaTools(ctx.parentOpts) : deriveMetaTools(permitted, ctx.parentOpts);
92
+ // A "filtered" spawn with no capability grants and no meta-tools resolves to a deny-all plane —
93
+ // the child model sees zero tools and reports "no tools available". Warn the host (visible, not
94
+ // fatal) with the fix, mirroring `maybeWarnFailureShapedChunk`'s tone. Exempt workflow nodes:
95
+ // `!inherit && workflow-node ⇒ quarantined ⇒ intentional deny-all, not a misconfiguration.
96
+ if (!inherit && !ctx.isWorkflowNode && permitted.size === 0 && metaTools.size === 0) {
97
+ console.warn(`[deepstrike] spawned sub-agent "${ctx.spec.identity.agentId}" resolved to zero tools ` +
98
+ `(deny-all filter). Mount tools as capabilities and grant via spec.capabilityFilter, or pass ` +
99
+ `spec.toolAccess:'inherit' to run on the parent's plane. If a tool-less child is intentional, ignore this.`);
100
+ }
92
101
  const basePlane = inherit
93
102
  ? ctx.parentOpts.executionPlane
94
103
  : new FilteredExecutionPlane(ctx.parentOpts.executionPlane, permitted, metaTools);
@@ -126,6 +135,10 @@ export class SubAgentOrchestrator {
126
135
  enablePlanTool: metaTools.has("update_plan") ? ctx.parentOpts.enablePlanTool : undefined,
127
136
  // M5 v2.1: a workflow node's `start_workflow` flattens to the parent kernel (no nested pivot).
128
137
  isWorkflowNode: ctx.isWorkflowNode,
138
+ // Nested vehicle: the child joins the inherited runGroup for lineage/settlement only — it
139
+ // must NOT re-reserve budget axes the parent already holds (that double-reserve squeezed the
140
+ // child's grant to 0 and the kernel stripped its first-turn tools).
141
+ nestedGroupVehicle: true,
129
142
  // The child runs under ITS OWN spec, never the parent's: the spread above would otherwise
130
143
  // leak the parent's `runSpec` (identity, capability filter — and a LoopDriver's armed
131
144
  // `loopRound`, giving every child a phantom pace tool). A loop-node iteration carries its
@@ -52,6 +52,13 @@ export interface AgentRunSpec {
52
52
  /** O3: per-child wall-clock cap in milliseconds (sets the child runner's `timeoutMs`; falls back to
53
53
  * the parent's). A hung child terminates `timeout` instead of stalling the parent indefinitely. */
54
54
  maxWallMs?: number;
55
+ /** Tool surface for a spawned sub-agent. Host-side only (like `modelHint`) — NOT sent to the kernel
56
+ * (`agentRunSpecToKernel` maps fields explicitly and omits it). Default `"filtered"` keeps the spawn
57
+ * path's deny-all-safe default: the child is filtered to its manifest grants, and a grant-less spawn
58
+ * resolves to zero tools. `"inherit"` runs the child on the parent's execution plane with the
59
+ * parent's meta-tool availability (same mechanism trusted workflow nodes use) — the child's surface
60
+ * is a subset of the parent's, never a privilege escalation. */
61
+ toolAccess?: "inherit" | "filtered";
55
62
  }
56
63
  /** Kernel process-table observation (Phase 3 canonical spawn signal). */
57
64
  export interface AgentProcessChangedObservation {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.2.45",
3
+ "version": "0.2.46",
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.45",
75
+ "@deepstrike/core": "0.2.46",
76
76
  "@google/generative-ai": "^0.24.1",
77
77
  "openai": "^5.23.2"
78
78
  },