@deepstrike/sdk 0.2.71 → 0.2.72

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 (77) hide show
  1. package/README.md +27 -3
  2. package/dist/advanced/public.d.ts +4 -0
  3. package/dist/advanced/public.js +2 -0
  4. package/dist/agent-facade.d.ts +19 -6
  5. package/dist/agent-facade.js +118 -20
  6. package/dist/agent-ir.d.ts +11 -5
  7. package/dist/agent-ir.js +42 -26
  8. package/dist/canonical-prefix-allowlist.d.ts +6 -0
  9. package/dist/canonical-prefix-allowlist.js +30 -0
  10. package/dist/evals/public.d.ts +50 -0
  11. package/dist/evals/public.js +25 -0
  12. package/dist/guardrail.d.ts +4 -1
  13. package/dist/handoff-target.d.ts +2 -0
  14. package/dist/handoff-target.js +7 -1
  15. package/dist/index.d.ts +10 -16
  16. package/dist/index.js +5 -7
  17. package/dist/kernel.d.ts +2 -2
  18. package/dist/knowledge/public.d.ts +2 -0
  19. package/dist/knowledge/public.js +1 -1
  20. package/dist/knowledge/source.d.ts +7 -0
  21. package/dist/knowledge/source.js +20 -1
  22. package/dist/memory/protocols.d.ts +2 -2
  23. package/dist/projection-pairs.d.ts +43 -0
  24. package/dist/projection-pairs.js +9 -0
  25. package/dist/providers/anthropic-adapter.d.ts +2 -2
  26. package/dist/providers/anthropic.d.ts +4 -4
  27. package/dist/providers/base.d.ts +5 -5
  28. package/dist/providers/content-normalization.d.ts +4 -4
  29. package/dist/providers/gemini-adapter.d.ts +2 -2
  30. package/dist/providers/gemini.d.ts +3 -3
  31. package/dist/providers/ollama-adapter.d.ts +2 -2
  32. package/dist/providers/ollama.d.ts +2 -2
  33. package/dist/providers/openai-chat.d.ts +4 -4
  34. package/dist/providers/openai-responses-adapter.d.ts +2 -2
  35. package/dist/providers/openai-responses.d.ts +2 -2
  36. package/dist/providers/openai.d.ts +4 -4
  37. package/dist/providers/protocol-adapter.d.ts +2 -2
  38. package/dist/providers/protocol-capabilities.d.ts +1 -0
  39. package/dist/providers/protocol-capabilities.js +3 -0
  40. package/dist/providers/public.d.ts +4 -2
  41. package/dist/providers/public.js +2 -1
  42. package/dist/providers/replay-validator.d.ts +3 -3
  43. package/dist/runtime/archive.d.ts +7 -7
  44. package/dist/runtime/canonical-kernel-step.d.ts +2 -2
  45. package/dist/runtime/context-manager.d.ts +56 -0
  46. package/dist/runtime/context-manager.js +112 -0
  47. package/dist/runtime/eval.d.ts +2 -2
  48. package/dist/runtime/kernel-step.d.ts +5 -5
  49. package/dist/runtime/provider-replay.d.ts +2 -2
  50. package/dist/runtime/public.d.ts +22 -0
  51. package/dist/runtime/public.js +11 -0
  52. package/dist/runtime/replay-fixture.d.ts +3 -3
  53. package/dist/runtime/replay-fixture.js +1 -1
  54. package/dist/runtime/replay-provider.d.ts +4 -4
  55. package/dist/runtime/replay-provider.js +1 -1
  56. package/dist/runtime/runner.d.ts +17 -5
  57. package/dist/runtime/runner.js +110 -37
  58. package/dist/runtime/session-log.d.ts +1 -1
  59. package/dist/runtime/session-repair.d.ts +2 -2
  60. package/dist/runtime/workflow-control-flow.d.ts +1 -1
  61. package/dist/runtime/workflow-control-flow.js +16 -2
  62. package/dist/runtime-classification.d.ts +161 -0
  63. package/dist/runtime-classification.js +66 -0
  64. package/dist/runtime-language.d.ts +32 -0
  65. package/dist/runtime-language.js +51 -0
  66. package/dist/skill.d.ts +31 -5
  67. package/dist/types/agent.d.ts +17 -4
  68. package/dist/types.d.ts +22 -12
  69. package/dist/workflow/definition.d.ts +19 -0
  70. package/dist/workflow/definition.js +29 -0
  71. package/dist/workflow/public.d.ts +3 -1
  72. package/dist/workflow/public.js +1 -0
  73. package/package.json +16 -2
  74. package/dist/compat/anthropic/mcp.d.ts +0 -15
  75. package/dist/compat/anthropic/mcp.js +0 -10
  76. package/dist/compat/openai/agent.d.ts +0 -34
  77. package/dist/compat/openai/agent.js +0 -24
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  </a>
5
5
  </p>
6
6
 
7
- # DeepStrike Node.js SDK
7
+ # DeepStrike Node.js SDK (0.2.72)
8
8
 
9
9
  Build Node.js Agents with providers, typed tools, memory, Skills, delegation, workflows, and durable sessions. The SDK keeps the Agent's long-running work explicit through stream events, SessionLog evidence, tool policies, and host-provided integrations.
10
10
 
@@ -87,9 +87,11 @@ The root export is the **Agent intent layer** — what you reach for to define a
87
87
  | `@deepstrike/sdk/memory` | `MemoryStore`, `WorkingMemory`, `InMemoryMemoryStore`, `rankMemories`, `extractSessionMemories`, `KnowledgeSource` |
88
88
  | `@deepstrike/sdk/harness` | `AttemptLoop`, body/judge/carry policies, `judge` |
89
89
  | `@deepstrike/sdk/os` | profiles, `KernelPrimitivesDashboard`, `primitiveForKind` / `KernelPrimitive`, signals, `PermissionManager`, replay-testing utilities |
90
- | `@deepstrike/sdk/advanced` | RuntimeRunner, SessionLog, execution planes, kernel diagnostics, and low-level orchestration escape hatches |
90
+ | `@deepstrike/sdk/runtime` | RuntimeRunner, SessionLog, runtime projections, and host execution helpers |
91
+ | `@deepstrike/sdk/evals` | Public evaluation language: `judge`, criteria, verdicts, and schemas |
92
+ | `@deepstrike/sdk/advanced` | Kernel diagnostics and low-level orchestration escape hatches |
91
93
 
92
- > **Migration from 0.2.x:** the kernel-lowering converters (`*ToKernel`), low-level prompt/eval builders, and the `OpenAIChatProvider` alias are no longer exported from root; backend providers, planes, memory, harness, and OS utilities moved to the subpaths above. See [`MIGRATION-v0.2.30.md`](./MIGRATION-v0.2.30.md).
94
+ > **Migration from 0.2.71:** see [`MIGRATION-v0.2.71-to-v0.2.72.md`](../MIGRATION-v0.2.71-to-v0.2.72.md) for the AgentDefinition, message, runtime binding, workflow and package changes.
93
95
 
94
96
  The recipes below the Agent section that mention `RuntimeRunner` are advanced implementation examples. Import it from `@deepstrike/sdk/advanced`; application code should use the Agent and Session methods shown above.
95
97
 
@@ -114,6 +116,28 @@ console.log(delegated.output)
114
116
 
115
117
  For parallel work and dependency graphs, use `agent.workflow(...)`. Kernel scheduling and run isolation remain internal to the Agent facade.
116
118
 
119
+ ### Multimodal input
120
+
121
+ Pass image or audio parts through `AgentRunOptions.attachments`. The runner persists them with the
122
+ session and avoids injecting the same attachment twice when a session continues or resumes:
123
+
124
+ ```typescript
125
+ const session = agent.session("conversation-1")
126
+
127
+ await session.run("先看看这张图", {
128
+ attachments: [{
129
+ type: "image",
130
+ source: { kind: "url", url: "https://storage.example.com/signed/image.png" },
131
+ mediaType: "image/png",
132
+ }],
133
+ })
134
+
135
+ await session.run("继续解释其中的内容")
136
+ ```
137
+
138
+ The current public `ContentPart` contract supports text, image, audio, and tool-result parts.
139
+ Video and file attachments require an explicit content-type extension and provider conversion.
140
+
117
141
  ### Deploying to serverless / bundlers
118
142
 
119
143
  `@deepstrike/core` is a native N-API addon; its platform binary ships via `optionalDependencies`. Bundlers (Next.js/Vercel, webpack, esbuild) don't trace `.node` files by default, so the function fails at runtime with `Cannot find module '@deepstrike/core'`. Tell your bundler to treat the package as external and trace its files:
@@ -18,3 +18,7 @@ export * from "../runtime/reliability.js";
18
18
  export * from "../runtime/turn-policy.js";
19
19
  export * from "../runtime/reactive-session.js";
20
20
  export * from "../runtime/reaction-checkpoint.js";
21
+ export { projectAgentRun, projectAgentContext, projectAgentCapabilities, projectAgentGovernance, projectAgentDelegation } from "../agent-ir.js";
22
+ export type { AgentDescriptor } from "../agent-ir.js";
23
+ export { FileKernelJournal, InMemoryKernelJournal, JournalCasConflictError, JournalIntegrityError, JournalIoError, diagnoseKernelJournal, } from "../runtime/public.js";
24
+ export type { CheckpointCandidate, InstalledCheckpoint, JournalAppendReceipt, JournalEntry, JournalHead, JournalPruneReceipt, JournalRecordInput, KernelJournal, KernelJournalDiagnosis, ContextPrepared, ContextPrepareJson, ContextVerifyJson, ContextProviderPreparationRequest, EvolutionRuntime, EvolutionStore, InvocationOutcome, ModelInvocation, ProviderAttempt, ProviderAttemptRecord, ProviderAttemptStatus, UsageAccountingPolicy, ModelUsageSettlement, } from "../runtime/public.js";
@@ -14,3 +14,5 @@ export * from "../runtime/reliability.js";
14
14
  export * from "../runtime/turn-policy.js";
15
15
  export * from "../runtime/reactive-session.js";
16
16
  export * from "../runtime/reaction-checkpoint.js";
17
+ export { projectAgentRun, projectAgentContext, projectAgentCapabilities, projectAgentGovernance, projectAgentDelegation } from "../agent-ir.js";
18
+ export { FileKernelJournal, InMemoryKernelJournal, JournalCasConflictError, JournalIntegrityError, JournalIoError, diagnoseKernelJournal, } from "../runtime/public.js";
@@ -1,21 +1,24 @@
1
- import { type AgentOptions } from "./agent.js";
1
+ import { type AgentOptions, type ModelRef } from "./agent.js";
2
2
  import { type SessionLog } from "./runtime/session-log.js";
3
3
  import { type ExecutionPlane } from "./runtime/execution-plane.js";
4
4
  import { type RuntimeOptions } from "./runtime/runner.js";
5
- import type { LLMProvider, StreamEvent, TokenUsage } from "./types.js";
5
+ import type { LLMProvider, StreamEvent, TokenUsage, ContentPart } from "./types.js";
6
6
  import type { RegisteredTool } from "./tools/index.js";
7
7
  import type { MemoryRecord, MemoryRecall, MemoryScope, MemoryStore, MemoryKind } from "./memory/protocols.js";
8
8
  import type { WorkflowSpec, WorkflowOutcome, KernelAgentRole } from "./types/agent.js";
9
9
  export interface AgentDefinition extends Omit<AgentOptions, "model" | "name"> {
10
10
  name?: string;
11
- provider: LLMProvider;
11
+ /** Public model identity. Runtime resolves this through a provider binding. */
12
+ model?: ModelRef;
13
+ /** Optional host binding retained for local/custom execution. */
14
+ provider?: LLMProvider;
12
15
  tools?: RegisteredTool[];
13
16
  executionPlane?: ExecutionPlane;
14
17
  sessionLog?: SessionLog;
15
18
  maxTokens?: number;
16
19
  memoryStore?: MemoryStore;
17
20
  memoryScope?: MemoryScope;
18
- runtimeOptions?: Pick<RuntimeOptions, "memoryPolicy" | "governancePolicy" | "signalSource" | "signalPolicy" | "resourceQuota" | "onPermissionRequest" | "payloadStore" | "runGroup" | "subAgentOrchestrator" | "reducers">;
21
+ runtimeOptions?: Pick<RuntimeOptions, "memoryPolicy" | "governancePolicy" | "signalSource" | "signalPolicy" | "resourceQuota" | "onPermissionRequest" | "payloadStore" | "runGroup" | "subAgentOrchestrator" | "reducers" | "providerFor" | "initialMemory" | "skillCatalog" | "knowledgeSource" | "contextManager">;
19
22
  }
20
23
  export interface AgentRunOptions {
21
24
  session?: SessionRef;
@@ -23,6 +26,8 @@ export interface AgentRunOptions {
23
26
  signal?: AbortSignal;
24
27
  metadata?: Record<string, unknown>;
25
28
  onPermissionRequest?: RuntimeOptions["onPermissionRequest"];
29
+ /** Multimodal user input attached to this run and persisted in the session log. */
30
+ attachments?: ContentPart[];
26
31
  }
27
32
  export interface SessionRef {
28
33
  id: string;
@@ -33,6 +38,10 @@ export interface RunResult<T = string> {
33
38
  sessionId: string;
34
39
  status: "completed" | "partial" | "failed" | "cancelled";
35
40
  usage?: TokenUsage;
41
+ outputValidation?: {
42
+ ok: boolean;
43
+ errors: string[];
44
+ };
36
45
  }
37
46
  export interface AgentSession extends SessionRef {
38
47
  run(goal: string, options?: Omit<AgentRunOptions, "session">): Promise<RunResult>;
@@ -57,13 +66,16 @@ export interface RecallOptions {
57
66
  export interface DelegationRequest {
58
67
  goal: string;
59
68
  role?: KernelAgentRole;
69
+ /** Optional declared handoff target. When handoffs are declared, this is required and allowlisted. */
70
+ target?: import("./handoff-target.js").AgentRef;
60
71
  }
61
72
  export interface DelegationResult {
62
73
  output: string;
63
74
  status: "completed" | "partial" | "failed";
64
75
  nodeId?: string;
65
76
  }
66
- export interface ExecutableAgent {
77
+ /** The executable host handle created from an AgentDefinition. */
78
+ export interface AgentRuntime {
67
79
  readonly name: string;
68
80
  readonly definition: Readonly<AgentDefinition>;
69
81
  run(goal: string, options?: AgentRunOptions): Promise<RunResult>;
@@ -79,5 +91,6 @@ export interface ExecutableAgent {
79
91
  session?: SessionRef;
80
92
  leaseMs?: number;
81
93
  }): Promise<RunResult | null>;
94
+ close(): Promise<void>;
82
95
  }
83
- export declare function createAgent(definition: AgentDefinition): ExecutableAgent;
96
+ export declare function createAgent(definition: AgentDefinition): AgentRuntime;
@@ -1,6 +1,12 @@
1
+ import { normalizeAgent } from "./agent-ir.js";
1
2
  import { InMemorySessionLog } from "./runtime/session-log.js";
2
3
  import { LocalExecutionPlane } from "./runtime/execution-plane.js";
3
4
  import { RuntimeRunner } from "./runtime/runner.js";
5
+ import { extractJsonValue, schemaInstruction, validateAgainstSchema } from "./runtime/output-schema.js";
6
+ import { McpProxyPlane } from "./runtime/mcp-proxy-plane.js";
7
+ import { EnvCredentialVault } from "./runtime/credential-vault.js";
8
+ import { agentRefName } from "./handoff-target.js";
9
+ import { createTextKnowledgeSource } from "./knowledge/public.js";
4
10
  function sessionId(ref) {
5
11
  return ref?.id ?? `session-${crypto.randomUUID()}`;
6
12
  }
@@ -13,6 +19,19 @@ function statusFromDone(status) {
13
19
  return "failed";
14
20
  return "partial";
15
21
  }
22
+ function mergeGuardrailPolicies(base, guardrails) {
23
+ const policies = [base, ...(guardrails ?? []).map(guardrail => guardrail.policy)].filter((policy) => policy !== undefined);
24
+ if (!policies.length)
25
+ return undefined;
26
+ return {
27
+ ...(policies.some(policy => policy.defaultAction === "deny") ? { defaultAction: "deny" } : {}),
28
+ rules: policies.flatMap(policy => policy.rules ?? []),
29
+ vetoes: [...new Set(policies.flatMap(policy => policy.vetoes ?? []))],
30
+ rateLimits: policies.flatMap(policy => policy.rateLimits ?? []),
31
+ constraints: policies.flatMap(policy => policy.constraints ?? []),
32
+ ...(policies.some(policy => policy.surfaceDeniedInSystem === false) ? { surfaceDeniedInSystem: false } : {}),
33
+ };
34
+ }
16
35
  class AgentSessionImpl {
17
36
  owner;
18
37
  id;
@@ -33,16 +52,16 @@ class AgentSessionImpl {
33
52
  this.owner.interrupt(reason);
34
53
  }
35
54
  }
36
- class ExecutableAgentImpl {
55
+ class AgentRuntimeImpl {
37
56
  name;
38
57
  definition;
39
58
  sessionLog;
40
59
  activeRunner = null;
60
+ mcpPlane;
61
+ mcpConnection;
41
62
  constructor(definition) {
42
- if (!definition.provider)
43
- throw new TypeError("createAgent requires a provider");
44
63
  this.definition = Object.freeze({ ...definition });
45
- this.name = definition.name ?? "agent";
64
+ this.name = normalizeAgent(definition).name;
46
65
  this.sessionLog = definition.sessionLog ?? new InMemorySessionLog();
47
66
  }
48
67
  session(id = `session-${crypto.randomUUID()}`) {
@@ -88,6 +107,17 @@ class ExecutableAgentImpl {
88
107
  return store.search(this.name, request);
89
108
  }
90
109
  async delegate(request) {
110
+ const handoffs = this.definition.handoffs ?? [];
111
+ if (handoffs.length) {
112
+ if (!request.target)
113
+ throw new Error(`agent "${this.name}" requires an explicit handoff target`);
114
+ const targetName = agentRefName(request.target);
115
+ const allowed = handoffs.some(handoff => {
116
+ return agentRefName(handoff.agent) === targetName;
117
+ });
118
+ if (!allowed)
119
+ throw new Error(`agent "${this.name}" cannot hand off to "${targetName}"`);
120
+ }
91
121
  const spec = {
92
122
  nodes: [{
93
123
  task: { goal: request.goal },
@@ -107,6 +137,7 @@ class ExecutableAgentImpl {
107
137
  }
108
138
  async workflow(spec, options = {}) {
109
139
  const runner = this.createRunner({});
140
+ await this.prepareMcp();
110
141
  this.activeRunner = runner;
111
142
  try {
112
143
  return await runner.runWorkflow(spec, { sessionId: sessionId(options.session) });
@@ -140,17 +171,21 @@ class ExecutableAgentImpl {
140
171
  }
141
172
  stream(goal, options = {}) {
142
173
  const session = sessionId(options.session);
143
- const runner = this.createRunner(options);
144
- this.activeRunner = runner;
145
- const abort = () => runner.interrupt("user");
146
- if (options.signal) {
147
- if (options.signal.aborted)
148
- runner.interrupt("user");
149
- else
150
- options.signal.addEventListener("abort", abort, { once: true });
151
- }
152
- const stream = runner.run({ sessionId: session, goal });
153
- return this.clearRunnerAfter(stream, options.signal, abort);
174
+ const owner = this;
175
+ return (async function* () {
176
+ const runner = owner.createRunner(options);
177
+ await owner.prepareMcp();
178
+ owner.activeRunner = runner;
179
+ const abort = () => runner.interrupt("user");
180
+ if (options.signal) {
181
+ if (options.signal.aborted)
182
+ runner.interrupt("user");
183
+ else
184
+ options.signal.addEventListener("abort", abort, { once: true });
185
+ }
186
+ const stream = runner.run({ sessionId: session, goal, ...(options.attachments?.length ? { attachments: options.attachments } : {}) });
187
+ yield* owner.clearRunnerAfter(stream, options.signal, abort);
188
+ })();
154
189
  }
155
190
  async run(goal, options = {}) {
156
191
  const session = sessionId(options.session);
@@ -163,11 +198,15 @@ class ExecutableAgentImpl {
163
198
  const started = [...persisted].reverse().find(entry => entry.event.kind === "run_started");
164
199
  const usageEvent = [...events].reverse().find(event => event.type === "usage");
165
200
  const output = events.filter(event => event.type === "text_delta").map(event => String(event.delta ?? "")).join("");
201
+ const outputValidation = this.definition.outputSchema
202
+ ? validateAgainstSchema(extractJsonValue(output), this.definition.outputSchema)
203
+ : undefined;
166
204
  return {
167
205
  output,
168
206
  runId: started?.event.kind === "run_started" ? started.event.run_id : `run-${crypto.randomUUID()}`,
169
207
  sessionId: session,
170
- status: error ? "failed" : statusFromDone(done?.status ?? "partial"),
208
+ status: error || outputValidation && !outputValidation.ok ? "failed" : statusFromDone(done?.status ?? "partial"),
209
+ ...(outputValidation ? { outputValidation } : {}),
171
210
  ...(usageEvent?.totalTokens !== undefined ? {
172
211
  usage: {
173
212
  inputTokens: usageEvent.inputTokens ?? 0,
@@ -179,24 +218,83 @@ class ExecutableAgentImpl {
179
218
  }
180
219
  async *resume(id, options = {}) {
181
220
  const runner = this.createRunner(options);
221
+ await this.prepareMcp();
182
222
  this.activeRunner = runner;
183
223
  yield* this.clearRunnerAfter(runner.wake(id), options.signal, () => runner.interrupt("user"));
184
224
  }
185
225
  interrupt(reason = "user") {
186
226
  this.activeRunner?.interrupt(reason);
187
227
  }
228
+ async close() {
229
+ await this.mcpConnection;
230
+ await this.mcpPlane?.disconnect();
231
+ this.mcpPlane = undefined;
232
+ this.mcpConnection = undefined;
233
+ }
234
+ async prepareMcp() {
235
+ if (!this.mcpPlane || this.mcpConnection) {
236
+ await this.mcpConnection;
237
+ return;
238
+ }
239
+ this.mcpConnection = this.mcpPlane.connect();
240
+ await this.mcpConnection;
241
+ }
188
242
  createRunner(options) {
243
+ const model = this.definition.model;
244
+ const provider = this.definition.provider
245
+ ?? (typeof model === "string" ? this.definition.runtimeOptions?.providerFor?.(model) : undefined);
246
+ if (!provider) {
247
+ throw new Error(`agent "${this.name}" has no runtime provider binding for model ${typeof this.definition.model === "string" ? this.definition.model : "(unresolved)"}`);
248
+ }
249
+ if (this.definition.executionPlane && this.definition.mcpServers?.length) {
250
+ throw new Error("agent mcpServers cannot be combined with a custom executionPlane");
251
+ }
189
252
  const plane = this.definition.executionPlane
190
- ?? (this.definition.tools ?? []).reduce((current, currentTool) => current.register(currentTool), new LocalExecutionPlane());
253
+ ?? (this.definition.mcpServers?.length
254
+ ? (() => {
255
+ const servers = Object.fromEntries(this.definition.mcpServers.map(server => {
256
+ if (server.transport.kind !== "stdio") {
257
+ throw new Error(`agent MCP transport "${server.transport.kind}" is not supported by the local runtime`);
258
+ }
259
+ if (server.auth && Object.keys(server.auth).length > 0) {
260
+ throw new Error(`agent MCP server "${server.name ?? server.transport.command}" auth requires an explicit CredentialVault binding`);
261
+ }
262
+ return [server.name ?? server.transport.command, {
263
+ command: server.transport.command,
264
+ ...(server.transport.args ? { args: server.transport.args } : {}),
265
+ }];
266
+ }));
267
+ this.mcpPlane ??= new McpProxyPlane({ servers, vault: new EnvCredentialVault() });
268
+ return this.mcpPlane;
269
+ })()
270
+ : (this.definition.tools ?? []).reduce((current, currentTool) => current.register(currentTool), new LocalExecutionPlane()));
271
+ if (this.definition.mcpServers?.length && this.definition.tools?.length) {
272
+ plane.register(...this.definition.tools);
273
+ }
191
274
  const runtime = {
192
- provider: this.definition.provider,
275
+ provider,
276
+ ...(mergeGuardrailPolicies(this.definition.runtimeOptions?.governancePolicy, this.definition.guardrails)
277
+ ? { governancePolicy: mergeGuardrailPolicies(this.definition.runtimeOptions?.governancePolicy, this.definition.guardrails) }
278
+ : {}),
279
+ ...(this.definition.capabilityFilter ? { capabilityFilter: this.definition.capabilityFilter } : {}),
193
280
  executionPlane: plane,
194
281
  sessionLog: this.sessionLog,
195
282
  maxTokens: this.definition.maxTokens ?? 32_000,
196
- ...(this.definition.instructions ? { systemPrompt: this.definition.instructions } : {}),
283
+ ...(this.definition.instructions || this.definition.outputSchema ? {
284
+ systemPrompt: [
285
+ this.definition.instructions,
286
+ this.definition.outputSchema ? schemaInstruction(this.definition.outputSchema) : undefined,
287
+ ].filter((part) => Boolean(part)).join("\n\n"),
288
+ } : {}),
197
289
  ...(options.maxTurns !== undefined ? { maxTurns: options.maxTurns } : {}),
198
290
  ...(this.definition.memoryStore ? { memoryStore: this.definition.memoryStore } : {}),
199
291
  ...(this.definition.memoryScope ? { memoryScope: this.definition.memoryScope } : {}),
292
+ ...(this.definition.skills?.length ? { skillCatalog: this.definition.skills } : {}),
293
+ ...(!this.definition.runtimeOptions?.knowledgeSource && this.definition.knowledge?.some(item => item.source.kind === "text") ? {
294
+ knowledgeSource: createTextKnowledgeSource(this.definition.knowledge
295
+ .filter((item) => item.source.kind === "text")
296
+ .map(item => ({ id: item.id, name: item.name, content: item.source.content }))),
297
+ } : {}),
200
298
  agentId: this.name,
201
299
  ...(this.definition.runtimeOptions ?? {}),
202
300
  ...(options.onPermissionRequest ? { onPermissionRequest: options.onPermissionRequest } : {}),
@@ -215,5 +313,5 @@ class ExecutableAgentImpl {
215
313
  }
216
314
  }
217
315
  export function createAgent(definition) {
218
- return new ExecutableAgentImpl(definition);
316
+ return new AgentRuntimeImpl(definition);
219
317
  }
@@ -1,3 +1,4 @@
1
+ import type { AgentDefinition } from "./agent-facade.js";
1
2
  import { Agent, type AgentOptions, type ModelRef } from "./agent.js";
2
3
  import type { Guardrail } from "./guardrail.js";
3
4
  import type { Handoff } from "./handoff-target.js";
@@ -15,7 +16,7 @@ export interface AgentToolDefinition {
15
16
  }
16
17
  /** A JSON-friendly Agent definition accepted by `normalizeAgent`. It is deliberately declarative:
17
18
  * executable tools still enter the SDK through `AgentOptions.tools`. */
18
- export interface AgentDefinition extends Omit<AgentOptions, "tools"> {
19
+ export interface AgentDescriptor extends Omit<AgentOptions, "tools"> {
19
20
  tools?: Array<RegisteredTool | AgentToolDefinition>;
20
21
  }
21
22
  export interface AgentToolIR {
@@ -85,19 +86,24 @@ export interface AgentSpec {
85
86
  guardrails?: Guardrail[];
86
87
  metadata?: Record<string, unknown>;
87
88
  /** Declared capabilities. This descriptive view grants nothing by itself. */
88
- capabilities: AgentCapabilityIR[];
89
+ readonly capabilities: AgentCapabilityIR[];
89
90
  /** Host ceiling copied from the public Agent, when supplied. Empty axes remain non-narrowing. */
90
91
  capabilityFilter?: AgentCapabilityFilter;
91
92
  /** The declarations that survive the supplied local ceiling. Host mounts may narrow further. */
92
- effectiveCapabilities: AgentCapabilityIR[];
93
+ readonly effectiveCapabilities: AgentCapabilityIR[];
93
94
  /** Namespace-isolated provider extensions. Unknown namespaces are preserved verbatim. */
94
95
  extensions: Record<string, unknown>;
95
- inputs: AgentLoweringInputs;
96
96
  }
97
97
  /** Normalizes native Agents and JSON-safe descriptor objects into the one public surface used by
98
98
  * lowering. It does not interpret provider namespaces or create executable capabilities. */
99
- export declare function normalizeAgent(agent: Agent | AgentDefinition): Agent;
99
+ export declare function normalizeAgent(agent: Agent | AgentDefinition | AgentDescriptor): Agent;
100
100
  /** Pure: no provider branching, no scheduling, authorization, persistence, or Kernel wire calls.
101
101
  * Providers consume only their own namespace from `extensions`; the host decides whether declared
102
102
  * capabilities survive its existing attenuation filter. */
103
103
  export declare function lowerAgent(agent: Agent): AgentSpec;
104
+ /** Detached projections; callers can adapt them without changing AgentSpec authority. */
105
+ export declare function projectAgentRun(spec: AgentSpec): AgentLoweringInputs["run"];
106
+ export declare function projectAgentContext(spec: AgentSpec): AgentLoweringInputs["context"];
107
+ export declare function projectAgentCapabilities(spec: AgentSpec): AgentLoweringInputs["capabilities"];
108
+ export declare function projectAgentGovernance(spec: AgentSpec): AgentLoweringInputs["governance"];
109
+ export declare function projectAgentDelegation(spec: AgentSpec): AgentLoweringInputs["delegation"];
package/dist/agent-ir.js CHANGED
@@ -37,7 +37,7 @@ export function normalizeAgent(agent) {
37
37
  return agent;
38
38
  const tools = agent.tools?.map(tool => isRegisteredTool(tool) ? tool : toolDefinitionToRegisteredTool(tool));
39
39
  const { tools: _rawTools, ...options } = agent;
40
- return new Agent({ ...options, ...(tools ? { tools } : {}) });
40
+ return new Agent({ ...options, name: options.name ?? "agent", ...(tools ? { tools } : {}) });
41
41
  }
42
42
  function lowerTool(tool) {
43
43
  let parameters;
@@ -88,17 +88,7 @@ export function lowerAgent(agent) {
88
88
  const guardrails = clone(agent.guardrails ?? []);
89
89
  const memory = lowerMemory(agent.memory);
90
90
  const extensions = clone(agent.providerOptions ?? {});
91
- const capabilities = [
92
- ...tools.map(tool => ({ kind: "tool", id: tool.name, description: tool.description })),
93
- ...mcpServers.map(server => ({
94
- kind: "mcp_server",
95
- id: server.name ?? server.transport.kind,
96
- description: server.name ?? `${server.transport.kind} MCP server`,
97
- })),
98
- ...skills.map(skill => ({ kind: "skill", id: skill.name, description: skill.description ?? "" })),
99
- ];
100
91
  const capabilityFilter = agent.capabilityFilter ? clone(agent.capabilityFilter) : undefined;
101
- const effectiveCapabilities = capabilities.filter(capability => capabilityAllowed(capability, capabilityFilter));
102
92
  return {
103
93
  name: agent.name,
104
94
  ...(agent.description ? { description: agent.description } : {}),
@@ -113,22 +103,48 @@ export function lowerAgent(agent) {
113
103
  ...(handoffs.length ? { handoffs } : {}),
114
104
  ...(guardrails.length ? { guardrails } : {}),
115
105
  ...(agent.metadata ? { metadata: clone(agent.metadata) } : {}),
116
- capabilities,
106
+ get capabilities() { return declaredCapabilities(this); },
117
107
  ...(capabilityFilter ? { capabilityFilter } : {}),
118
- effectiveCapabilities,
119
- extensions,
120
- inputs: {
121
- run: { name: agent.name, ...(agent.model ? { model: clone(agent.model) } : {}) },
122
- context: {
123
- ...(agent.description ? { description: agent.description } : {}),
124
- ...(agent.instructions ? { instructions: agent.instructions } : {}),
125
- ...(agent.outputSchema ? { outputSchema: clone(agent.outputSchema) } : {}),
126
- knowledge,
127
- },
128
- capabilities: { tools, mcpServers, skills, effective: effectiveCapabilities },
129
- ...(memory ? { memory } : {}),
130
- delegation: { handoffs },
131
- governance: { guardrails },
108
+ get effectiveCapabilities() {
109
+ return declaredCapabilities(this).filter(capability => capabilityAllowed(capability, this.capabilityFilter));
132
110
  },
111
+ extensions,
112
+ };
113
+ }
114
+ /** Detached projections; callers can adapt them without changing AgentSpec authority. */
115
+ export function projectAgentRun(spec) {
116
+ return { name: spec.name, ...(spec.model !== undefined ? { model: clone(spec.model) } : {}) };
117
+ }
118
+ export function projectAgentContext(spec) {
119
+ return {
120
+ ...(spec.description !== undefined ? { description: spec.description } : {}),
121
+ ...(spec.instructions !== undefined ? { instructions: spec.instructions } : {}),
122
+ ...(spec.outputSchema !== undefined ? { outputSchema: clone(spec.outputSchema) } : {}),
123
+ knowledge: clone(spec.knowledge ?? []),
133
124
  };
134
125
  }
126
+ export function projectAgentCapabilities(spec) {
127
+ return {
128
+ tools: clone(spec.tools),
129
+ mcpServers: clone(spec.mcpServers ?? []),
130
+ skills: clone(spec.skills ?? []),
131
+ effective: clone(spec.effectiveCapabilities),
132
+ };
133
+ }
134
+ export function projectAgentGovernance(spec) {
135
+ return { guardrails: clone(spec.guardrails ?? []) };
136
+ }
137
+ export function projectAgentDelegation(spec) {
138
+ return { handoffs: clone(spec.handoffs ?? []) };
139
+ }
140
+ function declaredCapabilities(spec) {
141
+ return [
142
+ ...spec.tools.map(tool => ({ kind: "tool", id: tool.name, description: tool.description })),
143
+ ...(spec.mcpServers ?? []).map(server => ({
144
+ kind: "mcp_server",
145
+ id: server.name ?? server.transport.kind,
146
+ description: server.name ?? `${server.transport.kind} MCP server`,
147
+ })),
148
+ ...(spec.skills ?? []).map(skill => ({ kind: "skill", id: skill.name, description: skill.description ?? "" })),
149
+ ];
150
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * SPC-028-03: names that retain the Canonical prefix for ABI/runtime reasons.
3
+ * New provider-neutral types should use a domain and representation name instead.
4
+ */
5
+ export declare const CANONICAL_PREFIX_ALLOWLIST: readonly ["CanonicalAdapterInput", "CanonicalCheckpoint", "CanonicalCommit", "CanonicalKernel", "CanonicalKernelHost", "CanonicalKernelInput", "CanonicalKernelInstance", "CanonicalKernelRebuildRequiredError", "CanonicalKernelRejectedError", "CanonicalMessage", "CanonicalMessageBlock", "CanonicalPlannedStep", "CanonicalPreparation", "CanonicalPrepared", "CanonicalRejected", "CanonicalRenderedContext", "CanonicalReplayed", "CanonicalRestoreCost", "CanonicalRunnerRuntime", "CanonicalRunnerRuntimeOptions", "CanonicalStopReason", "CanonicalToolResult", "CanonicalTransition", "CanonicalTransitionOptions"];
6
+ export type AllowedCanonicalPrefixName = typeof CANONICAL_PREFIX_ALLOWLIST[number];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * SPC-028-03: names that retain the Canonical prefix for ABI/runtime reasons.
3
+ * New provider-neutral types should use a domain and representation name instead.
4
+ */
5
+ export const CANONICAL_PREFIX_ALLOWLIST = [
6
+ "CanonicalAdapterInput",
7
+ "CanonicalCheckpoint",
8
+ "CanonicalCommit",
9
+ "CanonicalKernel",
10
+ "CanonicalKernelHost",
11
+ "CanonicalKernelInput",
12
+ "CanonicalKernelInstance",
13
+ "CanonicalKernelRebuildRequiredError",
14
+ "CanonicalKernelRejectedError",
15
+ "CanonicalMessage",
16
+ "CanonicalMessageBlock",
17
+ "CanonicalPlannedStep",
18
+ "CanonicalPreparation",
19
+ "CanonicalPrepared",
20
+ "CanonicalRejected",
21
+ "CanonicalRenderedContext",
22
+ "CanonicalReplayed",
23
+ "CanonicalRestoreCost",
24
+ "CanonicalRunnerRuntime",
25
+ "CanonicalRunnerRuntimeOptions",
26
+ "CanonicalStopReason",
27
+ "CanonicalToolResult",
28
+ "CanonicalTransition",
29
+ "CanonicalTransitionOptions",
30
+ ];
@@ -0,0 +1,50 @@
1
+ /** Public evaluation language. Runtime evidence remains available through the runtime subpath. */
2
+ export { judge, buildEvalMessages, parseVerdict, verdictOutputSchema } from "../runtime/eval.js";
3
+ export type { Criterion, Verdict, VerdictDetail, JudgeArgs } from "../runtime/eval.js";
4
+ export interface DatasetCase {
5
+ id: string;
6
+ input: string;
7
+ expected?: unknown;
8
+ metadata?: Record<string, unknown>;
9
+ }
10
+ export interface Dataset {
11
+ name?: string;
12
+ cases: DatasetCase[];
13
+ }
14
+ export interface Evaluator {
15
+ name: string;
16
+ evaluate(input: {
17
+ testCase: DatasetCase;
18
+ output: string;
19
+ }): Promise<number> | number;
20
+ }
21
+ export interface EvalResult {
22
+ caseId: string;
23
+ output: string;
24
+ scores: Record<string, number>;
25
+ }
26
+ /** Optional execution evidence kept separate from the stable score/result contract. */
27
+ export interface EvalTrace {
28
+ caseId: string;
29
+ executedInput: string;
30
+ contextBinding?: Record<string, unknown>;
31
+ route?: unknown;
32
+ measurement?: unknown;
33
+ artifactSet?: unknown;
34
+ }
35
+ export interface EvalRun {
36
+ runId: string;
37
+ results: EvalResult[];
38
+ completed: boolean;
39
+ traces?: EvalTrace[];
40
+ }
41
+ export declare function evaluate(agent: {
42
+ run(input: string): Promise<{
43
+ output: string;
44
+ }>;
45
+ }, options: {
46
+ dataset: Dataset;
47
+ evaluators: Evaluator[];
48
+ runId?: string;
49
+ includeTrace?: boolean;
50
+ }): Promise<EvalRun>;
@@ -0,0 +1,25 @@
1
+ /** Public evaluation language. Runtime evidence remains available through the runtime subpath. */
2
+ export { judge, buildEvalMessages, parseVerdict, verdictOutputSchema } from "../runtime/eval.js";
3
+ export async function evaluate(agent, options) {
4
+ const results = [];
5
+ const traces = [];
6
+ for (const testCase of options.dataset.cases) {
7
+ const output = await agent.run(testCase.input);
8
+ const scores = {};
9
+ for (const evaluator of options.evaluators)
10
+ scores[evaluator.name] = await evaluator.evaluate({ testCase, output: output.output });
11
+ results.push({ caseId: testCase.id, output: output.output, scores });
12
+ if (options.includeTrace) {
13
+ const evidence = output;
14
+ traces.push({
15
+ caseId: testCase.id,
16
+ executedInput: testCase.input,
17
+ ...(testCase.metadata ? { contextBinding: testCase.metadata } : {}),
18
+ ...(evidence.route !== undefined ? { route: evidence.route } : {}),
19
+ ...(evidence.usage !== undefined ? { measurement: evidence.usage } : {}),
20
+ ...(evidence.artifacts !== undefined ? { artifactSet: evidence.artifacts } : {}),
21
+ });
22
+ }
23
+ }
24
+ return { runId: options.runId ?? crypto.randomUUID(), results, completed: true, ...(options.includeTrace ? { traces } : {}) };
25
+ }
@@ -1,6 +1,9 @@
1
- /** Public guardrail declaration. Execution/lowering belongs to a later governance card. */
1
+ import type { GovernancePolicy } from "./governance.js";
2
+ /** Public guardrail declaration. A policy-bearing guardrail lowers into host governance. */
2
3
  export interface Guardrail {
3
4
  name: string;
4
5
  description?: string;
5
6
  metadata?: Record<string, unknown>;
7
+ /** Optional executable governance policy. A descriptive guardrail without this field is inert. */
8
+ policy?: GovernancePolicy;
6
9
  }
@@ -3,6 +3,8 @@ import type { JsonSchema } from "./runtime/output-schema.js";
3
3
  export type AgentRef = string | {
4
4
  name: string;
5
5
  };
6
+ /** Canonical lowering primitive shared by handoff authorization and workflow nodes. */
7
+ export declare function agentRefName(ref: AgentRef): string;
6
8
  export interface Handoff {
7
9
  agent: AgentRef;
8
10
  description?: string;
@@ -1 +1,7 @@
1
- export {};
1
+ /** Canonical lowering primitive shared by handoff authorization and workflow nodes. */
2
+ export function agentRefName(ref) {
3
+ const name = typeof ref === "string" ? ref : ref.name;
4
+ if (!name)
5
+ throw new Error("agent reference requires a non-empty name");
6
+ return name;
7
+ }