@deepstrike/sdk 0.2.52 → 0.2.60

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 (148) hide show
  1. package/README.md +28 -28
  2. package/dist/agent-ir.d.ts +103 -0
  3. package/dist/agent-ir.js +134 -0
  4. package/dist/agent.d.ts +67 -0
  5. package/dist/agent.js +36 -0
  6. package/dist/collaboration/harness.js +1 -1
  7. package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
  8. package/dist/collaboration/modes/creator-verifier.js +4 -6
  9. package/dist/collaboration/pool.d.ts +8 -20
  10. package/dist/collaboration/pool.js +27 -97
  11. package/dist/compat/anthropic/mcp.d.ts +15 -0
  12. package/dist/compat/anthropic/mcp.js +10 -0
  13. package/dist/compat/openai/agent.d.ts +34 -0
  14. package/dist/compat/openai/agent.js +24 -0
  15. package/dist/governance.d.ts +1 -17
  16. package/dist/governance.js +1 -34
  17. package/dist/guardrail.d.ts +6 -0
  18. package/dist/guardrail.js +1 -0
  19. package/dist/handoff-target.d.ts +12 -0
  20. package/dist/handoff-target.js +1 -0
  21. package/dist/harness/manifest.js +0 -4
  22. package/dist/index.d.ts +19 -7
  23. package/dist/index.js +8 -5
  24. package/dist/kernel.d.ts +2 -20
  25. package/dist/knowledge/public.d.ts +29 -0
  26. package/dist/knowledge/public.js +1 -0
  27. package/dist/mcp-server.d.ts +28 -0
  28. package/dist/mcp-server.js +1 -0
  29. package/dist/memory/agent.d.ts +2 -2
  30. package/dist/memory/agent.js +2 -2
  31. package/dist/memory/durable.d.ts +16 -0
  32. package/dist/memory/durable.js +46 -0
  33. package/dist/memory/in-memory-store.d.ts +9 -7
  34. package/dist/memory/in-memory-store.js +8 -2
  35. package/dist/memory/protocols.d.ts +22 -4
  36. package/dist/memory/public.d.ts +4 -3
  37. package/dist/memory/public.js +3 -2
  38. package/dist/providers/anthropic-adapter.d.ts +47 -0
  39. package/dist/providers/anthropic-adapter.js +444 -0
  40. package/dist/providers/anthropic-compatible.d.ts +2 -3
  41. package/dist/providers/anthropic-compatible.js +8 -5
  42. package/dist/providers/anthropic.d.ts +19 -23
  43. package/dist/providers/anthropic.js +169 -395
  44. package/dist/providers/base.js +43 -3
  45. package/dist/providers/capability-router.d.ts +29 -0
  46. package/dist/providers/capability-router.js +43 -0
  47. package/dist/providers/catalog.d.ts +16 -4
  48. package/dist/providers/catalog.js +112 -21
  49. package/dist/providers/content-normalization.d.ts +57 -0
  50. package/dist/providers/content-normalization.js +238 -0
  51. package/dist/providers/content-policy.d.ts +16 -0
  52. package/dist/providers/content-policy.js +39 -0
  53. package/dist/providers/credentials.d.ts +83 -0
  54. package/dist/providers/credentials.js +190 -0
  55. package/dist/providers/endpoints.d.ts +137 -0
  56. package/dist/providers/endpoints.js +128 -0
  57. package/dist/providers/factories.js +9 -3
  58. package/dist/providers/gemini-adapter.d.ts +33 -0
  59. package/dist/providers/gemini-adapter.js +272 -0
  60. package/dist/providers/gemini.d.ts +16 -3
  61. package/dist/providers/gemini.js +97 -195
  62. package/dist/providers/model-catalog.d.ts +37 -0
  63. package/dist/providers/model-catalog.js +62 -0
  64. package/dist/providers/model-registry.d.ts +98 -0
  65. package/dist/providers/model-registry.js +315 -0
  66. package/dist/providers/ollama-adapter.d.ts +65 -0
  67. package/dist/providers/ollama-adapter.js +188 -0
  68. package/dist/providers/ollama.d.ts +9 -4
  69. package/dist/providers/ollama.js +96 -109
  70. package/dist/providers/openai-chat-dialects.d.ts +154 -0
  71. package/dist/providers/openai-chat-dialects.js +179 -0
  72. package/dist/providers/openai-chat.d.ts +46 -18
  73. package/dist/providers/openai-chat.js +418 -51
  74. package/dist/providers/openai-responses-adapter.d.ts +42 -0
  75. package/dist/providers/openai-responses-adapter.js +341 -0
  76. package/dist/providers/openai-responses.d.ts +14 -33
  77. package/dist/providers/openai-responses.js +131 -264
  78. package/dist/providers/openai.d.ts +29 -76
  79. package/dist/providers/openai.js +195 -292
  80. package/dist/providers/protocol-adapter.d.ts +34 -0
  81. package/dist/providers/protocol-adapter.js +9 -0
  82. package/dist/providers/protocol-capabilities.d.ts +34 -0
  83. package/dist/providers/protocol-capabilities.js +44 -0
  84. package/dist/providers/provider-error.d.ts +31 -0
  85. package/dist/providers/provider-error.js +149 -0
  86. package/dist/providers/public.d.ts +26 -3
  87. package/dist/providers/public.js +13 -1
  88. package/dist/providers/registry.d.ts +7 -6
  89. package/dist/providers/registry.js +47 -20
  90. package/dist/providers/request-plan.d.ts +86 -0
  91. package/dist/providers/request-plan.js +175 -0
  92. package/dist/providers/usage-normalizer.d.ts +48 -0
  93. package/dist/providers/usage-normalizer.js +96 -0
  94. package/dist/providers/vendor-profiles.d.ts +2 -15
  95. package/dist/providers/vendor-profiles.js +14 -60
  96. package/dist/runtime/canonical-kernel-step.d.ts +1 -2
  97. package/dist/runtime/canonical-kernel-step.js +47 -12
  98. package/dist/runtime/context-policy.d.ts +10 -12
  99. package/dist/runtime/context-policy.js +6 -8
  100. package/dist/runtime/durable-content.d.ts +50 -0
  101. package/dist/runtime/durable-content.js +159 -0
  102. package/dist/runtime/execution-plane.d.ts +2 -2
  103. package/dist/runtime/execution-plane.js +2 -2
  104. package/dist/runtime/kernel-event-log.js +0 -1
  105. package/dist/runtime/kernel-step.d.ts +0 -1
  106. package/dist/runtime/kernel-step.js +4 -2
  107. package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
  108. package/dist/runtime/mcp-proxy-plane.js +44 -6
  109. package/dist/runtime/output-schema.d.ts +1 -2
  110. package/dist/runtime/provider-replay.d.ts +1 -1
  111. package/dist/runtime/provider-replay.js +12 -27
  112. package/dist/runtime/reactive-session.d.ts +1 -1
  113. package/dist/runtime/reactive-session.js +2 -3
  114. package/dist/runtime/run-group.d.ts +1 -1
  115. package/dist/runtime/runner.d.ts +26 -40
  116. package/dist/runtime/runner.js +145 -63
  117. package/dist/runtime/session-log.d.ts +8 -1
  118. package/dist/runtime/session-log.js +42 -2
  119. package/dist/runtime/session-repair.d.ts +1 -1
  120. package/dist/runtime/session-repair.js +1 -1
  121. package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
  122. package/dist/runtime/sub-agent-orchestrator.js +8 -11
  123. package/dist/runtime/workflow-control-flow.d.ts +0 -4
  124. package/dist/runtime/workflow-control-flow.js +0 -16
  125. package/dist/session.d.ts +11 -0
  126. package/dist/session.js +1 -0
  127. package/dist/skill.d.ts +17 -0
  128. package/dist/skill.js +16 -0
  129. package/dist/skills/loader.d.ts +3 -0
  130. package/dist/tools/errors.d.ts +1 -3
  131. package/dist/tools/errors.js +1 -3
  132. package/dist/tools/index.d.ts +3 -0
  133. package/dist/types/agent.d.ts +21 -9
  134. package/dist/types/agent.js +30 -4
  135. package/dist/types.d.ts +128 -13
  136. package/package.json +3 -3
  137. package/dist/providers/deepseek.d.ts +0 -46
  138. package/dist/providers/deepseek.js +0 -97
  139. package/dist/providers/glm.d.ts +0 -25
  140. package/dist/providers/glm.js +0 -48
  141. package/dist/providers/kimi.d.ts +0 -23
  142. package/dist/providers/kimi.js +0 -30
  143. package/dist/providers/minimax.d.ts +0 -49
  144. package/dist/providers/minimax.js +0 -98
  145. package/dist/providers/profiles.d.ts +0 -1992
  146. package/dist/providers/profiles.js +0 -796
  147. package/dist/providers/qwen.d.ts +0 -38
  148. package/dist/providers/qwen.js +0 -97
@@ -53,7 +53,7 @@ function deriveMetaTools(permitted, opts) {
53
53
  const metaTools = new Set();
54
54
  if (permitted.has("skill") && opts.skillDir)
55
55
  metaTools.add("skill");
56
- if (permitted.has("memory") && opts.dreamStore)
56
+ if (permitted.has("memory") && opts.memoryStore)
57
57
  metaTools.add("memory");
58
58
  if (permitted.has("knowledge") && opts.knowledgeSource)
59
59
  metaTools.add("knowledge");
@@ -67,7 +67,7 @@ function availableMetaTools(opts) {
67
67
  const metaTools = new Set();
68
68
  if (opts.skillDir)
69
69
  metaTools.add("skill");
70
- if (opts.dreamStore)
70
+ if (opts.memoryStore)
71
71
  metaTools.add("memory");
72
72
  if (opts.knowledgeSource)
73
73
  metaTools.add("knowledge");
@@ -129,20 +129,16 @@ export class SubAgentOrchestrator {
129
129
  systemPrompt,
130
130
  sessionLog: ctx.sessionLog,
131
131
  skillDir: metaTools.has("skill") ? ctx.parentOpts.skillDir : undefined,
132
- dreamStore: metaTools.has("memory") ? ctx.parentOpts.dreamStore : undefined,
132
+ memoryStore: metaTools.has("memory") ? ctx.parentOpts.memoryStore : undefined,
133
133
  knowledgeSource: metaTools.has("knowledge") ? ctx.parentOpts.knowledgeSource : undefined,
134
134
  enablePlanTool: metaTools.has("update_plan") ? ctx.parentOpts.enablePlanTool : undefined,
135
135
  // Nested vehicle: the child joins the inherited runGroup for lineage/settlement only — it
136
136
  // must NOT re-reserve budget axes the parent already holds (that double-reserve squeezed the
137
137
  // child's grant to 0 and the kernel stripped its first-turn tools).
138
138
  nestedGroupVehicle: true,
139
- // The child runs under ITS OWN spec, never the parent's: the spread above would otherwise
140
- // leak the parent's `runSpec` (identity, capability filter and a LoopDriver's armed
141
- // `loopRound`, giving every child a phantom pace tool). A loop-node iteration carries its
142
- // own minimal spec to arm the pacing trap (DW-3); everything else runs spec-less as before.
143
- runSpec: ctx.spec.loopRound
144
- ? { identity: ctx.spec.identity, role: ctx.spec.role, goal: ctx.spec.goal, loopRound: ctx.spec.loopRound }
145
- : undefined,
139
+ // The child always runs under its own canonical spec, never the parent's. This preserves its
140
+ // capability ceiling, exposure baseline, identity, and optional loop pacing in one shape.
141
+ runSpec: ctx.spec,
146
142
  });
147
143
  // #2-B-ii: when the parent preempts this node (kernel `AgentPreempted`), interrupt the child —
148
144
  // cancelling its in-flight LLM call. Handle an already-aborted signal too (creation race).
@@ -258,7 +254,7 @@ export function attemptOutcomeToLoopResult(outcome) {
258
254
  /** Canonical single-node root workflow for harness / coordinator use. */
259
255
  export async function spawnStandalone(parentOpts, parentSessionId, spec, orchestrator = defaultSubAgentOrchestrator, contextInput) {
260
256
  if (spec.tokenBudget !== undefined || spec.maxTurns !== undefined || spec.maxWallMs !== undefined) {
261
- throw new Error("spawnStandalone cannot represent per-node resource caps under canonical ABI v3");
257
+ throw new Error("spawnStandalone cannot represent per-node resource caps under the canonical ABI");
262
258
  }
263
259
  const { RuntimeRunner } = await import("./runner.js");
264
260
  let captured;
@@ -272,6 +268,7 @@ export async function spawnStandalone(parentOpts, parentSessionId, spec, orchest
272
268
  ...ctx.manifest,
273
269
  agent_id: spec.identity.agentId,
274
270
  parent_session_id: parentSessionId,
271
+ permitted_capability_ids: spec.capabilityFilter?.allowedIds ?? [],
275
272
  },
276
273
  ...(contextInput ? { contextInput } : {}),
277
274
  });
@@ -12,10 +12,6 @@ export declare function dependencyOutputsNote(inputAgentIds: string[] | undefine
12
12
  export declare function classifyInstruction(labels: string[]): string;
13
13
  /** Build a tournament judge's goal: the controller's criterion + the two candidates to compare. */
14
14
  export declare function judgeGoal(criterion: string, leftOutput: string, rightOutput: string): string;
15
- /** Extract a loop stop signal from a loop iteration's output. Returns the `loopContinue` value, or
16
- * `undefined` when the agent gave no clear signal (⇒ the kernel runs the loop to `max_iters`).
17
- * Accepts `{loop_continue: bool}` or, leniently, `{done: bool}` (continue = !done). */
18
- export declare function extractLoopContinue(text: string): boolean | undefined;
19
15
  /** Extract the chosen branch label from a classifier's output. Prefers `{branch: "..."}`; falls back
20
16
  * to a bare label string that exactly matches one of the valid labels. Returns `undefined` when no
21
17
  * recognizable choice was made (the kernel then prunes every branch — a safe "none matched"). */
@@ -45,22 +45,6 @@ export function judgeGoal(criterion, leftOutput, rightOutput) {
45
45
  `criterion above.\n\n[CANDIDATE left]\n${leftOutput}\n\n[CANDIDATE right]\n${rightOutput}\n\n` +
46
46
  `Respond with ONLY a JSON object: {"winner": "left"} or {"winner": "right"}.`);
47
47
  }
48
- /** Extract a loop stop signal from a loop iteration's output. Returns the `loopContinue` value, or
49
- * `undefined` when the agent gave no clear signal (⇒ the kernel runs the loop to `max_iters`).
50
- * Accepts `{loop_continue: bool}` or, leniently, `{done: bool}` (continue = !done). */
51
- export function extractLoopContinue(text) {
52
- const v = extractJsonValue(text);
53
- if (v && typeof v === "object" && !Array.isArray(v)) {
54
- const o = v;
55
- if (typeof o.loop_continue === "boolean")
56
- return o.loop_continue;
57
- if (typeof o.loopContinue === "boolean")
58
- return o.loopContinue;
59
- if (typeof o.done === "boolean")
60
- return !o.done;
61
- }
62
- return undefined;
63
- }
64
48
  /** Extract the chosen branch label from a classifier's output. Prefers `{branch: "..."}`; falls back
65
49
  * to a bare label string that exactly matches one of the valid labels. Returns `undefined` when no
66
50
  * recognizable choice was made (the kernel then prunes every branch — a safe "none matched"). */
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Public user-session descriptor. This is distinct from persisted `SessionData` and the runtime
3
+ * `SessionLog`: it carries caller-visible continuity metadata, not messages or journal events.
4
+ */
5
+ export interface Session {
6
+ id: string;
7
+ userId?: string;
8
+ state?: Record<string, unknown>;
9
+ metadata?: Record<string, unknown>;
10
+ providerOptions?: Record<string, unknown>;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ /** spc_001 §2.4: public Skill contract, built directly on `SKILL.md`-style frontmatter files. */
2
+ export interface Skill {
3
+ name: string;
4
+ description?: string;
5
+ instructions?: string;
6
+ resources?: unknown[];
7
+ scripts?: unknown[];
8
+ tools?: unknown[];
9
+ mcpServers?: unknown[];
10
+ knowledge?: unknown[];
11
+ metadata?: Record<string, unknown>;
12
+ providerOptions?: Record<string, unknown>;
13
+ }
14
+ /** Loads one skill by name from a skill directory, reusing the existing frontmatter scanner and
15
+ * body reader — does not reimplement directory scanning. Returns `null` if the skill file is
16
+ * absent (mirrors `readSkillFile`'s own not-found signal). */
17
+ export declare function loadSkill(skillDir: string, name: string): Promise<Skill | null>;
package/dist/skill.js ADDED
@@ -0,0 +1,16 @@
1
+ import { readSkillFile, scanSkillDir } from "./skills/loader.js";
2
+ /** Loads one skill by name from a skill directory, reusing the existing frontmatter scanner and
3
+ * body reader — does not reimplement directory scanning. Returns `null` if the skill file is
4
+ * absent (mirrors `readSkillFile`'s own not-found signal). */
5
+ export async function loadSkill(skillDir, name) {
6
+ const body = await readSkillFile(skillDir, name);
7
+ if (body === null)
8
+ return null;
9
+ const metas = await scanSkillDir(skillDir);
10
+ const meta = metas.find(m => m.name === name);
11
+ return {
12
+ name: meta?.name ?? name,
13
+ description: meta?.description,
14
+ instructions: body,
15
+ };
16
+ }
@@ -4,6 +4,9 @@ export interface SkillMetadata {
4
4
  whenToUse?: string;
5
5
  effort?: number;
6
6
  estimatedTokens?: number;
7
+ /** Optional structured grants supplied by the SDK caller. They are not parsed from simple
8
+ * SKILL.md frontmatter: the canonical kernel validates their attenuation at activation. */
9
+ capabilityGrants?: Array<Record<string, unknown>>;
7
10
  /** P1-B tool gating: tool ids this skill needs. When the skill is active, the kernel narrows the
8
11
  * exposed toolset to `stable-core ∪ allowedTools`. Parsed from `allowed_tools:` frontmatter
9
12
  * (comma-separated or `[a, b]`). Absent ⇒ the skill does not narrow (back-compat). */
@@ -52,8 +52,6 @@ export declare function formatToolError(err: unknown): string;
52
52
  * - body throws any other `Error` → `{success:false, code: error.code ?? "internal", error: error.message}`
53
53
  * - body throws a non-Error → `{success:false, code:"internal", error: formatToolError(...)}`
54
54
  *
55
- * The classic `tool()` factory is unchanged. `safeTool` is opt-in: import and switch one tool at
56
- * a time. Designed for the consumer-side pattern users had to hand-roll to escape the legacy
57
- * `String(err)` foot-gun.
55
+ * `safeTool` is opt-in and returns a structured error envelope instead of `String(err)`.
58
56
  */
59
57
  export declare function safeTool<T = unknown>(name: string, description: string, parameters: Record<string, unknown>, fn: (args: Record<string, unknown>, ctx?: ToolExecContext) => Promise<ToolEnvelope<T> | T> | ToolEnvelope<T> | T): RegisteredTool;
@@ -84,9 +84,7 @@ export function formatToolError(err) {
84
84
  * - body throws any other `Error` → `{success:false, code: error.code ?? "internal", error: error.message}`
85
85
  * - body throws a non-Error → `{success:false, code:"internal", error: formatToolError(...)}`
86
86
  *
87
- * The classic `tool()` factory is unchanged. `safeTool` is opt-in: import and switch one tool at
88
- * a time. Designed for the consumer-side pattern users had to hand-roll to escape the legacy
89
- * `String(err)` foot-gun.
87
+ * `safeTool` is opt-in and returns a structured error envelope instead of `String(err)`.
90
88
  */
91
89
  export function safeTool(name, description, parameters, fn) {
92
90
  const wrapped = async (args, ctx) => {
@@ -17,6 +17,9 @@ export interface ToolExecContext {
17
17
  export interface RegisteredTool {
18
18
  schema: ToolSchema;
19
19
  execute(args: Record<string, unknown>, ctx?: ToolExecContext): Promise<string> | AsyncIterable<ToolChunk>;
20
+ /** spc_001: vendor-specific extension bag, keyed by provider name. Preserved through
21
+ * normalization/lowering, never flattened into portable fields. */
22
+ providerOptions?: Record<string, unknown>;
20
23
  }
21
24
  export declare function tool(name: string, description: string, parameters: Record<string, unknown>, fn: (args: Record<string, unknown>, ctx?: ToolExecContext) => Promise<string> | string): RegisteredTool;
22
25
  export declare function streamingTool(name: string, description: string, parameters: Record<string, unknown>, fn: (args: Record<string, unknown>, ctx?: ToolExecContext) => AsyncIterable<ToolChunk>): RegisteredTool;
@@ -46,8 +46,7 @@ export interface AgentRunSpec {
46
46
  * advertised before any skill activates, so `exposed = meta ∪ ((baseline ∪ stableCore ∪
47
47
  * ⋃ activeSkills.allowed_tools) ∩ ceiling)`. That makes narrow→wide progressive disclosure
48
48
  * expressible: a tool can be reachable after `skill(x)` without being advertised beforehand.
49
- * Absent legacy behavior (ceiling + errs-open skill narrowing). `[]` is meaningful and
50
- * distinct from absent: the minimal surface (meta-tools + stable-core only). Entries outside
49
+ * Absent and `[]` both mean the minimal surface (meta-tools + stable-core only). Entries outside
51
50
  * the ceiling silently intersect away. Lowered from `RuntimeOptions.baselineToolIds`. */
52
51
  exposureBaseline?: string[];
53
52
  /** M1/G3: per-agent model preference (e.g. "opus"/"sonnet"/"haiku"); the host resolves it to a
@@ -68,6 +67,9 @@ export interface AgentRunSpec {
68
67
  * parent's meta-tool availability (same mechanism trusted workflow nodes use) — the child's surface
69
68
  * is a subset of the parent's, never a privilege escalation. */
70
69
  toolAccess?: "inherit" | "filtered";
70
+ /** spc_001: vendor-specific extension bag, keyed by provider name (e.g. `{ openai: {...} }`).
71
+ * Preserved through normalization/lowering, never flattened into portable fields. */
72
+ providerOptions?: Record<string, unknown>;
71
73
  }
72
74
  /** Kernel process-table observation (Phase 3 canonical spawn signal). */
73
75
  export interface AgentProcessChangedObservation {
@@ -87,7 +89,7 @@ export interface LoopResult {
87
89
  finalMessage?: Message;
88
90
  turnsUsed: number;
89
91
  totalTokensUsed: number;
90
- /** A#2 v2 loop stop signal: a loop iteration sets `false` to end the loop before `max_iters`.
92
+ /** loop-control loop stop signal: a loop iteration sets `false` to end the loop before `max_iters`.
91
93
  * `undefined` (every non-loop result) ⇒ no opinion → run to the cap. Sent only when set. */
92
94
  loopContinue?: boolean;
93
95
  /** A#2 classify routing: a classifier node reports the chosen branch label here; the kernel runs
@@ -96,8 +98,8 @@ export interface LoopResult {
96
98
  /** A#2 tournament verdict: a judge reports the winning entrant's agent id here. Sent only when set. */
97
99
  tournamentWinner?: string;
98
100
  /** ③ loop-agent pacing: the kernel-adjudicated after-round decision, surfaced by the orchestrator
99
- * from the child's done event. For a loop-node iteration this is the PRIMARY continuation
100
- * vocabulary (stop → loopContinue=false); the legacy text-sniffed signal is the fallback.
101
+ * from the child's done event. For a loop-node iteration this is the only continuation
102
+ * vocabulary (stop → loopContinue=false).
101
103
  * SDK-internal — stripped by `subAgentResultToKernel`. */
102
104
  paceDecision?: import("../runtime/kernel-step.js").PaceDecision;
103
105
  /** Two-axis AttemptLoop result. Serialized alongside `termination` so hosts can observe judge
@@ -162,6 +164,14 @@ export type WorkflowTaskSpec = {
162
164
  export type NodeTrust = "trusted" | "quarantined";
163
165
  export type WorkflowDependencyPolicy = "all_success" | "accept_partial" | "all_terminal" | "optional";
164
166
  export type WorkflowNodeStatus = "completed" | "completed_partial" | "failed" | "skipped_upstream_failed";
167
+ /** Host-observed, deterministic scheduling inputs for one workflow node. They never originate
168
+ * from model-authored workflow tools. */
169
+ export interface SchedulingFactors {
170
+ deadlineUrgency?: number;
171
+ processPriority?: number;
172
+ resourcePressure?: number;
173
+ budgetPressure?: number;
174
+ }
165
175
  export declare function workflowNodeStatusFromTermination(termination: TerminationReason | string): WorkflowNodeStatus;
166
176
  /** One node in a declarative workflow DAG (camelCase host shape). */
167
177
  export interface WorkflowNodeSpec {
@@ -178,7 +188,7 @@ export interface WorkflowNodeSpec {
178
188
  /** G2: make this a deterministic *reduce* node — it runs no LLM agent. The runner routes it to the
179
189
  * registered reducer of this name, over its `dependsOn` nodes' outputs (dedupe / filter / merge). */
180
190
  reducer?: string;
181
- /** A#2 v2: make this a *loop* node — re-run its agent up to `maxIters` times. An iteration may end
191
+ /** loop-control: make this a *loop* node — re-run its agent up to `maxIters` times. An iteration may end
182
192
  * the loop early by reporting `loopContinue: false` (the runner solicits this from the agent). */
183
193
  loop?: {
184
194
  maxIters: number;
@@ -202,6 +212,8 @@ export interface WorkflowNodeSpec {
202
212
  maxTurns?: number;
203
213
  /** O3: cap this node's child run at `maxWallMs` wall-clock milliseconds. */
204
214
  maxWallMs?: number;
215
+ /** Host-only scheduling facts used with the configured deterministic scheduler policy. */
216
+ schedulingFactors?: SchedulingFactors;
205
217
  /** Indices of nodes this node depends on. */
206
218
  dependsOn?: number[];
207
219
  /** How dependency terminal states gate this node. Defaults to `all_success`. */
@@ -270,7 +282,7 @@ export interface WorkflowSpawnInfo {
270
282
  left: string;
271
283
  right: string;
272
284
  };
273
- /** A#2 v2: present only for a *loop* iteration spawn — the loop's `max_iters`. Marks the spawn as a
285
+ /** loop-control: present only for a *loop* iteration spawn — the loop's `max_iters`. Marks the spawn as a
274
286
  * loop iteration so the runner solicits + reports a `loopContinue` stop signal. */
275
287
  loop_max_iters?: number;
276
288
  /** A#2: present only for a *classify* spawn — the branch labels the classifier must choose among.
@@ -315,10 +327,10 @@ export declare function workflowSpecToKernel(spec: WorkflowSpec): Record<string,
315
327
  * (true loop-until-done / dynamic fan-out). Give it to nodes meant to fan out; the runner intercepts
316
328
  * the call and routes the nodes to the parent kernel (the child's own kernel holds no workflow). */
317
329
  export declare const submitWorkflowNodesTool: ToolSchema;
318
- /** M5 v1 (flatten): the tool an agent calls to **author a sub-workflow** — a cohesive DAG of nodes
330
+ /** workflow authoring: the tool an agent calls to **author a sub-workflow** — a cohesive DAG of nodes
319
331
  * (incl. loop/classify/tournament/reduce) composed onto the running workflow. Mechanically it lowers
320
332
  * to the same append path as `submit_workflow_nodes` (a `WorkflowSpec` is a node batch), but reads as
321
- * "write a harness" rather than "append nodes". v2 adds top-level bootstrap (the `LoadWorkflow`
333
+ * "write a harness" rather than "append nodes". Top-level bootstrap uses (the `LoadWorkflow`
322
334
  * kernel syscall) so a plain run can start a workflow from scratch. */
323
335
  export declare const startWorkflowTool: ToolSchema;
324
336
  /** Build a sub-agent run spec for a kernel-generated workflow node. */
@@ -36,7 +36,7 @@ export function agentRunSpecToKernel(spec) {
36
36
  ...(spec.loopRound.defaultAction !== undefined ? { default_action: spec.loopRound.defaultAction } : {}),
37
37
  };
38
38
  }
39
- // Exposure baseline: `undefined` ⇒ omit the field entirely (kernel `None` = legacy behavior);
39
+ // Exposure baseline: `undefined` ⇒ omit the field entirely (kernel canonical default);
40
40
  // `[]` ⇒ send `[]` (kernel `Some([])` = the minimal surface). The unset/minimal distinction is
41
41
  // load-bearing, so this is deliberately NOT the `length > 0` idiom `allowedToolIds` uses.
42
42
  if (spec.exposureBaseline !== undefined)
@@ -240,6 +240,7 @@ function nodeKindToKernel(n) {
240
240
  * whole spec) and `submit_workflow_nodes` (R3-1 runtime append) so the two encodings never drift. */
241
241
  export function workflowNodeSpecToKernel(n) {
242
242
  const kind = nodeKindToKernel(n);
243
+ const schedulingFactors = schedulingFactorsToKernel(n.schedulingFactors);
243
244
  return {
244
245
  task: workflowTaskToKernel(n.task),
245
246
  role: n.role,
@@ -256,16 +257,41 @@ export function workflowNodeSpecToKernel(n) {
256
257
  // O3: per-node turn / wall-clock caps (additive; omitted when unset).
257
258
  ...(n.maxTurns != null ? { max_turns: n.maxTurns } : {}),
258
259
  ...(n.maxWallMs != null ? { max_wall_ms: n.maxWallMs } : {}),
260
+ ...(schedulingFactors ? { scheduling_factors: schedulingFactors } : {}),
259
261
  ...(n.dependsOn && n.dependsOn.length ? { depends_on: n.dependsOn } : {}),
260
262
  dep_policy: n.depPolicy ?? "all_success",
261
263
  };
262
264
  }
265
+ function schedulingFactorsToKernel(factors) {
266
+ if (factors === undefined)
267
+ return undefined;
268
+ const allowed = new Set(["deadlineUrgency", "processPriority", "resourcePressure", "budgetPressure"]);
269
+ const unknown = Object.keys(factors).filter(key => !allowed.has(key));
270
+ if (unknown.length > 0)
271
+ throw new TypeError(`unknown scheduling factor(s): ${unknown.join(", ")}`);
272
+ const out = {};
273
+ for (const [host, kernel] of Object.entries({
274
+ deadlineUrgency: "deadline_urgency",
275
+ processPriority: "process_priority",
276
+ resourcePressure: "resource_pressure",
277
+ budgetPressure: "budget_pressure",
278
+ })) {
279
+ const value = factors[host];
280
+ if (value !== undefined) {
281
+ if (!Number.isSafeInteger(value) || value < 0) {
282
+ throw new RangeError(`schedulingFactors.${host} must be a non-negative safe integer`);
283
+ }
284
+ out[kernel] = value;
285
+ }
286
+ }
287
+ return out;
288
+ }
263
289
  /** Map a host `WorkflowSpec` to the canonical workflow-root JSON. */
264
290
  export function workflowSpecToKernel(spec) {
265
291
  return { nodes: spec.nodes.map(workflowNodeSpecToKernel) };
266
292
  }
267
293
  /** Shared JSON-Schema for a workflow-node batch (a DAG). Used by both `submit_workflow_nodes`
268
- * (append) and `start_workflow` (M5 v1: author a sub-workflow), so the two tools never drift. */
294
+ * (append) and `start_workflow` (workflow authoring: author a sub-workflow), so the two tools never drift. */
269
295
  const workflowNodesArraySchema = {
270
296
  type: "array",
271
297
  description: "Workflow nodes (a DAG); each runs as a gated sub-agent. A node may declare ONE control-flow kind " +
@@ -391,10 +417,10 @@ export const submitWorkflowNodesTool = {
391
417
  required: ["nodes"],
392
418
  }),
393
419
  };
394
- /** M5 v1 (flatten): the tool an agent calls to **author a sub-workflow** — a cohesive DAG of nodes
420
+ /** workflow authoring: the tool an agent calls to **author a sub-workflow** — a cohesive DAG of nodes
395
421
  * (incl. loop/classify/tournament/reduce) composed onto the running workflow. Mechanically it lowers
396
422
  * to the same append path as `submit_workflow_nodes` (a `WorkflowSpec` is a node batch), but reads as
397
- * "write a harness" rather than "append nodes". v2 adds top-level bootstrap (the `LoadWorkflow`
423
+ * "write a harness" rather than "append nodes". Top-level bootstrap uses (the `LoadWorkflow`
398
424
  * kernel syscall) so a plain run can start a workflow from scratch. */
399
425
  export const startWorkflowTool = {
400
426
  name: "start_workflow",
package/dist/types.d.ts CHANGED
@@ -26,8 +26,70 @@ export interface ToolResultPart {
26
26
  callId: string;
27
27
  output: string;
28
28
  isError: boolean;
29
+ /** Structured tool output. Provider boundaries normalize this into one canonical block list
30
+ * and reject `output` when it disagrees with the deterministic text projection. */
31
+ contentParts?: ToolOutputBlock[];
29
32
  }
30
33
  export type ContentPart = TextPart | ImagePart | AudioPart | ToolResultPart;
34
+ /**
35
+ * spc_011-B-05: canonical multimodal content, additive alongside `ContentPart` during the
36
+ * migration. `ContentBlockImage`/`ContentBlockAudio`/etc.
37
+ * are distinctly named (not reusing `ImagePart`/`AudioPart`) since those names are already taken
38
+ * by `ContentPart`'s variants with a different shape (`url?/data?` inline vs `source: MediaSource`).
39
+ */
40
+ export type MediaSource = {
41
+ kind: "url";
42
+ url: string;
43
+ } | {
44
+ kind: "base64";
45
+ data: string;
46
+ } | {
47
+ kind: "fileId";
48
+ id: string;
49
+ /** Endpoint that issued this provider-owned reference. An omitted affinity constrains the
50
+ * reference to the already-resolved current endpoint. */
51
+ affinity?: {
52
+ providerId: string;
53
+ endpointId: string;
54
+ };
55
+ } | {
56
+ kind: "object";
57
+ handle: string;
58
+ owner?: string;
59
+ payloadRef?: string;
60
+ };
61
+ export interface ContentBlockText {
62
+ type: "text";
63
+ text: string;
64
+ }
65
+ export interface ContentBlockImage {
66
+ type: "image";
67
+ source: MediaSource;
68
+ mediaType?: string;
69
+ providerOptions?: Record<string, unknown>;
70
+ }
71
+ export interface ContentBlockAudio {
72
+ type: "audio";
73
+ source: MediaSource;
74
+ mediaType?: string;
75
+ providerOptions?: Record<string, unknown>;
76
+ }
77
+ export interface ContentBlockVideo {
78
+ type: "video";
79
+ source: MediaSource;
80
+ mediaType?: string;
81
+ providerOptions?: Record<string, unknown>;
82
+ }
83
+ export interface ContentBlockFile {
84
+ type: "file";
85
+ source: MediaSource;
86
+ filename?: string;
87
+ mediaType?: string;
88
+ providerOptions?: Record<string, unknown>;
89
+ }
90
+ /** Legal content returned by a tool. Deliberately excludes ToolResult, so nesting is
91
+ * unrepresentable in the canonical type. */
92
+ export type ToolOutputBlock = ContentBlockText | ContentBlockImage | ContentBlockAudio | ContentBlockVideo | ContentBlockFile;
31
93
  export interface Message {
32
94
  role: "system" | "user" | "assistant" | "tool";
33
95
  /** Plain-text content. When `contentParts` is present, this holds only the text segments. */
@@ -50,11 +112,16 @@ export interface ToolResult {
50
112
  isFatal?: boolean;
51
113
  errorKind?: ToolErrorKind;
52
114
  tokenCount?: number;
115
+ /** spc_012-N-01: same additive contract as `ToolResultPart.contentParts` (see there). */
116
+ contentParts?: ToolOutputBlock[];
53
117
  }
54
118
  export interface ToolSchema {
55
119
  name: string;
56
120
  description: string;
57
121
  parameters: string;
122
+ /** spc_001: vendor-specific extension bag, keyed by provider name. Preserved through
123
+ * normalization/lowering, never flattened into portable fields. */
124
+ providerOptions?: Record<string, unknown>;
58
125
  }
59
126
  export interface StreamEvent {
60
127
  type: string;
@@ -93,10 +160,12 @@ export interface UsageEvent extends StreamEvent {
93
160
  tools?: number;
94
161
  messages?: number;
95
162
  };
96
- /** Provider stop reason for the response — `max_tokens` (Anthropic) / `length` (OpenAI) flag an
97
- * output-cap truncation, which drives the kernel's max-output-tokens recovery. Absent when the
98
- * provider doesn't report one. */
99
- stopReason?: string;
163
+ /** Canonical provider stop reason. `max_tokens` drives the kernel's output-cap recovery. */
164
+ stopReason?: "end_turn" | "tool_use" | "max_tokens" | "stop_sequence" | "content_filter" | "other";
165
+ /** Original provider spelling for diagnostics only. RuntimeRunner never forwards it to Kernel. */
166
+ rawStopReason?: string;
167
+ /** Normalized postflight usage parsed from this same raw provider response. */
168
+ providerUsage?: ProviderUsage;
100
169
  }
101
170
  export type ToolChunk = string | {
102
171
  type: "text";
@@ -122,7 +191,7 @@ export interface ToolDeltaEvent extends StreamEvent {
122
191
  type: "tool_delta";
123
192
  callId: string;
124
193
  name: string;
125
- /** Backward-compatible text projection when the chunk carries text. */
194
+ /** Text projection when the chunk carries text. */
126
195
  delta?: string;
127
196
  chunk: Exclude<ToolChunk, string>;
128
197
  }
@@ -141,6 +210,9 @@ export interface ToolResultEvent extends StreamEvent {
141
210
  isError: boolean;
142
211
  isFatal?: boolean;
143
212
  errorKind?: ToolErrorKind;
213
+ /** spc_012-N-02: structured multimodal blocks when the tool returned non-text content
214
+ * (e.g. an MCP screenshot). `content` stays the text projection; see `ToolResultPart.contentParts`. */
215
+ contentParts?: ToolOutputBlock[];
144
216
  }
145
217
  /** R3-1: a workflow node's agent called the `submit_workflow_nodes` tool. The runner intercepts it
146
218
  * (it cannot apply to the child's own kernel — the workflow lives in the parent) and surfaces the
@@ -206,12 +278,11 @@ export interface ToolAuditFailedEvent extends StreamEvent {
206
278
  }
207
279
  /** Kernel session-entropy measurement at a completed turn boundary. "Entropy" = session
208
280
  * disorder: repetition, tool failures, rollbacks, context pressure. The component vector is
209
- * the contract; `score` is a versioned default fold (`scoreVersion`). All normalized
281
+ * the contract; `score` is the canonical default fold. All normalized
210
282
  * components are in [0, 1]. */
211
283
  export interface EntropySample {
212
284
  turn: number;
213
285
  score: number;
214
- scoreVersion: number;
215
286
  /** Context pressure after this boundary's eviction pass. */
216
287
  rho: number;
217
288
  /** Consecutive-identical-turn streak, normalized against the RepeatFuse deny rung. */
@@ -262,6 +333,40 @@ export interface TokenUsage {
262
333
  /** Prompt tokens written to cache (billed ~1.25x). Subset of inputTokens. */
263
334
  cacheCreationInputTokens?: number;
264
335
  }
336
+ /** Raw postflight token facts normalized across provider wire shapes. */
337
+ export interface ProviderUsage {
338
+ inputTokens: number;
339
+ outputTokens: number;
340
+ cacheReadInputTokens?: number;
341
+ cacheCreationInputTokens?: number;
342
+ /** Output tokens spent on hidden reasoning (OpenAI `completion_tokens_details.reasoning_tokens` /
343
+ * Responses `output_tokens_details.reasoning_tokens`). A SUBSET of `outputTokens`, not additional
344
+ * — vendors that don't report a separate count (Anthropic, Gemini via this SDK) leave this unset
345
+ * rather than guessing. */
346
+ reasoningTokens?: number;
347
+ }
348
+ /** Node-side mirror of the reserved Rust `context::measurement` types — where a
349
+ * preflight token count came from. Field names/shape intentionally match the Rust
350
+ * `MeasurementSource` enum (`kind`-tagged, snake_case variant names) so the two sides can be
351
+ * compared/round-tripped without a translation layer. A-00R removed the non-durable adaptive
352
+ * scheduler producer; the shape remains for the native provider meter implementations. */
353
+ export type MeasurementSource = {
354
+ kind: "native";
355
+ provider: string;
356
+ } | {
357
+ kind: "local_exact";
358
+ tokenizer: string;
359
+ } | {
360
+ kind: "heuristic";
361
+ };
362
+ export type MeasurementConfidence = "exact" | "high_confidence" | "low_confidence";
363
+ /** A single preflight token-count fact for a candidate render, for a specific provider/model —
364
+ * the Node counterpart of Rust's `PromptMeasurement` (spc_011-C-02). */
365
+ export interface PromptMeasurement {
366
+ inputTokens: number;
367
+ source: MeasurementSource;
368
+ confidence: MeasurementConfidence;
369
+ }
265
370
  export interface ProviderToolSpec {
266
371
  name: string;
267
372
  description: string;
@@ -326,9 +431,8 @@ export interface ProviderDescriptor {
326
431
  }
327
432
  /** Provider-native fields required to replay a turn across requests (thinking blocks, reasoning_content, etc.). */
328
433
  export interface ProviderReplay {
329
- schema_version?: 1 | 2;
330
434
  provider?: string;
331
- protocol?: ProviderProtocol;
435
+ protocol: ProviderProtocol;
332
436
  model?: string;
333
437
  /** Anthropic-style assistant content blocks (thinking, text, tool_use). */
334
438
  native_blocks?: Array<Record<string, unknown>>;
@@ -409,12 +513,23 @@ export interface LLMProvider {
409
513
  * candidate) before issuing the request. Seed any persisted replay first.
410
514
  */
411
515
  assessReplayability?(context: RenderedContext, extensions?: Record<string, unknown>): ReplayabilityAssessment;
516
+ /**
517
+ * spc_011-C-02/03: preflight token count via the provider's own native counting endpoint
518
+ * (Anthropic `messages.countTokens` and Gemini `countTokens`),
519
+ * where the vendor offers one. Optional — providers without a native endpoint simply omit it,
520
+ * and callers fall back to `FallbackEstimator` (Rust `context::token_engine`, spc_011-C-01) or
521
+ * a local tokenizer. Not currently invoked by any dispatch loop (nothing in the Rust kernel
522
+ * emits `EffectKind::MeasurePrompt` yet — see its doc comment); this method exists so the
523
+ * capability remains directly callable, but no dispatch trigger is enabled until request
524
+ * fingerprinting and durable measurement semantics are defined.
525
+ */
526
+ countTokens?(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<PromptMeasurement>;
412
527
  complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
413
528
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState,
414
529
  /** #2-B-ii: when provided, a preempting `InterruptNow` (or `interrupt()`) aborts the in-flight
415
530
  * request. SDK-client providers should forward it to the client (`{ signal }`); the runner also
416
531
  * breaks the consume loop on abort, so providers that ignore it still stop processing immediately
417
- * (only the socket lingers). Optional ⇒ backward-compatible; providers may ignore it. */
532
+ * (only the socket lingers). */
418
533
  signal?: AbortSignal): AsyncIterable<StreamEvent>;
419
534
  }
420
535
  /**
@@ -425,10 +540,10 @@ export interface AsyncSummarizer {
425
540
  summarize(archived: Message[], action: string): Promise<string>;
426
541
  }
427
542
  /**
428
- * Long-term memory summarizer for semantic `page_out` events (Layer 5 contract).
429
- * The kernel emits `page_out { tier_hint: "semantic" }`; the SDK persists an LLM summary to DreamStore.
543
+ * Durable-memory summarizer for semantic `page_out` events (Layer 5 contract).
544
+ * The kernel emits `page_out { tier_hint: "semantic" }`; the SDK persists an LLM summary to MemoryStore.
430
545
  */
431
- export interface DreamSummarizer {
546
+ export interface MemorySummarizer {
432
547
  summarize(archived: Message[], context: {
433
548
  action?: string;
434
549
  }): Promise<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.2.52",
3
+ "version": "0.2.60",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -62,7 +62,7 @@
62
62
  "README.md"
63
63
  ],
64
64
  "scripts": {
65
- "build": "tsc",
65
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc",
66
66
  "test": "node --experimental-vm-modules node_modules/.bin/jest",
67
67
  "test:e2e": "node --experimental-vm-modules node_modules/.bin/jest --testPathPattern e2e/run --testTimeout 300000",
68
68
  "test:e2e:k": "node --experimental-vm-modules node_modules/.bin/jest --testPathPattern e2e/run --testTimeout 300000",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@anthropic-ai/sdk": "^0.99.0",
75
- "@deepstrike/core": "0.2.52",
75
+ "@deepstrike/core": "0.2.60",
76
76
  "@google/generative-ai": "^0.24.1",
77
77
  "openai": "^5.23.2"
78
78
  },