torus-ai 0.3.0 → 0.4.0
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.
- package/README.md +30 -0
- package/dist/index.d.ts +35 -1
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -1
- package/package.json +44 -8
- package/src/index.ts +8 -0
- package/src/mcp-client.ts +114 -0
package/README.md
CHANGED
|
@@ -144,6 +144,36 @@ A weekly GitHub Action ([model-watch.yml](./.github/workflows/model-watch.yml))
|
|
|
144
144
|
pulls NVIDIA's live `/v1/models`, flags new free endpoints as candidates, and opens
|
|
145
145
|
a PR for human review against the policy. Run it locally with `npm run model-watch`.
|
|
146
146
|
|
|
147
|
+
## Connecting to MCP servers (Torus is an MCP host)
|
|
148
|
+
|
|
149
|
+
Torus speaks two flavors of [MCP](https://modelcontextprotocol.io):
|
|
150
|
+
|
|
151
|
+
- **In-process** — `tool()` + `createSdkMcpServer()` define tools that run in your
|
|
152
|
+
process (the toolkit, the catalog/billing servers).
|
|
153
|
+
- **External** — connect to the wider MCP ecosystem (GitHub, Postgres, Slack, …)
|
|
154
|
+
over **stdio** (a local subprocess) or **HTTP**. Their tools are discovered and
|
|
155
|
+
registered under the same `mcp__<server>__<tool>` namespace, so they work in the
|
|
156
|
+
loop, the cascade, and packs, gated by the same permission allowlist.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { query, connectMcpServers } from "torus-ai";
|
|
160
|
+
|
|
161
|
+
const { servers, close } = await connectMcpServers({
|
|
162
|
+
github: { command: "npx", args: ["-y", "@modelcontextprotocol/server-github"],
|
|
163
|
+
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! } }, // stdio
|
|
164
|
+
docs: { type: "http", url: "https://example.com/mcp" }, // remote
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
for await (const ev of query("List my 3 newest GitHub issues", {
|
|
168
|
+
mcpServers: servers,
|
|
169
|
+
permissions: { allowedTools: ["mcp__github__*"] }, // allowlist the external tools
|
|
170
|
+
})) { /* ... */ }
|
|
171
|
+
|
|
172
|
+
await close(); // tear down the subprocess / connection
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Needs the optional `@modelcontextprotocol/sdk` package (`npm i @modelcontextprotocol/sdk`).
|
|
176
|
+
|
|
147
177
|
## Specializing for a product (packs)
|
|
148
178
|
|
|
149
179
|
Don't fork the SDK per product — load a **pack**. A pack is an adapter that turns
|
package/dist/index.d.ts
CHANGED
|
@@ -488,6 +488,40 @@ declare function loadPack(dir: string, opts?: {
|
|
|
488
488
|
tools?: SdkMcpServer[];
|
|
489
489
|
}): Promise<AgentPack>;
|
|
490
490
|
|
|
491
|
+
type McpServerConfig = {
|
|
492
|
+
type?: "stdio";
|
|
493
|
+
command: string;
|
|
494
|
+
args?: string[];
|
|
495
|
+
env?: Record<string, string>;
|
|
496
|
+
} | {
|
|
497
|
+
type: "http";
|
|
498
|
+
url: string;
|
|
499
|
+
headers?: Record<string, string>;
|
|
500
|
+
};
|
|
501
|
+
interface McpConnection {
|
|
502
|
+
/** Namespaced server — its tools become mcp__<name>__<tool>. */
|
|
503
|
+
server: SdkMcpServer;
|
|
504
|
+
/** Tear down the MCP client + transport. */
|
|
505
|
+
close(): Promise<void>;
|
|
506
|
+
}
|
|
507
|
+
/** Connect to one external MCP server and expose its tools as an SdkMcpServer. */
|
|
508
|
+
declare function connectMcpServer(name: string, config: McpServerConfig): Promise<McpConnection>;
|
|
509
|
+
/**
|
|
510
|
+
* Connect to several external MCP servers at once.
|
|
511
|
+
*
|
|
512
|
+
* const { servers, close } = await connectMcpServers({
|
|
513
|
+
* github: { command: "npx", args: ["-y", "@modelcontextprotocol/server-github"], env: { GITHUB_TOKEN } },
|
|
514
|
+
* docs: { type: "http", url: "https://example.com/mcp" },
|
|
515
|
+
* });
|
|
516
|
+
* for await (const ev of query("...", { mcpServers: servers,
|
|
517
|
+
* permissions: { allowedTools: ["mcp__github__*"] } })) { ... }
|
|
518
|
+
* await close();
|
|
519
|
+
*/
|
|
520
|
+
declare function connectMcpServers(configs: Record<string, McpServerConfig>): Promise<{
|
|
521
|
+
servers: SdkMcpServer[];
|
|
522
|
+
close(): Promise<void>;
|
|
523
|
+
}>;
|
|
524
|
+
|
|
491
525
|
declare const CHEAP_MODEL = "claude-haiku-4-5";
|
|
492
526
|
declare const EXPENSIVE_MODEL = "claude-sonnet-4-6";
|
|
493
527
|
declare const GEMINI_CHEAP_MODEL = "gemini-2.5-flash-lite";
|
|
@@ -550,4 +584,4 @@ interface QueryOptions {
|
|
|
550
584
|
*/
|
|
551
585
|
declare function query(prompt: string | ContentBlock[], options?: QueryOptions): AsyncGenerator<AgentEvent>;
|
|
552
586
|
|
|
553
|
-
export { type AgentEvent, type AgentPack, type AnthropicOptions, AnthropicProvider, CHEAP_MODEL, type CanUseTool, type CascadeOptions, CascadeProvider, type CascadeStep, type CatalogItem, type Complexity, type ContentBlock, DEEPSEEK_V4_FLASH, DEEPSEEK_V4_PRO, type DefaultProviderOptions, EXPENSIVE_MODEL, GEMINI_CHEAP_MODEL, GEMINI_EXPENSIVE_MODEL, type GeminiOptions, GeminiProvider, type Invoice, type JSONSchema, KIMI_K2_6, LLAMA_VISION, type LoadedContext, type LoopOptions, type LoopResult, type MediaBlock, type Message, type MockOptions, MockProvider, type ModelProvider, type ModelRequest, type ModelResponse, NVIDIA_BASE_URL, type NvidiaOptions, NvidiaProvider, type PackGuardrails, type PackKnowledge, type PermissionConfig, type PermissionDecision, PermissionEngine, type PipelineOptions, type QueryOptions, type RegisteredTool, type Role, type RouterOptions, type RoutingStats, type SdkMcpServer, type SpecializeOptions, type SpecializedAgent, type StageContract, type StageInput, type StopReason, type TextBlock, type ToolContext, type ToolDefinition, ToolRegistry, type ToolResultBlock, type ToolResultPayload, type ToolSchema, type ToolUseBlock, builtinTools, classifyComplexity, classifyComplexityGemini, createCatalogServer, createDefaultProvider, createHandoffServer, createInvoiceServer, createLeadMemoryServer, createSdkMcpServer, createSpecializedAgent, fastHeuristic, getRoutingStats, hasMedia, judgeComplexity, judgeComplexityGemini, latestUserText, listDirTool, loadPack, loadStageContext, loadStages, matchesAllow, parseContract, query, readFileTool, runLoop, runPipeline, selectGeminiModel, selectModel, tool, writeFileTool };
|
|
587
|
+
export { type AgentEvent, type AgentPack, type AnthropicOptions, AnthropicProvider, CHEAP_MODEL, type CanUseTool, type CascadeOptions, CascadeProvider, type CascadeStep, type CatalogItem, type Complexity, type ContentBlock, DEEPSEEK_V4_FLASH, DEEPSEEK_V4_PRO, type DefaultProviderOptions, EXPENSIVE_MODEL, GEMINI_CHEAP_MODEL, GEMINI_EXPENSIVE_MODEL, type GeminiOptions, GeminiProvider, type Invoice, type JSONSchema, KIMI_K2_6, LLAMA_VISION, type LoadedContext, type LoopOptions, type LoopResult, type McpConnection, type McpServerConfig, type MediaBlock, type Message, type MockOptions, MockProvider, type ModelProvider, type ModelRequest, type ModelResponse, NVIDIA_BASE_URL, type NvidiaOptions, NvidiaProvider, type PackGuardrails, type PackKnowledge, type PermissionConfig, type PermissionDecision, PermissionEngine, type PipelineOptions, type QueryOptions, type RegisteredTool, type Role, type RouterOptions, type RoutingStats, type SdkMcpServer, type SpecializeOptions, type SpecializedAgent, type StageContract, type StageInput, type StopReason, type TextBlock, type ToolContext, type ToolDefinition, ToolRegistry, type ToolResultBlock, type ToolResultPayload, type ToolSchema, type ToolUseBlock, builtinTools, classifyComplexity, classifyComplexityGemini, connectMcpServer, connectMcpServers, createCatalogServer, createDefaultProvider, createHandoffServer, createInvoiceServer, createLeadMemoryServer, createSdkMcpServer, createSpecializedAgent, fastHeuristic, getRoutingStats, hasMedia, judgeComplexity, judgeComplexityGemini, latestUserText, listDirTool, loadPack, loadStageContext, loadStages, matchesAllow, parseContract, query, readFileTool, runLoop, runPipeline, selectGeminiModel, selectModel, tool, writeFileTool };
|
package/dist/index.js
CHANGED
|
@@ -1064,6 +1064,68 @@ async function loadPack(dir, opts = {}) {
|
|
|
1064
1064
|
};
|
|
1065
1065
|
}
|
|
1066
1066
|
|
|
1067
|
+
// src/mcp-client.ts
|
|
1068
|
+
async function connect(config) {
|
|
1069
|
+
const clientMod = await import("@modelcontextprotocol/sdk/client/index.js").catch(() => {
|
|
1070
|
+
throw new Error("MCP client needs @modelcontextprotocol/sdk: run `npm i @modelcontextprotocol/sdk`.");
|
|
1071
|
+
});
|
|
1072
|
+
const Client = clientMod.Client;
|
|
1073
|
+
let transport;
|
|
1074
|
+
if (config.type === "http") {
|
|
1075
|
+
const mod = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
1076
|
+
transport = new mod.StreamableHTTPClientTransport(
|
|
1077
|
+
new URL(config.url),
|
|
1078
|
+
config.headers ? { requestInit: { headers: config.headers } } : void 0
|
|
1079
|
+
);
|
|
1080
|
+
} else {
|
|
1081
|
+
const mod = await import("@modelcontextprotocol/sdk/client/stdio.js");
|
|
1082
|
+
transport = new mod.StdioClientTransport({
|
|
1083
|
+
command: config.command,
|
|
1084
|
+
args: config.args ?? [],
|
|
1085
|
+
env: { ...process.env, ...config.env ?? {} }
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
const client = new Client({ name: "torus", version: "0.4.0" }, { capabilities: {} });
|
|
1089
|
+
await client.connect(transport);
|
|
1090
|
+
return client;
|
|
1091
|
+
}
|
|
1092
|
+
async function connectMcpServer(name, config) {
|
|
1093
|
+
const client = await connect(config);
|
|
1094
|
+
const listed = await client.listTools();
|
|
1095
|
+
const tools = (listed.tools ?? []).map(
|
|
1096
|
+
(t) => tool(
|
|
1097
|
+
t.name,
|
|
1098
|
+
t.description ?? "",
|
|
1099
|
+
t.inputSchema ?? { type: "object", properties: {} },
|
|
1100
|
+
async (input) => {
|
|
1101
|
+
const res = await client.callTool({ name: t.name, arguments: input ?? {} });
|
|
1102
|
+
const text = (res.content ?? []).filter((c) => c?.type === "text").map((c) => c.text).join("\n") || JSON.stringify(res.content ?? res);
|
|
1103
|
+
return { content: text, isError: !!res.isError };
|
|
1104
|
+
}
|
|
1105
|
+
)
|
|
1106
|
+
);
|
|
1107
|
+
return {
|
|
1108
|
+
server: createSdkMcpServer({ name, version: "1.0.0", tools }),
|
|
1109
|
+
close: async () => {
|
|
1110
|
+
try {
|
|
1111
|
+
await client.close();
|
|
1112
|
+
} catch {
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
async function connectMcpServers(configs) {
|
|
1118
|
+
const conns = await Promise.all(
|
|
1119
|
+
Object.entries(configs).map(([name, cfg]) => connectMcpServer(name, cfg))
|
|
1120
|
+
);
|
|
1121
|
+
return {
|
|
1122
|
+
servers: conns.map((c) => c.server),
|
|
1123
|
+
close: async () => {
|
|
1124
|
+
await Promise.all(conns.map((c) => c.close()));
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1067
1129
|
// src/index.ts
|
|
1068
1130
|
async function* query(prompt, options = {}) {
|
|
1069
1131
|
const registry = new ToolRegistry();
|
|
@@ -1102,6 +1164,8 @@ export {
|
|
|
1102
1164
|
builtinTools,
|
|
1103
1165
|
classifyComplexity,
|
|
1104
1166
|
classifyComplexityGemini,
|
|
1167
|
+
connectMcpServer,
|
|
1168
|
+
connectMcpServers,
|
|
1105
1169
|
createCatalogServer,
|
|
1106
1170
|
createDefaultProvider,
|
|
1107
1171
|
createHandoffServer,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/tools.ts","../src/permissions.ts","../src/loop.ts","../src/pipeline.ts","../src/context.ts","../src/builtins.ts","../src/subagents.ts","../src/providers/mock.ts","../src/router.ts","../src/providers/anthropic.ts","../src/providers/gemini.ts","../src/providers/nvidia.ts","../src/providers/cascade.ts","../src/pack.ts","../src/packkit.ts","../src/index.ts"],"sourcesContent":["// ─────────────────────────────────────────────────────────────────────────\n// Core wire types — the plain-data interface every layer speaks (ICM principle 2:\n// \"plain text/structured data is the interface\"). No provider-specific shapes leak\n// past this file; the AnthropicProvider/MockProvider translate to and from these.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type Role = \"user\" | \"assistant\";\n\nexport interface TextBlock {\n type: \"text\";\n text: string;\n}\nexport interface ToolUseBlock {\n type: \"tool_use\";\n id: string;\n name: string; // namespaced name as offered to the model, e.g. \"mcp__research__lookup\"\n input: Record<string, unknown>;\n}\nexport interface ToolResultBlock {\n type: \"tool_result\";\n toolUseId: string;\n content: string;\n isError?: boolean;\n}\n/**\n * Multimodal input. Provide either a remote `url` or base64 `data` (+ `mimeType`).\n * Image is broadly supported; video is experimental and model-dependent (routed\n * to a video-capable model like Kimi K2.6).\n */\nexport interface MediaBlock {\n type: \"image\" | \"video\";\n url?: string; // remote URL or a data: URL\n data?: string; // raw base64 (paired with mimeType)\n mimeType?: string; // e.g. \"image/png\", \"image/jpeg\", \"video/mp4\"\n}\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | MediaBlock;\n\n/** True if a message list carries any image/video content (drives vision routing). */\nexport function hasMedia(messages: Message[]): boolean {\n return messages.some((m) => m.content.some((b) => b.type === \"image\" || b.type === \"video\"));\n}\n\nexport interface Message {\n role: Role;\n content: ContentBlock[];\n}\n\nexport type StopReason = \"end_turn\" | \"tool_use\" | \"max_turns\";\n\nexport interface ModelResponse {\n content: ContentBlock[];\n stopReason: StopReason;\n}\n\nexport type JSONSchema = Record<string, unknown>;\n\nexport interface ToolSchema {\n name: string;\n description: string;\n inputSchema: JSONSchema;\n}\n\nexport interface ModelRequest {\n system: string;\n messages: Message[];\n tools: ToolSchema[];\n}\n\n/** The one capability the SDK needs from any model backend. Swap freely. */\nexport interface ModelProvider {\n readonly name: string;\n generate(req: ModelRequest): Promise<ModelResponse>;\n}\n\n// ── Tools ────────────────────────────────────────────────────────────────\n\nexport interface ToolResultPayload {\n content: string;\n isError?: boolean;\n}\n\nexport interface ToolContext {\n workspaceDir: string;\n stageDir?: string;\n signal?: AbortSignal;\n}\n\nexport interface ToolDefinition {\n name: string; // bare name, e.g. \"lookup\"; namespacing is applied at registration\n description: string;\n inputSchema: JSONSchema;\n handler: (\n input: any,\n ctx: ToolContext,\n ) => Promise<ToolResultPayload> | ToolResultPayload;\n}\n\n/** An in-process MCP server: tools that run in this same process, no subprocess. */\nexport interface SdkMcpServer {\n kind: \"sdk-mcp\";\n name: string; // becomes the mcp__<name>__ namespace prefix\n version: string;\n tools: ToolDefinition[];\n}\n\n// ── Permissions ────────────────────────────────────────────────────────────\n\nexport type PermissionDecision =\n | { behavior: \"allow\"; updatedInput?: Record<string, unknown> }\n | { behavior: \"deny\"; message: string };\n\nexport type CanUseTool = (\n toolName: string,\n input: Record<string, unknown>,\n) => Promise<PermissionDecision> | PermissionDecision;\n\n// ── Streaming events ───────────────────────────────────────────────────────\n\nexport type AgentEvent =\n | { type: \"assistant_text\"; text: string; stage?: string }\n | { type: \"tool_use\"; name: string; input: Record<string, unknown>; stage?: string }\n | { type: \"tool_result\"; name: string; content: string; isError: boolean; stage?: string }\n | { type: \"permission_denied\"; name: string; message: string; stage?: string }\n | { type: \"stage_start\"; stage: string }\n | { type: \"stage_output\"; stage: string; artifact: string; path: string }\n | { type: \"context_loaded\"; stage?: string; tokensEstimated: number; files: string[] }\n | { type: \"result\"; finalText: string; turns: number; stage?: string };\n","import type {\n JSONSchema,\n SdkMcpServer,\n ToolContext,\n ToolDefinition,\n ToolResultPayload,\n ToolSchema,\n} from \"./types.ts\";\n\n/**\n * Define a custom tool. Mirrors `tool()` from the Claude Agent SDK.\n * tool(\"get_temp\", \"Get temperature\", { type:\"object\", ... }, async (input, ctx) => ...)\n */\nexport function tool(\n name: string,\n description: string,\n inputSchema: JSONSchema,\n handler: (input: any, ctx: ToolContext) => Promise<ToolResultPayload> | ToolResultPayload,\n): ToolDefinition {\n return { name, description, inputSchema, handler };\n}\n\n/**\n * Bundle tools into an in-process MCP server. Mirrors `createSdkMcpServer()`.\n * Tools become namespaced `mcp__<name>__<tool>` when registered.\n */\nexport function createSdkMcpServer(opts: {\n name: string;\n version?: string;\n tools: ToolDefinition[];\n}): SdkMcpServer {\n return { kind: \"sdk-mcp\", name: opts.name, version: opts.version ?? \"1.0.0\", tools: opts.tools };\n}\n\nexport interface RegisteredTool {\n fullName: string; // \"mcp__research__lookup\" or built-in \"read_file\"\n def: ToolDefinition;\n}\n\n/** Holds the model-facing tool catalog and executes calls by namespaced name. */\nexport class ToolRegistry {\n private map = new Map<string, ToolDefinition>();\n\n /** Built-ins register under their bare name (no namespace). */\n addBuiltins(defs: ToolDefinition[]): this {\n for (const d of defs) this.map.set(d.name, d);\n return this;\n }\n\n /** SDK MCP server tools register as mcp__<server>__<tool>. */\n addServer(server: SdkMcpServer): this {\n for (const t of server.tools) this.map.set(`mcp__${server.name}__${t.name}`, t);\n return this;\n }\n\n has(fullName: string): boolean {\n return this.map.has(fullName);\n }\n\n list(): RegisteredTool[] {\n return [...this.map.entries()].map(([fullName, def]) => ({ fullName, def }));\n }\n\n /** Tool schemas to hand the model, optionally filtered to a stage's allowlist. */\n schemas(filter?: (fullName: string) => boolean): ToolSchema[] {\n return this.list()\n .filter((t) => !filter || filter(t.fullName))\n .map((t) => ({ name: t.fullName, description: t.def.description, inputSchema: t.def.inputSchema }));\n }\n\n async execute(\n fullName: string,\n input: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResultPayload> {\n const def = this.map.get(fullName);\n if (!def) return { content: `Unknown tool: ${fullName}`, isError: true };\n try {\n return await def.handler(input, ctx);\n } catch (err) {\n return { content: `Tool ${fullName} threw: ${(err as Error).message}`, isError: true };\n }\n }\n}\n","import type { CanUseTool, PermissionDecision } from \"./types.ts\";\n\n/** Match a tool name against patterns supporting a trailing \"*\" wildcard. */\nexport function matchesAllow(name: string, patterns: string[]): boolean {\n return patterns.some((p) => {\n if (p === \"*\") return true;\n if (p.endsWith(\"*\")) return name.startsWith(p.slice(0, -1));\n return p === name;\n });\n}\n\nexport interface PermissionConfig {\n /** Allowlist (wildcards ok). If omitted, all tools allowed unless canUseTool vetoes. */\n allowedTools?: string[];\n /** Explicit denials, evaluated first. */\n disallowedTools?: string[];\n /** Final custom gate — can allow non-allowlisted tools, veto allowlisted ones, or rewrite input. */\n canUseTool?: CanUseTool;\n}\n\n/**\n * Evaluation order (mirrors the Agent SDK):\n * 1. disallowedTools → deny\n * 2. allowedTools → allow (if no canUseTool)\n * 3. canUseTool → final say\n * 4. default → allow when no allowlist, deny when allowlist set and unmatched\n */\nexport class PermissionEngine {\n private cfg: PermissionConfig;\n constructor(cfg: PermissionConfig = {}) {\n this.cfg = cfg;\n }\n\n async check(name: string, input: Record<string, unknown>): Promise<PermissionDecision> {\n const { allowedTools, disallowedTools, canUseTool } = this.cfg;\n\n if (disallowedTools && matchesAllow(name, disallowedTools)) {\n return { behavior: \"deny\", message: `${name} is in disallowedTools.` };\n }\n\n const onAllowlist = allowedTools ? matchesAllow(name, allowedTools) : true;\n\n if (canUseTool) return canUseTool(name, input); // callback has the final word\n\n if (onAllowlist) return { behavior: \"allow\" };\n return {\n behavior: \"deny\",\n message: `${name} is not in allowedTools and no canUseTool callback is set.`,\n };\n }\n}\n","import type { PermissionEngine } from \"./permissions.ts\";\nimport type { ToolRegistry } from \"./tools.ts\";\nimport type {\n AgentEvent,\n Message,\n ModelProvider,\n ToolContext,\n ToolResultBlock,\n} from \"./types.ts\";\n\n// The core agentic loop: gather context → call model → if it wants tools, run them\n// under the permission gate and feed results back → repeat until the model stops\n// asking for tools (or we hit maxTurns). This is the same contract the Claude Agent\n// SDK runs; everything else in this package just shapes what enters and leaves it.\n\nexport interface LoopOptions {\n provider: ModelProvider;\n registry: ToolRegistry;\n permissions: PermissionEngine;\n system: string;\n messages: Message[]; // seeded with the user turn\n toolContext: ToolContext;\n toolFilter?: (fullName: string) => boolean; // which tools to offer this run\n maxTurns?: number;\n stage?: string;\n}\n\nexport interface LoopResult {\n finalText: string;\n turns: number;\n messages: Message[];\n}\n\nlet counter = 0;\nconst genId = () => `tu_${++counter}`;\n\nexport async function* runLoop(opts: LoopOptions): AsyncGenerator<AgentEvent, LoopResult> {\n const { provider, registry, permissions, system, messages, toolContext } = opts;\n const maxTurns = opts.maxTurns ?? 8;\n const tools = registry.schemas(opts.toolFilter);\n\n let turns = 0;\n let finalText = \"\";\n\n while (turns < maxTurns) {\n turns++;\n const res = await provider.generate({ system, messages, tools });\n\n // Ensure every tool_use has an id (mock providers may omit it).\n for (const b of res.content) if (b.type === \"tool_use\" && !b.id) b.id = genId();\n messages.push({ role: \"assistant\", content: res.content });\n\n for (const b of res.content) {\n if (b.type === \"text\" && b.text.trim()) {\n yield { type: \"assistant_text\", text: b.text, stage: opts.stage };\n }\n }\n\n if (res.stopReason !== \"tool_use\") {\n finalText = res.content\n .filter((b): b is Extract<typeof b, { type: \"text\" }> => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\\n\")\n .trim();\n return { finalText, turns, messages };\n }\n\n const toolResults: ToolResultBlock[] = [];\n for (const b of res.content) {\n if (b.type !== \"tool_use\") continue;\n yield { type: \"tool_use\", name: b.name, input: b.input, stage: opts.stage };\n\n const decision = await permissions.check(b.name, b.input);\n if (decision.behavior === \"deny\") {\n yield { type: \"permission_denied\", name: b.name, message: decision.message, stage: opts.stage };\n toolResults.push({\n type: \"tool_result\",\n toolUseId: b.id,\n content: `Permission denied: ${decision.message}`,\n isError: true,\n });\n continue;\n }\n\n const input = decision.updatedInput ?? b.input;\n const result = await registry.execute(b.name, input, toolContext);\n yield {\n type: \"tool_result\",\n name: b.name,\n content: result.content,\n isError: !!result.isError,\n stage: opts.stage,\n };\n toolResults.push({\n type: \"tool_result\",\n toolUseId: b.id,\n content: result.content,\n isError: result.isError,\n });\n }\n\n messages.push({ role: \"user\", content: toolResults });\n }\n\n return { finalText: finalText || \"[max turns reached]\", turns, messages };\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { loadStageContext } from \"./context.ts\";\nimport { runLoop } from \"./loop.ts\";\nimport { PermissionEngine, type PermissionConfig } from \"./permissions.ts\";\nimport { builtinTools } from \"./builtins.ts\";\nimport { loadStages, type StageContract } from \"./subagents.ts\";\nimport { ToolRegistry } from \"./tools.ts\";\nimport type { AgentEvent, Message, ModelProvider, SdkMcpServer } from \"./types.ts\";\n\n// The ICM pipeline runner: walk numbered stages in order, give each stage only the\n// context its contract names, run the agent loop, write the named artifact to the\n// stage's output/ (the handoff point), then pause at a human review gate.\n\nexport interface PipelineOptions {\n workspaceDir: string;\n provider: ModelProvider;\n mcpServers?: SdkMcpServer[];\n /** Global permission overlay. A stage's own \"## Tools\" list is the primary allowlist. */\n permissions?: Pick<PermissionConfig, \"canUseTool\" | \"disallowedTools\">;\n /** Called after each stage writes output. Return false to halt the pipeline. */\n reviewGate?: (\n stage: StageContract,\n outputs: { artifact: string; path: string; text: string }[],\n ) => Promise<boolean> | boolean;\n maxTurnsPerStage?: number;\n contextBudgetTokens?: number; // ICM target ceiling, default 8000\n}\n\nexport async function* runPipeline(opts: PipelineOptions): AsyncGenerator<AgentEvent, void> {\n const registry = new ToolRegistry().addBuiltins(builtinTools);\n for (const s of opts.mcpServers ?? []) registry.addServer(s);\n\n const budget = opts.contextBudgetTokens ?? 8000;\n const stages = await loadStages(opts.workspaceDir);\n\n for (const stage of stages) {\n yield { type: \"stage_start\", stage: stage.name };\n\n // ── Layered context (ICM Layers 0–4, scoped to the contract) ──\n const ctx = await loadStageContext(opts.workspaceDir, stage);\n yield { type: \"context_loaded\", stage: stage.name, tokensEstimated: ctx.tokensEstimated, files: ctx.files };\n if (ctx.tokensEstimated > budget) {\n yield {\n type: \"assistant_text\",\n stage: stage.name,\n text: `⚠ context ~${ctx.tokensEstimated} tok exceeds budget ${budget} — trim this stage's Inputs (ICM principle 3).`,\n };\n }\n\n // ── The contract's \"## Tools\" list is the source of truth for availability ──\n const perm = new PermissionEngine({\n allowedTools: stage.tools, // [] ⇒ a pure prose transform, no tools offered\n disallowedTools: opts.permissions?.disallowedTools,\n canUseTool: opts.permissions?.canUseTool,\n });\n const toolFilter = (n: string) =>\n stage.tools.some((p) => (p.endsWith(\"*\") ? n.startsWith(p.slice(0, -1)) : p === n));\n\n const userPrompt =\n `Execute this stage.\\n\\n## Process\\n${stage.process}\\n\\n` +\n `Produce: ${stage.outputs.join(\", \") || \"a single markdown artifact\"}.`;\n const messages: Message[] = [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }] }];\n\n const result = yield* runLoop({\n provider: opts.provider,\n registry,\n permissions: perm,\n system: ctx.system,\n messages,\n toolFilter,\n toolContext: { workspaceDir: opts.workspaceDir, stageDir: stage.stageDir },\n maxTurns: opts.maxTurnsPerStage,\n stage: stage.name,\n });\n\n // ── Persist the deliverable to output/ per the Outputs contract (the handoff) ──\n const outDir = join(stage.stageDir, \"output\");\n await mkdir(outDir, { recursive: true });\n const primary = stage.outputs[0] ?? \"output.md\";\n const path = join(outDir, primary);\n await writeFile(path, result.finalText + \"\\n\", \"utf8\");\n yield { type: \"stage_output\", stage: stage.name, artifact: primary, path };\n yield { type: \"result\", stage: stage.name, finalText: result.finalText, turns: result.turns };\n\n // ── Review gate: every stage boundary is an edit surface (ICM principle 4) ──\n const proceed = opts.reviewGate\n ? await opts.reviewGate(stage, [{ artifact: primary, path, text: result.finalText }])\n : true;\n if (!proceed) return;\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { StageContract } from \"./subagents.ts\";\n\n// ICM principle 3 — \"layered context loading\": assemble the system prompt from\n// exactly the layers a stage names, nothing more. The control point is the\n// contract's Inputs list; this loader never loads \"everything just in case\".\n\nexport interface LoadedContext {\n system: string;\n files: string[];\n tokensEstimated: number;\n}\n\nconst estimateTokens = (s: string) => Math.ceil(s.length / 4); // ~4 chars/token heuristic\n\nasync function readIfExists(path: string): Promise<string | null> {\n if (!existsSync(path)) return null;\n return readFile(path, \"utf8\");\n}\n\nfunction relativeName(root: string, path: string): string {\n return path.replace(root, \"\").replace(/^[\\\\/]/, \"\").replace(/\\\\/g, \"/\");\n}\n\n/**\n * Build a stage's system prompt from the ICM layer hierarchy:\n * Layer 0 AGENT.md (identity + map)\n * Layer 1 CONTEXT.md (routing)\n * Layer 2 stage CONTEXT.md (this stage's contract)\n * Layer 3 scoped references (constraints — only files the contract names)\n * Layer 4 scoped working (prior stage output — only files the contract names)\n */\nexport async function loadStageContext(\n workspaceDir: string,\n contract: StageContract,\n): Promise<LoadedContext> {\n const parts: string[] = [];\n const files: string[] = [];\n\n const push = async (label: string, path: string) => {\n const text = await readIfExists(path);\n if (text == null) return;\n const src = relativeName(workspaceDir, path);\n parts.push(`<context layer=\"${label}\" src=\"${src}\">\\n${text.trim()}\\n</context>`);\n files.push(src);\n };\n\n await push(\"0 identity\", join(workspaceDir, \"AGENT.md\"));\n await push(\"1 routing\", join(workspaceDir, \"CONTEXT.md\"));\n await push(\"2 contract\", contract.contractPath);\n\n for (const input of contract.inputs) {\n const abs = join(contract.stageDir, input.path);\n await push(input.layer === 3 ? \"3 reference\" : \"4 working\", abs);\n }\n\n const system = parts.join(\"\\n\\n\");\n return { system, files, tokensEstimated: estimateTokens(system) };\n}\n","import { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport { tool } from \"./tools.ts\";\nimport type { ToolDefinition } from \"./types.ts\";\n\n// Confine all built-in file access to the workspace directory (defence in depth;\n// the permission layer is the primary gate).\nfunction safeResolve(workspaceDir: string, p: string): string {\n const root = resolve(workspaceDir);\n const full = resolve(root, p);\n const rel = relative(root, full);\n if (rel.startsWith(\"..\") || resolve(root, rel) !== full) {\n throw new Error(`Path escapes workspace: ${p}`);\n }\n return full;\n}\n\nexport const readFileTool: ToolDefinition = tool(\n \"read_file\",\n \"Read a UTF-8 text file relative to the workspace root.\",\n { type: \"object\", properties: { path: { type: \"string\" } }, required: [\"path\"] },\n async (input: { path: string }, ctx) => {\n const full = safeResolve(ctx.workspaceDir, input.path);\n return { content: await readFile(full, \"utf8\") };\n },\n);\n\nexport const writeFileTool: ToolDefinition = tool(\n \"write_file\",\n \"Write a UTF-8 text file relative to the workspace root (creates parent dirs).\",\n {\n type: \"object\",\n properties: { path: { type: \"string\" }, content: { type: \"string\" } },\n required: [\"path\", \"content\"],\n },\n async (input: { path: string; content: string }, ctx) => {\n const full = safeResolve(ctx.workspaceDir, input.path);\n await mkdir(dirname(full), { recursive: true });\n await writeFile(full, input.content, \"utf8\");\n return { content: `Wrote ${input.content.length} chars to ${input.path}` };\n },\n);\n\nexport const listDirTool: ToolDefinition = tool(\n \"list_dir\",\n \"List entries of a directory relative to the workspace root.\",\n { type: \"object\", properties: { path: { type: \"string\" } }, required: [\"path\"] },\n async (input: { path: string }, ctx) => {\n const full = safeResolve(ctx.workspaceDir, input.path);\n const entries = await readdir(full, { withFileTypes: true });\n return { content: entries.map((e) => (e.isDirectory() ? e.name + \"/\" : e.name)).join(\"\\n\") };\n },\n);\n\nexport const builtinTools: ToolDefinition[] = [readFileTool, writeFileTool, listDirTool];\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n// A \"subagent\" in this SDK is a stage: a markdown contract (Layer 2 CONTEXT.md)\n// that declares its Inputs / Process / Outputs / Tools. Parsing the contract turns\n// folder structure into agent architecture — the whole ICM premise.\n\nexport interface StageInput {\n layer: 3 | 4; // 3 = reference (constraints), 4 = working (input to process)\n path: string; // relative to the stage dir, exactly as the contract names it\n note?: string;\n}\n\nexport interface StageContract {\n name: string; // \"01_research\"\n order: number;\n stageDir: string;\n contractPath: string;\n inputs: StageInput[];\n process: string;\n outputs: string[]; // artifact filenames, written to the stage's output/\n tools: string[]; // allowlist patterns from the optional \"## Tools\" section\n}\n\n/** Pull the body of a \"## <Name>\" markdown section (up to the next \"## \" or EOF). */\nfunction section(body: string, name: string): string {\n const re = new RegExp(`(?:^|\\\\n)##\\\\s+${name}\\\\s*\\\\n([\\\\s\\\\S]*?)(?=\\\\n##\\\\s|$)`, \"i\");\n const m = body.match(re);\n return m ? m[1].trim() : \"\";\n}\n\nexport function parseContract(\n name: string,\n stageDir: string,\n contractPath: string,\n body: string,\n): StageContract {\n const order = parseInt(name.slice(0, 2), 10) || 0;\n\n // Inputs: \"- Layer 3 (reference): ../../_config/voice.md # optional note\"\n const inputs: StageInput[] = [];\n for (const line of section(body, \"Inputs\").split(\"\\n\")) {\n const m = line.match(/Layer\\s+([34])\\b.*?:\\s*([^\\s#]+)\\s*(?:#\\s*(.*))?$/i);\n if (m) inputs.push({ layer: Number(m[1]) as 3 | 4, path: m[2], note: m[3]?.trim() });\n }\n\n // Outputs: \"- research-output.md -> output/\"\n const outputs: string[] = [];\n for (const line of section(body, \"Outputs\").split(\"\\n\")) {\n const m = line.match(/-\\s*([A-Za-z0-9._-]+\\.(?:md|json|txt))/);\n if (m) outputs.push(m[1]);\n }\n\n // Tools (optional): the stage declares exactly which tools it may use.\n const toolsRaw = section(body, \"Tools\");\n const tools = toolsRaw\n ? toolsRaw\n .split(/[\\n,]/)\n .map((s) => s.replace(/^[-*]\\s*/, \"\").trim())\n .filter(Boolean)\n : [];\n\n return {\n name,\n order,\n stageDir,\n contractPath,\n inputs,\n process: section(body, \"Process\"),\n outputs,\n tools,\n };\n}\n\n/** Discover and parse every numbered stage folder, in execution order. */\nexport async function loadStages(workspaceDir: string): Promise<StageContract[]> {\n const stagesRoot = join(workspaceDir, \"stages\");\n const entries = await readdir(stagesRoot, { withFileTypes: true });\n const dirs = entries\n .filter((e) => e.isDirectory() && /^\\d{2}_/.test(e.name))\n .map((e) => e.name)\n .sort();\n\n const contracts: StageContract[] = [];\n for (const name of dirs) {\n const stageDir = join(stagesRoot, name);\n const contractPath = join(stageDir, \"CONTEXT.md\");\n const body = await readFile(contractPath, \"utf8\");\n contracts.push(parseContract(name, stageDir, contractPath, body));\n }\n return contracts;\n}\n","import type {\n ModelProvider,\n ModelRequest,\n ModelResponse,\n ToolSchema,\n} from \"../types.ts\";\n\nexport interface MockOptions {\n /** Label stamped into outputs so mock-generated content is unmistakable. */\n label?: string;\n}\n\n/**\n * A deterministic, offline provider that exercises the full agent loop with no API\n * key. Strategy: if tools are offered and none have been used yet, call the first\n * tool once; otherwise synthesize a final answer from the system context + any tool\n * results. It is intentionally dumb — its job is to prove the harness wiring, not to\n * write good prose. Swap in AnthropicProvider for real output.\n */\nexport class MockProvider implements ModelProvider {\n readonly name = \"mock\";\n private opts: MockOptions;\n constructor(opts: MockOptions = {}) {\n this.opts = opts;\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n const alreadyUsedTool = req.messages.some((m) =>\n m.content.some((b) => b.type === \"tool_use\"),\n );\n if (req.tools.length > 0 && !alreadyUsedTool) {\n const t = req.tools[0];\n return {\n stopReason: \"tool_use\",\n content: [{ type: \"tool_use\", id: \"\", name: t.name, input: this.sampleInput(t) }],\n };\n }\n return { stopReason: \"end_turn\", content: [{ type: \"text\", text: this.synthesize(req) }] };\n }\n\n private sampleInput(t: ToolSchema): Record<string, unknown> {\n const props = (t.inputSchema.properties ?? {}) as Record<string, { type?: string }>;\n const topic = \"the requested topic\";\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(props)) {\n out[k] =\n v.type === \"number\"\n ? 3\n : v.type === \"boolean\"\n ? true\n : k === \"path\"\n ? \"shared/notes.md\"\n : topic;\n }\n return out;\n }\n\n private synthesize(req: ModelRequest): string {\n const toolData = req.messages\n .flatMap((m) => m.content)\n .filter((b) => b.type === \"tool_result\")\n .map((b) => (b as { content: string }).content)\n .join(\"\\n\");\n\n const contract = extractLayer(req.system, \"2 contract\");\n const label = this.opts.label ? ` ${this.opts.label}` : \"\";\n\n const lines = [\n `<!-- mock model output${label} -->`,\n \"\",\n \"## Result\",\n \"\",\n \"Produced by the Torus MockProvider — proof that layered context →\",\n \"agent loop → output handoff works end to end. Replace with AnthropicProvider\",\n \"for real generation.\",\n ];\n if (toolData) {\n lines.push(\"\", \"### Tool-sourced material\", \"\", \"```\", toolData.slice(0, 600), \"```\");\n }\n if (contract) {\n lines.push(\"\", \"### Stage focus (read from the Layer 2 contract)\", \"\", firstLines(contract, 6));\n }\n return lines.join(\"\\n\");\n }\n}\n\nfunction extractLayer(system: string, layer: string): string {\n const m = system.match(new RegExp(`<context layer=\"${layer}\"[^>]*>([\\\\s\\\\S]*?)</context>`));\n return m ? m[1].trim() : \"\";\n}\nfunction firstLines(s: string, n: number): string {\n return s.split(\"\\n\").slice(0, n).join(\"\\n\");\n}\n","// ─────────────────────────────────────────────────────────────────────────\n// Intelligent LLM router — picks CHEAP vs EXPENSIVE per query to cut API cost.\n//\n// Hybrid strategy (provider-agnostic):\n// 1. Fast heuristics (no API call) for the obvious cases.\n// 2. Otherwise a structured \"judge\" call to the CHEAP model that classifies\n// the query as SIMPLE | COMPLEX.\n// SIMPLE → cheap model, COMPLEX → expensive model.\n//\n// The same mechanism is provided for two provider families:\n// - Anthropic: selectModel() (Claude Haiku judge → Haiku / Sonnet)\n// - Gemini: selectGeminiModel() (Gemini Flash-Lite judge → Flash-Lite / Pro)\n//\n// Safety: the select* functions never throw — on any failure they default to\n// the EXPENSIVE model so the user experience never breaks.\n// ─────────────────────────────────────────────────────────────────────────\n\nimport type { Message } from \"./types.ts\";\n\n// ── Target models ──────────────────────────────────────────────────────────\n// Change these in one place per provider.\nexport const CHEAP_MODEL = \"claude-haiku-4-5\"; // $1 / $5 per MTok\nexport const EXPENSIVE_MODEL = \"claude-sonnet-4-6\"; // current default — $3 / $15 per MTok\n\n// Gemini defaults to the stable 2.5 family. Swap to newer IDs (e.g.\n// \"gemini-3.1-flash-lite\" / \"gemini-3.1-pro-preview\") if your key has access.\nexport const GEMINI_CHEAP_MODEL = \"gemini-2.5-flash-lite\";\nexport const GEMINI_EXPENSIVE_MODEL = \"gemini-2.5-pro\";\n\nexport type Complexity = \"SIMPLE\" | \"COMPLEX\";\n\nexport interface RouterOptions {\n /** Reuse an existing provider SDK client (avoids a second client init). */\n client?: any;\n /** API key for a lazily-created client (defaults to the provider's env var). */\n apiKey?: string;\n /** Model used as the complexity judge. Defaults to the provider's cheap model. */\n judgeModel?: string;\n}\n\n// ── 1. Fast heuristics (no API call, provider-agnostic) ─────────────────────\n\nconst SIMPLE_KEYWORDS = [\n \"hello\", \"hi \", \"hey\", \"thanks\", \"thank you\", \"yes\", \"no\",\n \"format\", \"json\", \"yaml\", \"uppercase\", \"lowercase\", \"capitalize\",\n \"translate\", \"spell\", \"reverse\", \"echo\", \"greeting\",\n];\n\nconst estimateTokens = (s: string) => Math.ceil(s.length / 4); // ~4 chars/token\n\n/**\n * Cheap, deterministic pre-classification. Returns a verdict only when it's\n * confident; otherwise null (defer to the judge).\n */\nexport function fastHeuristic(prompt: string): Complexity | null {\n const tokens = estimateTokens(prompt);\n const lower = prompt.toLowerCase();\n\n // Short prompt that mentions a trivial operation → SIMPLE, route immediately.\n if (tokens <= 30 && SIMPLE_KEYWORDS.some((k) => lower.includes(k))) return \"SIMPLE\";\n\n // Very long prompts are almost always real work → skip the judge call.\n if (tokens >= 400) return \"COMPLEX\";\n\n return null;\n}\n\n// ── 2. LLM judges (structured output on each provider's cheap model) ─────────\n\nconst JUDGE_SYSTEM =\n \"You are a routing classifier. Decide whether a user query needs a powerful \" +\n \"model or can be handled by a small, fast one. Classify as SIMPLE (greetings, \" +\n \"formatting, short factual lookups, simple rewrites, single-step tasks) or \" +\n \"COMPLEX (multi-step reasoning, coding, analysis, planning, nuanced judgment). \" +\n 'Respond ONLY with the required JSON: {\"complexity\": \"SIMPLE\" | \"COMPLEX\"}.';\n\nconst COMPLEXITY_SCHEMA = {\n type: \"object\",\n properties: { complexity: { type: \"string\", enum: [\"SIMPLE\", \"COMPLEX\"] } },\n required: [\"complexity\"],\n additionalProperties: false,\n};\n\n/** Robustly extract SIMPLE/COMPLEX from a judge response. Throws if neither. */\nfunction parseComplexity(text: string): Complexity {\n try {\n const parsed = JSON.parse(text) as { complexity?: string };\n if (parsed.complexity === \"SIMPLE\" || parsed.complexity === \"COMPLEX\") return parsed.complexity;\n } catch {\n // fall through to text scan\n }\n const m = text.toUpperCase().match(/\\b(SIMPLE|COMPLEX)\\b/);\n if (m) return m[1] as Complexity;\n throw new Error(`judge returned unparseable complexity: ${text.slice(0, 80)}`);\n}\n\n// -- Anthropic judge --\nlet sharedAnthropic: any;\nasync function getAnthropic(opts: RouterOptions): Promise<any> {\n if (opts.client) return opts.client;\n if (sharedAnthropic) return sharedAnthropic;\n const mod = await import(\"@anthropic-ai/sdk\").catch(() => {\n throw new Error(\"Anthropic judge needs @anthropic-ai/sdk (npm i @anthropic-ai/sdk).\");\n });\n const Anthropic = (mod as any).default ?? (mod as any).Anthropic;\n sharedAnthropic = new Anthropic({ apiKey: opts.apiKey ?? process.env.ANTHROPIC_API_KEY });\n return sharedAnthropic;\n}\n\n/** Grade complexity with Claude (structured output). May throw. */\nexport async function judgeComplexity(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n const client = await getAnthropic(opts);\n const res = await client.messages.create({\n model: opts.judgeModel ?? CHEAP_MODEL,\n max_tokens: 64,\n system: JUDGE_SYSTEM,\n output_config: { format: { type: \"json_schema\", schema: COMPLEXITY_SCHEMA } },\n messages: [{ role: \"user\", content: prompt }],\n });\n const text: string = res.content.find((b: any) => b.type === \"text\")?.text ?? \"\";\n return parseComplexity(text);\n}\n\n// -- Gemini judge --\nlet sharedGemini: any;\nasync function getGemini(opts: RouterOptions): Promise<any> {\n if (opts.client) return opts.client;\n if (sharedGemini) return sharedGemini;\n const mod = await import(\"@google/genai\").catch(() => {\n throw new Error(\"Gemini judge needs @google/genai (npm i @google/genai).\");\n });\n const GoogleGenAI = (mod as any).GoogleGenAI;\n sharedGemini = new GoogleGenAI({\n apiKey: opts.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY,\n });\n return sharedGemini;\n}\n\n/** Grade complexity with Gemini (JSON structured output). May throw. */\nexport async function judgeComplexityGemini(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n const client = await getGemini(opts);\n const res = await client.models.generateContent({\n model: opts.judgeModel ?? GEMINI_CHEAP_MODEL,\n contents: prompt,\n config: {\n systemInstruction: JUDGE_SYSTEM,\n responseMimeType: \"application/json\",\n responseSchema: {\n type: \"object\",\n properties: { complexity: { type: \"string\", enum: [\"SIMPLE\", \"COMPLEX\"] } },\n required: [\"complexity\"],\n },\n },\n });\n return parseComplexity(res.text ?? \"\");\n}\n\n// ── 3. Classification + routing ─────────────────────────────────────────────\n\ntype Judge = (prompt: string, opts: RouterOptions) => Promise<Complexity>;\n\nasync function classifyWith(prompt: string, judge: Judge, opts: RouterOptions): Promise<Complexity> {\n return fastHeuristic(prompt) ?? judge(prompt, opts);\n}\n\n/** Heuristics first, Claude judge second. May throw. */\nexport function classifyComplexity(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n return classifyWith(prompt, judgeComplexity, opts);\n}\n\n/** Heuristics first, Gemini judge second. May throw. */\nexport function classifyComplexityGemini(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n return classifyWith(prompt, judgeComplexityGemini, opts);\n}\n\ninterface RouteConfig {\n cheapModel: string;\n expensiveModel: string;\n judge: Judge;\n}\n\nasync function routeWith(prompt: string, cfg: RouteConfig, opts: RouterOptions): Promise<string> {\n let model = cfg.expensiveModel;\n try {\n const complexity = await classifyWith(prompt, cfg.judge, opts);\n model = complexity === \"SIMPLE\" ? cfg.cheapModel : cfg.expensiveModel;\n } catch (err) {\n console.warn(\n `[router] classification failed — defaulting to expensive model. Reason: ${(err as Error).message}`,\n );\n model = cfg.expensiveModel;\n }\n record(model, model === cfg.cheapModel);\n return model;\n}\n\n/** Pick a Claude model for a prompt. Never throws (falls back to expensive). */\nexport function selectModel(prompt: string, opts: RouterOptions = {}): Promise<string> {\n return routeWith(prompt, { cheapModel: CHEAP_MODEL, expensiveModel: EXPENSIVE_MODEL, judge: judgeComplexity }, opts);\n}\n\n/** Pick a Gemini model for a prompt. Never throws (falls back to expensive). */\nexport function selectGeminiModel(prompt: string, opts: RouterOptions = {}): Promise<string> {\n return routeWith(\n prompt,\n { cheapModel: GEMINI_CHEAP_MODEL, expensiveModel: GEMINI_EXPENSIVE_MODEL, judge: judgeComplexityGemini },\n opts,\n );\n}\n\n// ── 4. Observability ─────────────────────────────────────────────────────────\n\nlet cheapCount = 0;\nlet expensiveCount = 0;\n\nfunction record(model: string, isCheap: boolean): void {\n if (isCheap) cheapCount++;\n else expensiveCount++;\n const total = cheapCount + expensiveCount;\n const pct = (n: number) => ((n / total) * 100).toFixed(0);\n console.log(\n `[router] → ${isCheap ? \"CHEAP\" : \"EXPENSIVE\"} (${model}) | cheap ${pct(cheapCount)}% / expensive ${pct(expensiveCount)}% (n=${total})`,\n );\n}\n\nexport interface RoutingStats {\n cheap: number;\n expensive: number;\n total: number;\n cheapPct: number;\n expensivePct: number;\n}\n\nexport function getRoutingStats(): RoutingStats {\n const total = cheapCount + expensiveCount;\n return {\n cheap: cheapCount,\n expensive: expensiveCount,\n total,\n cheapPct: total ? (cheapCount / total) * 100 : 0,\n expensivePct: total ? (expensiveCount / total) * 100 : 0,\n };\n}\n\n// ── Shared message util ──────────────────────────────────────────────────────\n\n/** Extract the most recent user turn's text — what the router classifies on. */\nexport function latestUserText(messages: Message[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n const m = messages[i];\n if (m.role !== \"user\") continue;\n const text = m.content\n .filter((b): b is Extract<typeof b, { type: \"text\" }> => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\\n\")\n .trim();\n if (text) return text;\n }\n return \"\";\n}\n","import { latestUserText, selectModel } from \"../router.ts\";\nimport type {\n ContentBlock,\n Message,\n ModelProvider,\n ModelRequest,\n ModelResponse,\n} from \"../types.ts\";\n\nexport interface AnthropicOptions {\n model?: string;\n apiKey?: string;\n maxTokens?: number;\n /**\n * When true, the model is chosen per-request by the cost router (cheap vs\n * expensive) based on query complexity, instead of using a fixed `model`.\n */\n route?: boolean;\n}\n\n/**\n * Real provider backed by the Anthropic Messages API. Requires the optional\n * `@anthropic-ai/sdk` dependency and an ANTHROPIC_API_KEY. The SDK is imported\n * lazily so the package (and the mock demo) work without it installed.\n */\nexport class AnthropicProvider implements ModelProvider {\n readonly name = \"anthropic\";\n private client: any;\n private model: string;\n private maxTokens: number;\n private apiKey?: string;\n private route: boolean;\n\n constructor(opts: AnthropicOptions = {}) {\n this.model = opts.model ?? \"claude-sonnet-4-6\";\n this.maxTokens = opts.maxTokens ?? 2048;\n this.apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;\n this.route = opts.route ?? false;\n }\n\n private async ensureClient(): Promise<void> {\n if (this.client) return;\n const mod = await import(\"@anthropic-ai/sdk\").catch(() => {\n throw new Error(\n \"AnthropicProvider needs the @anthropic-ai/sdk package: run `npm i @anthropic-ai/sdk`.\",\n );\n });\n const Anthropic = (mod as any).default ?? (mod as any).Anthropic;\n this.client = new Anthropic({ apiKey: this.apiKey });\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n await this.ensureClient();\n\n // Cost routing: pick cheap vs expensive per request from the latest user\n // turn. selectModel never throws — it falls back to the expensive model.\n const model = this.route\n ? await selectModel(latestUserText(req.messages), {\n client: this.client,\n apiKey: this.apiKey,\n })\n : this.model;\n\n const res = await this.client.messages.create({\n model,\n max_tokens: this.maxTokens,\n system: req.system,\n tools: req.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema,\n })),\n messages: req.messages.map(toApiMessage),\n });\n\n const content: ContentBlock[] = res.content.map((b: any): ContentBlock => {\n if (b.type === \"tool_use\") return { type: \"tool_use\", id: b.id, name: b.name, input: b.input };\n return { type: \"text\", text: b.type === \"text\" ? b.text : \"\" };\n });\n const stopReason = res.stop_reason === \"tool_use\" ? \"tool_use\" : \"end_turn\";\n return { content, stopReason };\n }\n}\n\nfunction toApiMessage(m: Message): any {\n return {\n role: m.role,\n content: m.content.flatMap((b): any[] => {\n if (b.type === \"text\") return [{ type: \"text\", text: b.text }];\n if (b.type === \"tool_use\") return [{ type: \"tool_use\", id: b.id, name: b.name, input: b.input }];\n if (b.type === \"tool_result\") {\n return [{ type: \"tool_result\", tool_use_id: b.toolUseId, content: b.content, is_error: b.isError }];\n }\n if (b.type === \"image\") {\n const source = b.data\n ? { type: \"base64\", media_type: b.mimeType ?? \"image/png\", data: b.data }\n : { type: \"url\", url: b.url };\n return [{ type: \"image\", source }];\n }\n return []; // video unsupported on Anthropic — drop the block\n }),\n };\n}\n","import { latestUserText, selectGeminiModel } from \"../router.ts\";\nimport type {\n ContentBlock,\n Message,\n ModelProvider,\n ModelRequest,\n ModelResponse,\n} from \"../types.ts\";\n\nexport interface GeminiOptions {\n model?: string;\n apiKey?: string;\n /**\n * When true, the model is chosen per-request by the cost router (cheap vs\n * expensive Gemini) based on query complexity, instead of a fixed `model`.\n */\n route?: boolean;\n}\n\n/**\n * Provider backed by the Google Gemini API (@google/genai). Requires the\n * optional `@google/genai` dependency and a GOOGLE_API_KEY (or GEMINI_API_KEY).\n * The SDK is imported lazily so the package works without it installed.\n */\nexport class GeminiProvider implements ModelProvider {\n readonly name = \"gemini\";\n private client: any;\n private model: string;\n private apiKey?: string;\n private route: boolean;\n\n constructor(opts: GeminiOptions = {}) {\n this.model = opts.model ?? \"gemini-2.5-flash\";\n this.apiKey = opts.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;\n this.route = opts.route ?? false;\n }\n\n private async ensureClient(): Promise<void> {\n if (this.client) return;\n const mod = await import(\"@google/genai\").catch(() => {\n throw new Error(\"GeminiProvider needs the @google/genai package: run `npm i @google/genai`.\");\n });\n const GoogleGenAI = (mod as any).GoogleGenAI;\n this.client = new GoogleGenAI({ apiKey: this.apiKey });\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n await this.ensureClient();\n\n const model = this.route\n ? await selectGeminiModel(latestUserText(req.messages), {\n client: this.client,\n apiKey: this.apiKey,\n })\n : this.model;\n\n const idToName = toolUseNames(req.messages);\n\n const config: any = {};\n if (req.system) config.systemInstruction = req.system;\n if (req.tools.length) {\n config.tools = [\n {\n functionDeclarations: req.tools.map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema,\n })),\n },\n ];\n }\n\n const res = await this.client.models.generateContent({\n model,\n contents: req.messages.map((m) => toGeminiContent(m, idToName)),\n config,\n });\n\n const content: ContentBlock[] = [];\n const text: string | undefined = res.text;\n if (text && text.trim()) content.push({ type: \"text\", text });\n\n const calls: any[] = res.functionCalls ?? [];\n for (const fc of calls) {\n content.push({ type: \"tool_use\", id: fc.id ?? \"\", name: fc.name, input: fc.args ?? {} });\n }\n if (content.length === 0) content.push({ type: \"text\", text: \"\" });\n\n return { content, stopReason: calls.length ? \"tool_use\" : \"end_turn\" };\n }\n}\n\n/** Map tool_use id -> tool name (Gemini matches function responses by name). */\nfunction toolUseNames(messages: Message[]): Map<string, string> {\n const map = new Map<string, string>();\n for (const m of messages) {\n for (const b of m.content) {\n if (b.type === \"tool_use\") map.set(b.id, b.name);\n }\n }\n return map;\n}\n\n/** Translate one of our Messages into a Gemini `Content` (role + parts). */\nfunction toGeminiContent(m: Message, idToName: Map<string, string>): any {\n const role = m.role === \"assistant\" ? \"model\" : \"user\";\n const parts = m.content.map((b): any => {\n switch (b.type) {\n case \"text\":\n return { text: b.text };\n case \"image\":\n case \"video\":\n // base64 -> inlineData; remote URL -> fileData\n return b.data\n ? { inlineData: { mimeType: b.mimeType ?? \"image/png\", data: b.data } }\n : { fileData: { mimeType: b.mimeType ?? \"image/png\", fileUri: b.url ?? \"\" } };\n case \"tool_use\":\n return { functionCall: { id: b.id, name: b.name, args: b.input } };\n case \"tool_result\":\n return {\n functionResponse: {\n id: b.toolUseId,\n name: idToName.get(b.toolUseId) ?? b.toolUseId,\n response: b.isError ? { error: b.content } : { result: b.content },\n },\n };\n }\n });\n return { role, parts };\n}\n","import type {\n ContentBlock,\n MediaBlock,\n ModelProvider,\n ModelRequest,\n ModelResponse,\n} from \"../types.ts\";\n\n// NVIDIA NIM exposes an OpenAI-compatible Chat Completions API, so this provider\n// talks to it with plain `fetch` — no extra SDK dependency. Free hosted endpoints\n// (e.g. Kimi K2.6, DeepSeek V4) are the SDK's default models via the cascade.\n\nexport const NVIDIA_BASE_URL = \"https://integrate.api.nvidia.com/v1\";\n\n// Exact IDs confirmed against GET /v1/models.\nexport const KIMI_K2_6 = \"moonshotai/kimi-k2.6\"; // 256K ctx, tools, agentic — text-only on NIM (verified)\nexport const DEEPSEEK_V4_PRO = \"deepseek-ai/deepseek-v4-pro\"; // 1M ctx, tools, text-only\nexport const DEEPSEEK_V4_FLASH = \"deepseek-ai/deepseek-v4-flash\"; // faster/cheaper, text-only\nexport const LLAMA_VISION = \"meta/llama-3.2-90b-vision-instruct\"; // free NVIDIA vision model (image), verified\n\nexport interface NvidiaOptions {\n model?: string;\n apiKey?: string;\n baseURL?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport class NvidiaProvider implements ModelProvider {\n readonly name = \"nvidia\";\n private model: string;\n private apiKey?: string;\n private baseURL: string;\n private maxTokens: number;\n private temperature: number;\n\n constructor(opts: NvidiaOptions = {}) {\n this.model = opts.model ?? KIMI_K2_6;\n this.apiKey = opts.apiKey ?? process.env.NVIDIA_API_KEY;\n this.baseURL = opts.baseURL ?? NVIDIA_BASE_URL;\n this.maxTokens = opts.maxTokens ?? 2048;\n this.temperature = opts.temperature ?? 0.2; // low default for deterministic agent behavior\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n if (!this.apiKey) throw new Error(\"NvidiaProvider needs NVIDIA_API_KEY (nvapi-...).\");\n\n const body: Record<string, unknown> = {\n model: this.model,\n messages: toOpenAIMessages(req),\n max_tokens: this.maxTokens,\n temperature: this.temperature,\n };\n if (req.tools.length) {\n body.tools = req.tools.map((t) => ({\n type: \"function\",\n function: { name: t.name, description: t.description, parameters: t.inputSchema },\n }));\n body.tool_choice = \"auto\";\n }\n\n const res = await fetch(`${this.baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n throw new Error(`NVIDIA ${this.model} ${res.status}: ${(await res.text()).slice(0, 300)}`);\n }\n\n const json: any = await res.json();\n const choice = json.choices?.[0];\n const msg = choice?.message ?? {};\n\n const content: ContentBlock[] = [];\n if (typeof msg.content === \"string\" && msg.content.trim()) {\n content.push({ type: \"text\", text: msg.content });\n }\n const toolCalls: any[] = msg.tool_calls ?? [];\n for (const tc of toolCalls) {\n content.push({\n type: \"tool_use\",\n id: tc.id ?? \"\",\n name: tc.function?.name ?? \"\",\n input: safeParse(tc.function?.arguments),\n });\n }\n if (content.length === 0) content.push({ type: \"text\", text: \"\" });\n\n const stopReason =\n choice?.finish_reason === \"tool_calls\" || toolCalls.length ? \"tool_use\" : \"end_turn\";\n return { content, stopReason };\n }\n}\n\nfunction safeParse(args: unknown): Record<string, unknown> {\n if (typeof args !== \"string\") return (args as Record<string, unknown>) ?? {};\n try {\n return JSON.parse(args);\n } catch {\n return {};\n }\n}\n\n/** Map our Messages into OpenAI-style chat messages (tool calls + tool results + media). */\nfunction toOpenAIMessages(req: ModelRequest): any[] {\n const out: any[] = [];\n if (req.system) out.push({ role: \"system\", content: req.system });\n\n for (const m of req.messages) {\n if (m.role === \"user\") {\n // tool_result blocks become individual {role:\"tool\"} messages\n for (const b of m.content) {\n if (b.type === \"tool_result\") {\n out.push({ role: \"tool\", tool_call_id: b.toolUseId, content: b.content });\n }\n }\n const parts = m.content.filter(\n (b) => b.type === \"text\" || b.type === \"image\" || b.type === \"video\",\n );\n if (parts.length) {\n const multimodal = parts.some((b) => b.type !== \"text\");\n out.push({\n role: \"user\",\n content: multimodal\n ? parts.map(toOpenAIPart)\n : parts.map((b) => (b as { text: string }).text).join(\"\\n\"),\n });\n }\n } else {\n // assistant\n const text = m.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n const toolUses = m.content.filter((b) => b.type === \"tool_use\");\n const msg: any = { role: \"assistant\", content: text || null };\n if (toolUses.length) {\n msg.tool_calls = toolUses.map((b: any) => ({\n id: b.id,\n type: \"function\",\n function: { name: b.name, arguments: JSON.stringify(b.input) },\n }));\n }\n out.push(msg);\n }\n }\n return out;\n}\n\nfunction toOpenAIPart(b: ContentBlock): any {\n if (b.type === \"text\") return { type: \"text\", text: b.text };\n const media = b as MediaBlock;\n const url =\n media.url ??\n (media.data ? `data:${media.mimeType ?? \"application/octet-stream\"};base64,${media.data}` : \"\");\n if (media.type === \"video\") return { type: \"video_url\", video_url: { url } }; // experimental\n return { type: \"image_url\", image_url: { url } };\n}\n","import type { ModelProvider, ModelRequest, ModelResponse } from \"../types.ts\";\nimport { DEEPSEEK_V4_PRO, KIMI_K2_6, LLAMA_VISION, NvidiaProvider } from \"./nvidia.ts\";\nimport { GeminiProvider } from \"./gemini.ts\";\n\n// Orchestration: try a prioritized list of (provider, model) steps, falling\n// through to the next on failure (rate limit, error, or capability mismatch).\n// Capability-aware: image requests only go to vision steps; video requests only\n// to video steps — text-only models (Kimi, DeepSeek) are skipped for those.\n\nexport interface CascadeStep {\n provider: ModelProvider;\n label: string; // e.g. \"nvidia:kimi-k2.6\"\n vision: boolean; // accepts image input?\n video?: boolean; // accepts video input? (default false)\n}\n\nexport interface CascadeOptions {\n steps: CascadeStep[];\n /** Called when a step is skipped or fails and the cascade falls through. */\n onFallback?: (info: { from: string; reason: string; needsVision: boolean }) => void;\n}\n\nexport class CascadeProvider implements ModelProvider {\n readonly name = \"cascade\";\n private steps: CascadeStep[];\n private onFallback?: CascadeOptions[\"onFallback\"];\n\n constructor(opts: CascadeOptions) {\n if (!opts.steps.length) throw new Error(\"CascadeProvider needs at least one step.\");\n this.steps = opts.steps;\n this.onFallback = opts.onFallback;\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n const has = (t: \"image\" | \"video\") =>\n req.messages.some((m) => m.content.some((b) => b.type === t));\n const needsVideo = has(\"video\");\n const needsImage = has(\"image\");\n const needsVision = needsImage || needsVideo;\n\n const eligible = needsVideo\n ? this.steps.filter((s) => s.video)\n : needsImage\n ? this.steps.filter((s) => s.vision)\n : this.steps;\n\n if (!eligible.length) {\n throw new Error(\n `Cascade: request needs ${needsVideo ? \"video\" : \"image\"} input but no step supports it.`,\n );\n }\n\n let lastErr: unknown;\n for (const step of eligible) {\n try {\n return await step.provider.generate(req);\n } catch (err) {\n lastErr = err;\n this.onFallback?.({\n from: step.label,\n reason: (err as Error).message?.slice(0, 200) ?? \"unknown\",\n needsVision,\n });\n }\n }\n throw new Error(`Cascade exhausted all steps. Last error: ${(lastErr as Error)?.message}`);\n }\n}\n\nexport interface DefaultProviderOptions {\n nvidiaApiKey?: string;\n googleApiKey?: string;\n /** Override the main NVIDIA model (default Kimi K2.6). */\n mainModel?: string;\n /** Override the secondary NVIDIA model (default DeepSeek V4 Pro). */\n secondaryModel?: string;\n /** NVIDIA vision model for image requests (default llama-3.2-90b-vision). */\n visionModel?: string;\n /** Gemini model used as the final fallback option (default gemini-2.5-flash). */\n geminiModel?: string;\n onFallback?: CascadeOptions[\"onFallback\"];\n}\n\n/**\n * The SDK's recommended default: free NVIDIA endpoints first, Google as one\n * fallback option. Capability-aware — image/video requests skip the text-only\n * steps automatically.\n *\n * 1. NVIDIA Kimi K2.6 — main; agentic + tools (text)\n * 2. NVIDIA DeepSeek V4 Pro — 1M-ctx text; skipped for media\n * 3. NVIDIA Llama-3.2-90B-Vision — image requests\n * 4. Gemini 2.5 Flash — final fallback; image + video\n */\nexport function createDefaultProvider(opts: DefaultProviderOptions = {}): CascadeProvider {\n const main = opts.mainModel ?? KIMI_K2_6;\n const secondary = opts.secondaryModel ?? DEEPSEEK_V4_PRO;\n const vision = opts.visionModel ?? LLAMA_VISION;\n const gemini = opts.geminiModel ?? \"gemini-2.5-flash\";\n const nv = (model: string) => new NvidiaProvider({ model, apiKey: opts.nvidiaApiKey });\n\n return new CascadeProvider({\n onFallback:\n opts.onFallback ??\n ((info) =>\n console.warn(`[cascade] ${info.from} failed (${info.reason}); trying next`)),\n steps: [\n { provider: nv(main), label: `nvidia:${main}`, vision: false, video: false },\n { provider: nv(secondary), label: `nvidia:${secondary}`, vision: false, video: false },\n { provider: nv(vision), label: `nvidia:${vision}`, vision: true, video: false },\n {\n provider: new GeminiProvider({ model: gemini, apiKey: opts.googleApiKey }),\n label: `gemini:${gemini}`,\n vision: true,\n video: true,\n },\n ],\n });\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { builtinTools } from \"./builtins.ts\";\nimport { runLoop } from \"./loop.ts\";\nimport { matchesAllow, PermissionEngine } from \"./permissions.ts\";\nimport { createCatalogServer, type CatalogItem } from \"./packkit.ts\";\nimport { createDefaultProvider } from \"./providers/cascade.ts\";\nimport { ToolRegistry } from \"./tools.ts\";\nimport type {\n AgentEvent,\n CanUseTool,\n ContentBlock,\n Message,\n ModelProvider,\n SdkMcpServer,\n} from \"./types.ts\";\n\n// Specialize the generic engine to a product by loading a *pack* (an adapter):\n// persona + sales playbook + policy + domain tools + catalog grounding + guardrails.\n// One engine, many packs — don't fork the SDK per vertical.\n\nexport interface PackKnowledge {\n /** Product catalog — auto-wired into a `search_catalog` tool for grounding. */\n catalog?: CatalogItem[];\n /** Short reference text (policies, FAQs) appended to the system prompt. */\n faqs?: string;\n}\n\nexport interface PackGuardrails {\n /** Allowlist of tool names the agent may call (namespaced, wildcards ok). */\n allowedTools?: string[];\n /** Tools that require explicit confirmation before running (namespaced names). */\n confirm?: string[];\n /** Extra custom gate, evaluated after allow/confirm. */\n canUseTool?: CanUseTool;\n /** Rules text (discount authority, no-overpromise, escalation) added to the prompt. */\n policy?: string;\n}\n\nexport interface AgentPack {\n name: string;\n persona: string; // who it is + voice (system prompt core)\n playbook?: string; // sales stages + goal\n tools?: SdkMcpServer[]; // domain actions (quote, reserve, invoice, handoff, ...)\n knowledge?: PackKnowledge;\n guardrails?: PackGuardrails;\n model?: ModelProvider; // defaults to the free-first cascade\n}\n\nexport interface SpecializeOptions {\n provider?: ModelProvider;\n /** Called when a `confirm` tool wants to run; return true to allow. */\n onConfirm?: (toolName: string, input: Record<string, unknown>) => boolean | Promise<boolean>;\n /** Allow built-in file tools (read/write/list). Off by default for packs. */\n includeBuiltins?: boolean;\n maxTurns?: number;\n}\n\nexport interface SpecializedAgent {\n pack: AgentPack;\n system: string;\n servers: SdkMcpServer[];\n query(prompt: string | ContentBlock[], extra?: { maxTurns?: number }): AsyncGenerator<AgentEvent>;\n}\n\n/** Build a ready-to-run specialized agent from a pack. */\nexport function createSpecializedAgent(pack: AgentPack, opts: SpecializeOptions = {}): SpecializedAgent {\n // Assemble the system prompt from persona + playbook + policy + grounding + faqs.\n const servers: SdkMcpServer[] = [...(pack.tools ?? [])];\n if (pack.knowledge?.catalog?.length) servers.unshift(createCatalogServer(pack.knowledge.catalog));\n\n const parts = [pack.persona.trim()];\n if (pack.playbook) parts.push(`## Playbook\\n${pack.playbook.trim()}`);\n if (pack.guardrails?.policy) parts.push(`## Policy\\n${pack.guardrails.policy.trim()}`);\n if (servers.some((s) => s.tools.some((t) => t.name === \"search_catalog\"))) {\n parts.push(\n \"Use the `search_catalog` tool for every product, price, or availability question. Never invent a price or claim availability you did not look up.\",\n );\n }\n if (pack.knowledge?.faqs) parts.push(`## Reference\\n${pack.knowledge.faqs.trim()}`);\n const system = parts.join(\"\\n\\n\");\n\n const confirmTools = pack.guardrails?.confirm ?? [];\n const allow = pack.guardrails?.allowedTools;\n const base = pack.guardrails?.canUseTool;\n\n const canUseTool: CanUseTool = async (name, input) => {\n if (confirmTools.includes(name)) {\n const ok = opts.onConfirm ? await opts.onConfirm(name, input) : false;\n if (!ok) return { behavior: \"deny\", message: `${name} requires confirmation and it was not granted.` };\n }\n if (allow && !matchesAllow(name, allow)) {\n return { behavior: \"deny\", message: `${name} is not allowed by this pack's guardrails.` };\n }\n return base ? base(name, input) : { behavior: \"allow\" };\n };\n\n const provider = opts.provider ?? pack.model ?? createDefaultProvider();\n const includeBuiltins = opts.includeBuiltins ?? false;\n\n return {\n pack,\n system,\n servers,\n async *query(prompt, extra) {\n const registry = new ToolRegistry();\n if (includeBuiltins) registry.addBuiltins(builtinTools);\n for (const s of servers) registry.addServer(s);\n\n const content: ContentBlock[] =\n typeof prompt === \"string\" ? [{ type: \"text\", text: prompt }] : prompt;\n const messages: Message[] = [{ role: \"user\", content }];\n\n const result = yield* runLoop({\n provider,\n registry,\n permissions: new PermissionEngine({ canUseTool }),\n system,\n messages,\n toolContext: { workspaceDir: process.cwd() },\n maxTurns: extra?.maxTurns ?? opts.maxTurns,\n });\n yield { type: \"result\", finalText: result.finalText, turns: result.turns };\n },\n };\n}\n\n/**\n * Load a pack's content from a folder (so non-devs can edit it):\n * persona.md · playbook.md · policy.md · catalog.json · faqs.md\n * Code tools (quote/reserve/invoice/...) are passed via `opts.tools`.\n */\nexport async function loadPack(\n dir: string,\n opts: { tools?: SdkMcpServer[] } = {},\n): Promise<AgentPack> {\n const read = async (f: string): Promise<string | undefined> => {\n const p = join(dir, f);\n return existsSync(p) ? await readFile(p, \"utf8\") : undefined;\n };\n const catalogRaw = await read(\"catalog.json\");\n const policy = await read(\"policy.md\");\n return {\n name: dir.split(/[\\\\/]/).filter(Boolean).pop() ?? \"pack\",\n persona: (await read(\"persona.md\")) ?? \"\",\n playbook: await read(\"playbook.md\"),\n knowledge: {\n catalog: catalogRaw ? (JSON.parse(catalogRaw) as CatalogItem[]) : undefined,\n faqs: await read(\"faqs.md\"),\n },\n guardrails: policy ? { policy } : undefined,\n tools: opts.tools,\n };\n}\n","import { createSdkMcpServer, tool } from \"./tools.ts\";\nimport type { SdkMcpServer } from \"./types.ts\";\n\n// Reusable tool patterns for specializing an agent to a vertical (a \"pack\").\n// Compose these into a pack's `tools`. They are deliberately backend-agnostic —\n// swap the in-memory stubs for real catalog/CRM/payment integrations later.\n\nexport type CatalogItem = Record<string, unknown> & {\n id?: string;\n name?: string;\n price?: number;\n tags?: string[];\n available?: boolean;\n};\n\n/** A `search_catalog` tool over an in-memory product list (text + price + tags). */\nexport function createCatalogServer(\n items: CatalogItem[],\n opts: { serverName?: string } = {},\n): SdkMcpServer {\n const search = tool(\n \"search_catalog\",\n \"Search the product catalog by text, max price, and tags. Returns matching items with prices and availability. Use this for every product/price/availability question — never guess.\",\n {\n type: \"object\",\n properties: {\n query: { type: \"string\" },\n maxPrice: { type: \"number\" },\n tags: { type: \"array\", items: { type: \"string\" } },\n limit: { type: \"number\" },\n },\n },\n (input: { query?: string; maxPrice?: number; tags?: string[]; limit?: number }) => {\n let res = items.filter((it) => it.available !== false);\n if (input.query) {\n const words = input.query.toLowerCase().split(/\\s+/).filter(Boolean);\n res = res.filter((it) => {\n const hay = JSON.stringify(it).toLowerCase();\n return words.every((w) => hay.includes(w));\n });\n }\n if (typeof input.maxPrice === \"number\") {\n res = res.filter((it) => typeof it.price !== \"number\" || it.price <= input.maxPrice!);\n }\n if (Array.isArray(input.tags) && input.tags.length) {\n res = res.filter((it) => Array.isArray(it.tags) && input.tags!.some((t) => it.tags!.includes(t)));\n }\n const out = res.slice(0, input.limit ?? 5);\n return { content: out.length ? JSON.stringify(out, null, 2) : \"No matching items.\" };\n },\n );\n return createSdkMcpServer({ name: opts.serverName ?? \"catalog\", tools: [search] });\n}\n\n/** `get_lead` / `update_lead` over an in-memory customer profile (the funnel state). */\nexport function createLeadMemoryServer(\n initial: Record<string, unknown> = {},\n): SdkMcpServer & { lead: Record<string, unknown> } {\n const lead: Record<string, unknown> = { ...initial };\n const get = tool(\n \"get_lead\",\n \"Get what we know about the current customer (name, date, budget, stage, items seen).\",\n { type: \"object\", properties: {} },\n () => ({ content: JSON.stringify(lead, null, 2) }),\n );\n const update = tool(\n \"update_lead\",\n \"Merge fields into the customer profile, e.g. { budget: 2000, stage: 'recommend' }.\",\n { type: \"object\", properties: { fields: { type: \"object\" } }, required: [\"fields\"] },\n (input: { fields: Record<string, unknown> }) => {\n Object.assign(lead, input.fields ?? {});\n return { content: `updated: ${Object.keys(input.fields ?? {}).join(\", \") || \"(none)\"}` };\n },\n );\n return Object.assign(createSdkMcpServer({ name: \"lead\", tools: [get, update] }), { lead });\n}\n\nexport interface Invoice {\n id: string;\n amount: number;\n currency: string;\n items?: unknown;\n customer?: unknown;\n status: \"pending\";\n}\n\n/**\n * A generic `create_invoice` settle tool: records an order + amount as pending\n * and returns an invoice id. Provider-agnostic — wire your processor via\n * `onCreate` (e.g. create a real payment link, then confirm via webhook).\n */\nexport function createInvoiceServer(\n opts: { onCreate?: (inv: Invoice) => void } = {},\n): SdkMcpServer & { invoices: Invoice[] } {\n const invoices: Invoice[] = [];\n let n = 0;\n const create = tool(\n \"create_invoice\",\n \"Record an order and amount as a pending invoice to settle, returning an invoice id. Call this only after the customer has agreed to buy.\",\n {\n type: \"object\",\n properties: {\n amount: { type: \"number\" },\n currency: { type: \"string\" },\n items: {},\n customer: {},\n },\n required: [\"amount\"],\n },\n (input: { amount: number; currency?: string; items?: unknown; customer?: unknown }) => {\n const inv: Invoice = {\n id: `inv_${++n}`,\n amount: input.amount,\n currency: input.currency ?? \"USD\",\n items: input.items,\n customer: input.customer,\n status: \"pending\",\n };\n invoices.push(inv);\n opts.onCreate?.(inv);\n return {\n content: JSON.stringify({ invoiceId: inv.id, status: inv.status, amount: inv.amount, currency: inv.currency }),\n };\n },\n );\n return Object.assign(createSdkMcpServer({ name: \"billing\", tools: [create] }), { invoices });\n}\n\n/** A `handoff_human` escalation tool. Wire `onHandoff` to notify a real agent. */\nexport function createHandoffServer(\n opts: { onHandoff?: (info: { reason: string; summary: string }) => void } = {},\n): SdkMcpServer {\n const handoff = tool(\n \"handoff_human\",\n \"Escalate to a human agent with a reason and a short summary of the conversation so far. Use when you're stuck, the request is high-value, or the customer asks for a person.\",\n {\n type: \"object\",\n properties: { reason: { type: \"string\" }, summary: { type: \"string\" } },\n required: [\"reason\"],\n },\n (input: { reason: string; summary?: string }) => {\n opts.onHandoff?.({ reason: input.reason, summary: input.summary ?? \"\" });\n return { content: \"Escalated to a human; they will take over shortly.\" };\n },\n );\n return createSdkMcpServer({ name: \"support\", tools: [handoff] });\n}\n","// Public API for Torus.\n\nexport * from \"./types.ts\";\nexport { tool, createSdkMcpServer, ToolRegistry, type RegisteredTool } from \"./tools.ts\";\nexport { PermissionEngine, matchesAllow, type PermissionConfig } from \"./permissions.ts\";\nexport { runLoop, type LoopOptions, type LoopResult } from \"./loop.ts\";\nexport { runPipeline, type PipelineOptions } from \"./pipeline.ts\";\nexport { builtinTools, readFileTool, writeFileTool, listDirTool } from \"./builtins.ts\";\nexport { loadStages, parseContract, type StageContract, type StageInput } from \"./subagents.ts\";\nexport { loadStageContext, type LoadedContext } from \"./context.ts\";\nexport { MockProvider, type MockOptions } from \"./providers/mock.ts\";\nexport { AnthropicProvider, type AnthropicOptions } from \"./providers/anthropic.ts\";\nexport { GeminiProvider, type GeminiOptions } from \"./providers/gemini.ts\";\nexport {\n NvidiaProvider,\n type NvidiaOptions,\n NVIDIA_BASE_URL,\n KIMI_K2_6,\n DEEPSEEK_V4_PRO,\n DEEPSEEK_V4_FLASH,\n LLAMA_VISION,\n} from \"./providers/nvidia.ts\";\nexport {\n CascadeProvider,\n createDefaultProvider,\n type CascadeStep,\n type CascadeOptions,\n type DefaultProviderOptions,\n} from \"./providers/cascade.ts\";\n\n// Specialization: turn the generic engine into a vertical agent via a \"pack\".\nexport {\n createSpecializedAgent,\n loadPack,\n type AgentPack,\n type PackKnowledge,\n type PackGuardrails,\n type SpecializeOptions,\n type SpecializedAgent,\n} from \"./pack.ts\";\nexport {\n createCatalogServer,\n createLeadMemoryServer,\n createInvoiceServer,\n createHandoffServer,\n type CatalogItem,\n type Invoice,\n} from \"./packkit.ts\";\nexport {\n // Anthropic (Claude) routing\n CHEAP_MODEL,\n EXPENSIVE_MODEL,\n selectModel,\n classifyComplexity,\n judgeComplexity,\n // Gemini routing — same mechanism, Gemini models\n GEMINI_CHEAP_MODEL,\n GEMINI_EXPENSIVE_MODEL,\n selectGeminiModel,\n classifyComplexityGemini,\n judgeComplexityGemini,\n // Shared\n fastHeuristic,\n getRoutingStats,\n latestUserText,\n type Complexity,\n type RouterOptions,\n type RoutingStats,\n} from \"./router.ts\";\n\nimport { builtinTools } from \"./builtins.ts\";\nimport { createDefaultProvider } from \"./providers/cascade.ts\";\nimport { runLoop } from \"./loop.ts\";\nimport { PermissionEngine, type PermissionConfig } from \"./permissions.ts\";\nimport { ToolRegistry } from \"./tools.ts\";\nimport type { AgentEvent, ContentBlock, Message, ModelProvider, SdkMcpServer } from \"./types.ts\";\n\nexport interface QueryOptions {\n /** Defaults to the NVIDIA-first cascade (Kimi K2.6 → DeepSeek V4 → Gemini). */\n provider?: ModelProvider;\n system?: string;\n mcpServers?: SdkMcpServer[];\n includeBuiltins?: boolean; // default true\n permissions?: PermissionConfig;\n workspaceDir?: string;\n maxTurns?: number;\n}\n\n/**\n * Single-shot agent run (no pipeline). Mirrors the Claude Agent SDK's streaming\n * `query()`: yields events as they happen and a final `result` event. The prompt\n * may be a string or an array of content blocks (e.g. text + image for vision).\n *\n * for await (const ev of query(\"Summarize X\", { mcpServers: [srv] })) { ... }\n * for await (const ev of query([{ type: \"text\", text: \"What's this?\" },\n * { type: \"image\", url: \"https://...\" }])) { ... }\n */\nexport async function* query(\n prompt: string | ContentBlock[],\n options: QueryOptions = {},\n): AsyncGenerator<AgentEvent> {\n const registry = new ToolRegistry();\n if (options.includeBuiltins ?? true) registry.addBuiltins(builtinTools);\n for (const s of options.mcpServers ?? []) registry.addServer(s);\n\n const content: ContentBlock[] =\n typeof prompt === \"string\" ? [{ type: \"text\", text: prompt }] : prompt;\n const messages: Message[] = [{ role: \"user\", content }];\n const result = yield* runLoop({\n provider: options.provider ?? createDefaultProvider(),\n registry,\n permissions: new PermissionEngine(options.permissions ?? {}),\n system: options.system ?? \"You are a helpful agent.\",\n messages,\n toolContext: { workspaceDir: options.workspaceDir ?? process.cwd() },\n maxTurns: options.maxTurns,\n });\n yield { type: \"result\", finalText: result.finalText, turns: result.turns };\n}\n"],"mappings":"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","names":["mkdir","writeFile","join","readFile","readFile","readFile","readdir","join","join","mkdir","writeFile","estimateTokens","existsSync","readFile","join","join","existsSync","readFile"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/tools.ts","../src/permissions.ts","../src/loop.ts","../src/pipeline.ts","../src/context.ts","../src/builtins.ts","../src/subagents.ts","../src/providers/mock.ts","../src/router.ts","../src/providers/anthropic.ts","../src/providers/gemini.ts","../src/providers/nvidia.ts","../src/providers/cascade.ts","../src/pack.ts","../src/packkit.ts","../src/mcp-client.ts","../src/index.ts"],"sourcesContent":["// ─────────────────────────────────────────────────────────────────────────\n// Core wire types — the plain-data interface every layer speaks (ICM principle 2:\n// \"plain text/structured data is the interface\"). No provider-specific shapes leak\n// past this file; the AnthropicProvider/MockProvider translate to and from these.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type Role = \"user\" | \"assistant\";\n\nexport interface TextBlock {\n type: \"text\";\n text: string;\n}\nexport interface ToolUseBlock {\n type: \"tool_use\";\n id: string;\n name: string; // namespaced name as offered to the model, e.g. \"mcp__research__lookup\"\n input: Record<string, unknown>;\n}\nexport interface ToolResultBlock {\n type: \"tool_result\";\n toolUseId: string;\n content: string;\n isError?: boolean;\n}\n/**\n * Multimodal input. Provide either a remote `url` or base64 `data` (+ `mimeType`).\n * Image is broadly supported; video is experimental and model-dependent (routed\n * to a video-capable model like Kimi K2.6).\n */\nexport interface MediaBlock {\n type: \"image\" | \"video\";\n url?: string; // remote URL or a data: URL\n data?: string; // raw base64 (paired with mimeType)\n mimeType?: string; // e.g. \"image/png\", \"image/jpeg\", \"video/mp4\"\n}\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | MediaBlock;\n\n/** True if a message list carries any image/video content (drives vision routing). */\nexport function hasMedia(messages: Message[]): boolean {\n return messages.some((m) => m.content.some((b) => b.type === \"image\" || b.type === \"video\"));\n}\n\nexport interface Message {\n role: Role;\n content: ContentBlock[];\n}\n\nexport type StopReason = \"end_turn\" | \"tool_use\" | \"max_turns\";\n\nexport interface ModelResponse {\n content: ContentBlock[];\n stopReason: StopReason;\n}\n\nexport type JSONSchema = Record<string, unknown>;\n\nexport interface ToolSchema {\n name: string;\n description: string;\n inputSchema: JSONSchema;\n}\n\nexport interface ModelRequest {\n system: string;\n messages: Message[];\n tools: ToolSchema[];\n}\n\n/** The one capability the SDK needs from any model backend. Swap freely. */\nexport interface ModelProvider {\n readonly name: string;\n generate(req: ModelRequest): Promise<ModelResponse>;\n}\n\n// ── Tools ────────────────────────────────────────────────────────────────\n\nexport interface ToolResultPayload {\n content: string;\n isError?: boolean;\n}\n\nexport interface ToolContext {\n workspaceDir: string;\n stageDir?: string;\n signal?: AbortSignal;\n}\n\nexport interface ToolDefinition {\n name: string; // bare name, e.g. \"lookup\"; namespacing is applied at registration\n description: string;\n inputSchema: JSONSchema;\n handler: (\n input: any,\n ctx: ToolContext,\n ) => Promise<ToolResultPayload> | ToolResultPayload;\n}\n\n/** An in-process MCP server: tools that run in this same process, no subprocess. */\nexport interface SdkMcpServer {\n kind: \"sdk-mcp\";\n name: string; // becomes the mcp__<name>__ namespace prefix\n version: string;\n tools: ToolDefinition[];\n}\n\n// ── Permissions ────────────────────────────────────────────────────────────\n\nexport type PermissionDecision =\n | { behavior: \"allow\"; updatedInput?: Record<string, unknown> }\n | { behavior: \"deny\"; message: string };\n\nexport type CanUseTool = (\n toolName: string,\n input: Record<string, unknown>,\n) => Promise<PermissionDecision> | PermissionDecision;\n\n// ── Streaming events ───────────────────────────────────────────────────────\n\nexport type AgentEvent =\n | { type: \"assistant_text\"; text: string; stage?: string }\n | { type: \"tool_use\"; name: string; input: Record<string, unknown>; stage?: string }\n | { type: \"tool_result\"; name: string; content: string; isError: boolean; stage?: string }\n | { type: \"permission_denied\"; name: string; message: string; stage?: string }\n | { type: \"stage_start\"; stage: string }\n | { type: \"stage_output\"; stage: string; artifact: string; path: string }\n | { type: \"context_loaded\"; stage?: string; tokensEstimated: number; files: string[] }\n | { type: \"result\"; finalText: string; turns: number; stage?: string };\n","import type {\n JSONSchema,\n SdkMcpServer,\n ToolContext,\n ToolDefinition,\n ToolResultPayload,\n ToolSchema,\n} from \"./types.ts\";\n\n/**\n * Define a custom tool. Mirrors `tool()` from the Claude Agent SDK.\n * tool(\"get_temp\", \"Get temperature\", { type:\"object\", ... }, async (input, ctx) => ...)\n */\nexport function tool(\n name: string,\n description: string,\n inputSchema: JSONSchema,\n handler: (input: any, ctx: ToolContext) => Promise<ToolResultPayload> | ToolResultPayload,\n): ToolDefinition {\n return { name, description, inputSchema, handler };\n}\n\n/**\n * Bundle tools into an in-process MCP server. Mirrors `createSdkMcpServer()`.\n * Tools become namespaced `mcp__<name>__<tool>` when registered.\n */\nexport function createSdkMcpServer(opts: {\n name: string;\n version?: string;\n tools: ToolDefinition[];\n}): SdkMcpServer {\n return { kind: \"sdk-mcp\", name: opts.name, version: opts.version ?? \"1.0.0\", tools: opts.tools };\n}\n\nexport interface RegisteredTool {\n fullName: string; // \"mcp__research__lookup\" or built-in \"read_file\"\n def: ToolDefinition;\n}\n\n/** Holds the model-facing tool catalog and executes calls by namespaced name. */\nexport class ToolRegistry {\n private map = new Map<string, ToolDefinition>();\n\n /** Built-ins register under their bare name (no namespace). */\n addBuiltins(defs: ToolDefinition[]): this {\n for (const d of defs) this.map.set(d.name, d);\n return this;\n }\n\n /** SDK MCP server tools register as mcp__<server>__<tool>. */\n addServer(server: SdkMcpServer): this {\n for (const t of server.tools) this.map.set(`mcp__${server.name}__${t.name}`, t);\n return this;\n }\n\n has(fullName: string): boolean {\n return this.map.has(fullName);\n }\n\n list(): RegisteredTool[] {\n return [...this.map.entries()].map(([fullName, def]) => ({ fullName, def }));\n }\n\n /** Tool schemas to hand the model, optionally filtered to a stage's allowlist. */\n schemas(filter?: (fullName: string) => boolean): ToolSchema[] {\n return this.list()\n .filter((t) => !filter || filter(t.fullName))\n .map((t) => ({ name: t.fullName, description: t.def.description, inputSchema: t.def.inputSchema }));\n }\n\n async execute(\n fullName: string,\n input: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResultPayload> {\n const def = this.map.get(fullName);\n if (!def) return { content: `Unknown tool: ${fullName}`, isError: true };\n try {\n return await def.handler(input, ctx);\n } catch (err) {\n return { content: `Tool ${fullName} threw: ${(err as Error).message}`, isError: true };\n }\n }\n}\n","import type { CanUseTool, PermissionDecision } from \"./types.ts\";\n\n/** Match a tool name against patterns supporting a trailing \"*\" wildcard. */\nexport function matchesAllow(name: string, patterns: string[]): boolean {\n return patterns.some((p) => {\n if (p === \"*\") return true;\n if (p.endsWith(\"*\")) return name.startsWith(p.slice(0, -1));\n return p === name;\n });\n}\n\nexport interface PermissionConfig {\n /** Allowlist (wildcards ok). If omitted, all tools allowed unless canUseTool vetoes. */\n allowedTools?: string[];\n /** Explicit denials, evaluated first. */\n disallowedTools?: string[];\n /** Final custom gate — can allow non-allowlisted tools, veto allowlisted ones, or rewrite input. */\n canUseTool?: CanUseTool;\n}\n\n/**\n * Evaluation order (mirrors the Agent SDK):\n * 1. disallowedTools → deny\n * 2. allowedTools → allow (if no canUseTool)\n * 3. canUseTool → final say\n * 4. default → allow when no allowlist, deny when allowlist set and unmatched\n */\nexport class PermissionEngine {\n private cfg: PermissionConfig;\n constructor(cfg: PermissionConfig = {}) {\n this.cfg = cfg;\n }\n\n async check(name: string, input: Record<string, unknown>): Promise<PermissionDecision> {\n const { allowedTools, disallowedTools, canUseTool } = this.cfg;\n\n if (disallowedTools && matchesAllow(name, disallowedTools)) {\n return { behavior: \"deny\", message: `${name} is in disallowedTools.` };\n }\n\n const onAllowlist = allowedTools ? matchesAllow(name, allowedTools) : true;\n\n if (canUseTool) return canUseTool(name, input); // callback has the final word\n\n if (onAllowlist) return { behavior: \"allow\" };\n return {\n behavior: \"deny\",\n message: `${name} is not in allowedTools and no canUseTool callback is set.`,\n };\n }\n}\n","import type { PermissionEngine } from \"./permissions.ts\";\nimport type { ToolRegistry } from \"./tools.ts\";\nimport type {\n AgentEvent,\n Message,\n ModelProvider,\n ToolContext,\n ToolResultBlock,\n} from \"./types.ts\";\n\n// The core agentic loop: gather context → call model → if it wants tools, run them\n// under the permission gate and feed results back → repeat until the model stops\n// asking for tools (or we hit maxTurns). This is the same contract the Claude Agent\n// SDK runs; everything else in this package just shapes what enters and leaves it.\n\nexport interface LoopOptions {\n provider: ModelProvider;\n registry: ToolRegistry;\n permissions: PermissionEngine;\n system: string;\n messages: Message[]; // seeded with the user turn\n toolContext: ToolContext;\n toolFilter?: (fullName: string) => boolean; // which tools to offer this run\n maxTurns?: number;\n stage?: string;\n}\n\nexport interface LoopResult {\n finalText: string;\n turns: number;\n messages: Message[];\n}\n\nlet counter = 0;\nconst genId = () => `tu_${++counter}`;\n\nexport async function* runLoop(opts: LoopOptions): AsyncGenerator<AgentEvent, LoopResult> {\n const { provider, registry, permissions, system, messages, toolContext } = opts;\n const maxTurns = opts.maxTurns ?? 8;\n const tools = registry.schemas(opts.toolFilter);\n\n let turns = 0;\n let finalText = \"\";\n\n while (turns < maxTurns) {\n turns++;\n const res = await provider.generate({ system, messages, tools });\n\n // Ensure every tool_use has an id (mock providers may omit it).\n for (const b of res.content) if (b.type === \"tool_use\" && !b.id) b.id = genId();\n messages.push({ role: \"assistant\", content: res.content });\n\n for (const b of res.content) {\n if (b.type === \"text\" && b.text.trim()) {\n yield { type: \"assistant_text\", text: b.text, stage: opts.stage };\n }\n }\n\n if (res.stopReason !== \"tool_use\") {\n finalText = res.content\n .filter((b): b is Extract<typeof b, { type: \"text\" }> => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\\n\")\n .trim();\n return { finalText, turns, messages };\n }\n\n const toolResults: ToolResultBlock[] = [];\n for (const b of res.content) {\n if (b.type !== \"tool_use\") continue;\n yield { type: \"tool_use\", name: b.name, input: b.input, stage: opts.stage };\n\n const decision = await permissions.check(b.name, b.input);\n if (decision.behavior === \"deny\") {\n yield { type: \"permission_denied\", name: b.name, message: decision.message, stage: opts.stage };\n toolResults.push({\n type: \"tool_result\",\n toolUseId: b.id,\n content: `Permission denied: ${decision.message}`,\n isError: true,\n });\n continue;\n }\n\n const input = decision.updatedInput ?? b.input;\n const result = await registry.execute(b.name, input, toolContext);\n yield {\n type: \"tool_result\",\n name: b.name,\n content: result.content,\n isError: !!result.isError,\n stage: opts.stage,\n };\n toolResults.push({\n type: \"tool_result\",\n toolUseId: b.id,\n content: result.content,\n isError: result.isError,\n });\n }\n\n messages.push({ role: \"user\", content: toolResults });\n }\n\n return { finalText: finalText || \"[max turns reached]\", turns, messages };\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { loadStageContext } from \"./context.ts\";\nimport { runLoop } from \"./loop.ts\";\nimport { PermissionEngine, type PermissionConfig } from \"./permissions.ts\";\nimport { builtinTools } from \"./builtins.ts\";\nimport { loadStages, type StageContract } from \"./subagents.ts\";\nimport { ToolRegistry } from \"./tools.ts\";\nimport type { AgentEvent, Message, ModelProvider, SdkMcpServer } from \"./types.ts\";\n\n// The ICM pipeline runner: walk numbered stages in order, give each stage only the\n// context its contract names, run the agent loop, write the named artifact to the\n// stage's output/ (the handoff point), then pause at a human review gate.\n\nexport interface PipelineOptions {\n workspaceDir: string;\n provider: ModelProvider;\n mcpServers?: SdkMcpServer[];\n /** Global permission overlay. A stage's own \"## Tools\" list is the primary allowlist. */\n permissions?: Pick<PermissionConfig, \"canUseTool\" | \"disallowedTools\">;\n /** Called after each stage writes output. Return false to halt the pipeline. */\n reviewGate?: (\n stage: StageContract,\n outputs: { artifact: string; path: string; text: string }[],\n ) => Promise<boolean> | boolean;\n maxTurnsPerStage?: number;\n contextBudgetTokens?: number; // ICM target ceiling, default 8000\n}\n\nexport async function* runPipeline(opts: PipelineOptions): AsyncGenerator<AgentEvent, void> {\n const registry = new ToolRegistry().addBuiltins(builtinTools);\n for (const s of opts.mcpServers ?? []) registry.addServer(s);\n\n const budget = opts.contextBudgetTokens ?? 8000;\n const stages = await loadStages(opts.workspaceDir);\n\n for (const stage of stages) {\n yield { type: \"stage_start\", stage: stage.name };\n\n // ── Layered context (ICM Layers 0–4, scoped to the contract) ──\n const ctx = await loadStageContext(opts.workspaceDir, stage);\n yield { type: \"context_loaded\", stage: stage.name, tokensEstimated: ctx.tokensEstimated, files: ctx.files };\n if (ctx.tokensEstimated > budget) {\n yield {\n type: \"assistant_text\",\n stage: stage.name,\n text: `⚠ context ~${ctx.tokensEstimated} tok exceeds budget ${budget} — trim this stage's Inputs (ICM principle 3).`,\n };\n }\n\n // ── The contract's \"## Tools\" list is the source of truth for availability ──\n const perm = new PermissionEngine({\n allowedTools: stage.tools, // [] ⇒ a pure prose transform, no tools offered\n disallowedTools: opts.permissions?.disallowedTools,\n canUseTool: opts.permissions?.canUseTool,\n });\n const toolFilter = (n: string) =>\n stage.tools.some((p) => (p.endsWith(\"*\") ? n.startsWith(p.slice(0, -1)) : p === n));\n\n const userPrompt =\n `Execute this stage.\\n\\n## Process\\n${stage.process}\\n\\n` +\n `Produce: ${stage.outputs.join(\", \") || \"a single markdown artifact\"}.`;\n const messages: Message[] = [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }] }];\n\n const result = yield* runLoop({\n provider: opts.provider,\n registry,\n permissions: perm,\n system: ctx.system,\n messages,\n toolFilter,\n toolContext: { workspaceDir: opts.workspaceDir, stageDir: stage.stageDir },\n maxTurns: opts.maxTurnsPerStage,\n stage: stage.name,\n });\n\n // ── Persist the deliverable to output/ per the Outputs contract (the handoff) ──\n const outDir = join(stage.stageDir, \"output\");\n await mkdir(outDir, { recursive: true });\n const primary = stage.outputs[0] ?? \"output.md\";\n const path = join(outDir, primary);\n await writeFile(path, result.finalText + \"\\n\", \"utf8\");\n yield { type: \"stage_output\", stage: stage.name, artifact: primary, path };\n yield { type: \"result\", stage: stage.name, finalText: result.finalText, turns: result.turns };\n\n // ── Review gate: every stage boundary is an edit surface (ICM principle 4) ──\n const proceed = opts.reviewGate\n ? await opts.reviewGate(stage, [{ artifact: primary, path, text: result.finalText }])\n : true;\n if (!proceed) return;\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { StageContract } from \"./subagents.ts\";\n\n// ICM principle 3 — \"layered context loading\": assemble the system prompt from\n// exactly the layers a stage names, nothing more. The control point is the\n// contract's Inputs list; this loader never loads \"everything just in case\".\n\nexport interface LoadedContext {\n system: string;\n files: string[];\n tokensEstimated: number;\n}\n\nconst estimateTokens = (s: string) => Math.ceil(s.length / 4); // ~4 chars/token heuristic\n\nasync function readIfExists(path: string): Promise<string | null> {\n if (!existsSync(path)) return null;\n return readFile(path, \"utf8\");\n}\n\nfunction relativeName(root: string, path: string): string {\n return path.replace(root, \"\").replace(/^[\\\\/]/, \"\").replace(/\\\\/g, \"/\");\n}\n\n/**\n * Build a stage's system prompt from the ICM layer hierarchy:\n * Layer 0 AGENT.md (identity + map)\n * Layer 1 CONTEXT.md (routing)\n * Layer 2 stage CONTEXT.md (this stage's contract)\n * Layer 3 scoped references (constraints — only files the contract names)\n * Layer 4 scoped working (prior stage output — only files the contract names)\n */\nexport async function loadStageContext(\n workspaceDir: string,\n contract: StageContract,\n): Promise<LoadedContext> {\n const parts: string[] = [];\n const files: string[] = [];\n\n const push = async (label: string, path: string) => {\n const text = await readIfExists(path);\n if (text == null) return;\n const src = relativeName(workspaceDir, path);\n parts.push(`<context layer=\"${label}\" src=\"${src}\">\\n${text.trim()}\\n</context>`);\n files.push(src);\n };\n\n await push(\"0 identity\", join(workspaceDir, \"AGENT.md\"));\n await push(\"1 routing\", join(workspaceDir, \"CONTEXT.md\"));\n await push(\"2 contract\", contract.contractPath);\n\n for (const input of contract.inputs) {\n const abs = join(contract.stageDir, input.path);\n await push(input.layer === 3 ? \"3 reference\" : \"4 working\", abs);\n }\n\n const system = parts.join(\"\\n\\n\");\n return { system, files, tokensEstimated: estimateTokens(system) };\n}\n","import { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport { tool } from \"./tools.ts\";\nimport type { ToolDefinition } from \"./types.ts\";\n\n// Confine all built-in file access to the workspace directory (defence in depth;\n// the permission layer is the primary gate).\nfunction safeResolve(workspaceDir: string, p: string): string {\n const root = resolve(workspaceDir);\n const full = resolve(root, p);\n const rel = relative(root, full);\n if (rel.startsWith(\"..\") || resolve(root, rel) !== full) {\n throw new Error(`Path escapes workspace: ${p}`);\n }\n return full;\n}\n\nexport const readFileTool: ToolDefinition = tool(\n \"read_file\",\n \"Read a UTF-8 text file relative to the workspace root.\",\n { type: \"object\", properties: { path: { type: \"string\" } }, required: [\"path\"] },\n async (input: { path: string }, ctx) => {\n const full = safeResolve(ctx.workspaceDir, input.path);\n return { content: await readFile(full, \"utf8\") };\n },\n);\n\nexport const writeFileTool: ToolDefinition = tool(\n \"write_file\",\n \"Write a UTF-8 text file relative to the workspace root (creates parent dirs).\",\n {\n type: \"object\",\n properties: { path: { type: \"string\" }, content: { type: \"string\" } },\n required: [\"path\", \"content\"],\n },\n async (input: { path: string; content: string }, ctx) => {\n const full = safeResolve(ctx.workspaceDir, input.path);\n await mkdir(dirname(full), { recursive: true });\n await writeFile(full, input.content, \"utf8\");\n return { content: `Wrote ${input.content.length} chars to ${input.path}` };\n },\n);\n\nexport const listDirTool: ToolDefinition = tool(\n \"list_dir\",\n \"List entries of a directory relative to the workspace root.\",\n { type: \"object\", properties: { path: { type: \"string\" } }, required: [\"path\"] },\n async (input: { path: string }, ctx) => {\n const full = safeResolve(ctx.workspaceDir, input.path);\n const entries = await readdir(full, { withFileTypes: true });\n return { content: entries.map((e) => (e.isDirectory() ? e.name + \"/\" : e.name)).join(\"\\n\") };\n },\n);\n\nexport const builtinTools: ToolDefinition[] = [readFileTool, writeFileTool, listDirTool];\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n// A \"subagent\" in this SDK is a stage: a markdown contract (Layer 2 CONTEXT.md)\n// that declares its Inputs / Process / Outputs / Tools. Parsing the contract turns\n// folder structure into agent architecture — the whole ICM premise.\n\nexport interface StageInput {\n layer: 3 | 4; // 3 = reference (constraints), 4 = working (input to process)\n path: string; // relative to the stage dir, exactly as the contract names it\n note?: string;\n}\n\nexport interface StageContract {\n name: string; // \"01_research\"\n order: number;\n stageDir: string;\n contractPath: string;\n inputs: StageInput[];\n process: string;\n outputs: string[]; // artifact filenames, written to the stage's output/\n tools: string[]; // allowlist patterns from the optional \"## Tools\" section\n}\n\n/** Pull the body of a \"## <Name>\" markdown section (up to the next \"## \" or EOF). */\nfunction section(body: string, name: string): string {\n const re = new RegExp(`(?:^|\\\\n)##\\\\s+${name}\\\\s*\\\\n([\\\\s\\\\S]*?)(?=\\\\n##\\\\s|$)`, \"i\");\n const m = body.match(re);\n return m ? m[1].trim() : \"\";\n}\n\nexport function parseContract(\n name: string,\n stageDir: string,\n contractPath: string,\n body: string,\n): StageContract {\n const order = parseInt(name.slice(0, 2), 10) || 0;\n\n // Inputs: \"- Layer 3 (reference): ../../_config/voice.md # optional note\"\n const inputs: StageInput[] = [];\n for (const line of section(body, \"Inputs\").split(\"\\n\")) {\n const m = line.match(/Layer\\s+([34])\\b.*?:\\s*([^\\s#]+)\\s*(?:#\\s*(.*))?$/i);\n if (m) inputs.push({ layer: Number(m[1]) as 3 | 4, path: m[2], note: m[3]?.trim() });\n }\n\n // Outputs: \"- research-output.md -> output/\"\n const outputs: string[] = [];\n for (const line of section(body, \"Outputs\").split(\"\\n\")) {\n const m = line.match(/-\\s*([A-Za-z0-9._-]+\\.(?:md|json|txt))/);\n if (m) outputs.push(m[1]);\n }\n\n // Tools (optional): the stage declares exactly which tools it may use.\n const toolsRaw = section(body, \"Tools\");\n const tools = toolsRaw\n ? toolsRaw\n .split(/[\\n,]/)\n .map((s) => s.replace(/^[-*]\\s*/, \"\").trim())\n .filter(Boolean)\n : [];\n\n return {\n name,\n order,\n stageDir,\n contractPath,\n inputs,\n process: section(body, \"Process\"),\n outputs,\n tools,\n };\n}\n\n/** Discover and parse every numbered stage folder, in execution order. */\nexport async function loadStages(workspaceDir: string): Promise<StageContract[]> {\n const stagesRoot = join(workspaceDir, \"stages\");\n const entries = await readdir(stagesRoot, { withFileTypes: true });\n const dirs = entries\n .filter((e) => e.isDirectory() && /^\\d{2}_/.test(e.name))\n .map((e) => e.name)\n .sort();\n\n const contracts: StageContract[] = [];\n for (const name of dirs) {\n const stageDir = join(stagesRoot, name);\n const contractPath = join(stageDir, \"CONTEXT.md\");\n const body = await readFile(contractPath, \"utf8\");\n contracts.push(parseContract(name, stageDir, contractPath, body));\n }\n return contracts;\n}\n","import type {\n ModelProvider,\n ModelRequest,\n ModelResponse,\n ToolSchema,\n} from \"../types.ts\";\n\nexport interface MockOptions {\n /** Label stamped into outputs so mock-generated content is unmistakable. */\n label?: string;\n}\n\n/**\n * A deterministic, offline provider that exercises the full agent loop with no API\n * key. Strategy: if tools are offered and none have been used yet, call the first\n * tool once; otherwise synthesize a final answer from the system context + any tool\n * results. It is intentionally dumb — its job is to prove the harness wiring, not to\n * write good prose. Swap in AnthropicProvider for real output.\n */\nexport class MockProvider implements ModelProvider {\n readonly name = \"mock\";\n private opts: MockOptions;\n constructor(opts: MockOptions = {}) {\n this.opts = opts;\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n const alreadyUsedTool = req.messages.some((m) =>\n m.content.some((b) => b.type === \"tool_use\"),\n );\n if (req.tools.length > 0 && !alreadyUsedTool) {\n const t = req.tools[0];\n return {\n stopReason: \"tool_use\",\n content: [{ type: \"tool_use\", id: \"\", name: t.name, input: this.sampleInput(t) }],\n };\n }\n return { stopReason: \"end_turn\", content: [{ type: \"text\", text: this.synthesize(req) }] };\n }\n\n private sampleInput(t: ToolSchema): Record<string, unknown> {\n const props = (t.inputSchema.properties ?? {}) as Record<string, { type?: string }>;\n const topic = \"the requested topic\";\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(props)) {\n out[k] =\n v.type === \"number\"\n ? 3\n : v.type === \"boolean\"\n ? true\n : k === \"path\"\n ? \"shared/notes.md\"\n : topic;\n }\n return out;\n }\n\n private synthesize(req: ModelRequest): string {\n const toolData = req.messages\n .flatMap((m) => m.content)\n .filter((b) => b.type === \"tool_result\")\n .map((b) => (b as { content: string }).content)\n .join(\"\\n\");\n\n const contract = extractLayer(req.system, \"2 contract\");\n const label = this.opts.label ? ` ${this.opts.label}` : \"\";\n\n const lines = [\n `<!-- mock model output${label} -->`,\n \"\",\n \"## Result\",\n \"\",\n \"Produced by the Torus MockProvider — proof that layered context →\",\n \"agent loop → output handoff works end to end. Replace with AnthropicProvider\",\n \"for real generation.\",\n ];\n if (toolData) {\n lines.push(\"\", \"### Tool-sourced material\", \"\", \"```\", toolData.slice(0, 600), \"```\");\n }\n if (contract) {\n lines.push(\"\", \"### Stage focus (read from the Layer 2 contract)\", \"\", firstLines(contract, 6));\n }\n return lines.join(\"\\n\");\n }\n}\n\nfunction extractLayer(system: string, layer: string): string {\n const m = system.match(new RegExp(`<context layer=\"${layer}\"[^>]*>([\\\\s\\\\S]*?)</context>`));\n return m ? m[1].trim() : \"\";\n}\nfunction firstLines(s: string, n: number): string {\n return s.split(\"\\n\").slice(0, n).join(\"\\n\");\n}\n","// ─────────────────────────────────────────────────────────────────────────\n// Intelligent LLM router — picks CHEAP vs EXPENSIVE per query to cut API cost.\n//\n// Hybrid strategy (provider-agnostic):\n// 1. Fast heuristics (no API call) for the obvious cases.\n// 2. Otherwise a structured \"judge\" call to the CHEAP model that classifies\n// the query as SIMPLE | COMPLEX.\n// SIMPLE → cheap model, COMPLEX → expensive model.\n//\n// The same mechanism is provided for two provider families:\n// - Anthropic: selectModel() (Claude Haiku judge → Haiku / Sonnet)\n// - Gemini: selectGeminiModel() (Gemini Flash-Lite judge → Flash-Lite / Pro)\n//\n// Safety: the select* functions never throw — on any failure they default to\n// the EXPENSIVE model so the user experience never breaks.\n// ─────────────────────────────────────────────────────────────────────────\n\nimport type { Message } from \"./types.ts\";\n\n// ── Target models ──────────────────────────────────────────────────────────\n// Change these in one place per provider.\nexport const CHEAP_MODEL = \"claude-haiku-4-5\"; // $1 / $5 per MTok\nexport const EXPENSIVE_MODEL = \"claude-sonnet-4-6\"; // current default — $3 / $15 per MTok\n\n// Gemini defaults to the stable 2.5 family. Swap to newer IDs (e.g.\n// \"gemini-3.1-flash-lite\" / \"gemini-3.1-pro-preview\") if your key has access.\nexport const GEMINI_CHEAP_MODEL = \"gemini-2.5-flash-lite\";\nexport const GEMINI_EXPENSIVE_MODEL = \"gemini-2.5-pro\";\n\nexport type Complexity = \"SIMPLE\" | \"COMPLEX\";\n\nexport interface RouterOptions {\n /** Reuse an existing provider SDK client (avoids a second client init). */\n client?: any;\n /** API key for a lazily-created client (defaults to the provider's env var). */\n apiKey?: string;\n /** Model used as the complexity judge. Defaults to the provider's cheap model. */\n judgeModel?: string;\n}\n\n// ── 1. Fast heuristics (no API call, provider-agnostic) ─────────────────────\n\nconst SIMPLE_KEYWORDS = [\n \"hello\", \"hi \", \"hey\", \"thanks\", \"thank you\", \"yes\", \"no\",\n \"format\", \"json\", \"yaml\", \"uppercase\", \"lowercase\", \"capitalize\",\n \"translate\", \"spell\", \"reverse\", \"echo\", \"greeting\",\n];\n\nconst estimateTokens = (s: string) => Math.ceil(s.length / 4); // ~4 chars/token\n\n/**\n * Cheap, deterministic pre-classification. Returns a verdict only when it's\n * confident; otherwise null (defer to the judge).\n */\nexport function fastHeuristic(prompt: string): Complexity | null {\n const tokens = estimateTokens(prompt);\n const lower = prompt.toLowerCase();\n\n // Short prompt that mentions a trivial operation → SIMPLE, route immediately.\n if (tokens <= 30 && SIMPLE_KEYWORDS.some((k) => lower.includes(k))) return \"SIMPLE\";\n\n // Very long prompts are almost always real work → skip the judge call.\n if (tokens >= 400) return \"COMPLEX\";\n\n return null;\n}\n\n// ── 2. LLM judges (structured output on each provider's cheap model) ─────────\n\nconst JUDGE_SYSTEM =\n \"You are a routing classifier. Decide whether a user query needs a powerful \" +\n \"model or can be handled by a small, fast one. Classify as SIMPLE (greetings, \" +\n \"formatting, short factual lookups, simple rewrites, single-step tasks) or \" +\n \"COMPLEX (multi-step reasoning, coding, analysis, planning, nuanced judgment). \" +\n 'Respond ONLY with the required JSON: {\"complexity\": \"SIMPLE\" | \"COMPLEX\"}.';\n\nconst COMPLEXITY_SCHEMA = {\n type: \"object\",\n properties: { complexity: { type: \"string\", enum: [\"SIMPLE\", \"COMPLEX\"] } },\n required: [\"complexity\"],\n additionalProperties: false,\n};\n\n/** Robustly extract SIMPLE/COMPLEX from a judge response. Throws if neither. */\nfunction parseComplexity(text: string): Complexity {\n try {\n const parsed = JSON.parse(text) as { complexity?: string };\n if (parsed.complexity === \"SIMPLE\" || parsed.complexity === \"COMPLEX\") return parsed.complexity;\n } catch {\n // fall through to text scan\n }\n const m = text.toUpperCase().match(/\\b(SIMPLE|COMPLEX)\\b/);\n if (m) return m[1] as Complexity;\n throw new Error(`judge returned unparseable complexity: ${text.slice(0, 80)}`);\n}\n\n// -- Anthropic judge --\nlet sharedAnthropic: any;\nasync function getAnthropic(opts: RouterOptions): Promise<any> {\n if (opts.client) return opts.client;\n if (sharedAnthropic) return sharedAnthropic;\n const mod = await import(\"@anthropic-ai/sdk\").catch(() => {\n throw new Error(\"Anthropic judge needs @anthropic-ai/sdk (npm i @anthropic-ai/sdk).\");\n });\n const Anthropic = (mod as any).default ?? (mod as any).Anthropic;\n sharedAnthropic = new Anthropic({ apiKey: opts.apiKey ?? process.env.ANTHROPIC_API_KEY });\n return sharedAnthropic;\n}\n\n/** Grade complexity with Claude (structured output). May throw. */\nexport async function judgeComplexity(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n const client = await getAnthropic(opts);\n const res = await client.messages.create({\n model: opts.judgeModel ?? CHEAP_MODEL,\n max_tokens: 64,\n system: JUDGE_SYSTEM,\n output_config: { format: { type: \"json_schema\", schema: COMPLEXITY_SCHEMA } },\n messages: [{ role: \"user\", content: prompt }],\n });\n const text: string = res.content.find((b: any) => b.type === \"text\")?.text ?? \"\";\n return parseComplexity(text);\n}\n\n// -- Gemini judge --\nlet sharedGemini: any;\nasync function getGemini(opts: RouterOptions): Promise<any> {\n if (opts.client) return opts.client;\n if (sharedGemini) return sharedGemini;\n const mod = await import(\"@google/genai\").catch(() => {\n throw new Error(\"Gemini judge needs @google/genai (npm i @google/genai).\");\n });\n const GoogleGenAI = (mod as any).GoogleGenAI;\n sharedGemini = new GoogleGenAI({\n apiKey: opts.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY,\n });\n return sharedGemini;\n}\n\n/** Grade complexity with Gemini (JSON structured output). May throw. */\nexport async function judgeComplexityGemini(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n const client = await getGemini(opts);\n const res = await client.models.generateContent({\n model: opts.judgeModel ?? GEMINI_CHEAP_MODEL,\n contents: prompt,\n config: {\n systemInstruction: JUDGE_SYSTEM,\n responseMimeType: \"application/json\",\n responseSchema: {\n type: \"object\",\n properties: { complexity: { type: \"string\", enum: [\"SIMPLE\", \"COMPLEX\"] } },\n required: [\"complexity\"],\n },\n },\n });\n return parseComplexity(res.text ?? \"\");\n}\n\n// ── 3. Classification + routing ─────────────────────────────────────────────\n\ntype Judge = (prompt: string, opts: RouterOptions) => Promise<Complexity>;\n\nasync function classifyWith(prompt: string, judge: Judge, opts: RouterOptions): Promise<Complexity> {\n return fastHeuristic(prompt) ?? judge(prompt, opts);\n}\n\n/** Heuristics first, Claude judge second. May throw. */\nexport function classifyComplexity(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n return classifyWith(prompt, judgeComplexity, opts);\n}\n\n/** Heuristics first, Gemini judge second. May throw. */\nexport function classifyComplexityGemini(prompt: string, opts: RouterOptions = {}): Promise<Complexity> {\n return classifyWith(prompt, judgeComplexityGemini, opts);\n}\n\ninterface RouteConfig {\n cheapModel: string;\n expensiveModel: string;\n judge: Judge;\n}\n\nasync function routeWith(prompt: string, cfg: RouteConfig, opts: RouterOptions): Promise<string> {\n let model = cfg.expensiveModel;\n try {\n const complexity = await classifyWith(prompt, cfg.judge, opts);\n model = complexity === \"SIMPLE\" ? cfg.cheapModel : cfg.expensiveModel;\n } catch (err) {\n console.warn(\n `[router] classification failed — defaulting to expensive model. Reason: ${(err as Error).message}`,\n );\n model = cfg.expensiveModel;\n }\n record(model, model === cfg.cheapModel);\n return model;\n}\n\n/** Pick a Claude model for a prompt. Never throws (falls back to expensive). */\nexport function selectModel(prompt: string, opts: RouterOptions = {}): Promise<string> {\n return routeWith(prompt, { cheapModel: CHEAP_MODEL, expensiveModel: EXPENSIVE_MODEL, judge: judgeComplexity }, opts);\n}\n\n/** Pick a Gemini model for a prompt. Never throws (falls back to expensive). */\nexport function selectGeminiModel(prompt: string, opts: RouterOptions = {}): Promise<string> {\n return routeWith(\n prompt,\n { cheapModel: GEMINI_CHEAP_MODEL, expensiveModel: GEMINI_EXPENSIVE_MODEL, judge: judgeComplexityGemini },\n opts,\n );\n}\n\n// ── 4. Observability ─────────────────────────────────────────────────────────\n\nlet cheapCount = 0;\nlet expensiveCount = 0;\n\nfunction record(model: string, isCheap: boolean): void {\n if (isCheap) cheapCount++;\n else expensiveCount++;\n const total = cheapCount + expensiveCount;\n const pct = (n: number) => ((n / total) * 100).toFixed(0);\n console.log(\n `[router] → ${isCheap ? \"CHEAP\" : \"EXPENSIVE\"} (${model}) | cheap ${pct(cheapCount)}% / expensive ${pct(expensiveCount)}% (n=${total})`,\n );\n}\n\nexport interface RoutingStats {\n cheap: number;\n expensive: number;\n total: number;\n cheapPct: number;\n expensivePct: number;\n}\n\nexport function getRoutingStats(): RoutingStats {\n const total = cheapCount + expensiveCount;\n return {\n cheap: cheapCount,\n expensive: expensiveCount,\n total,\n cheapPct: total ? (cheapCount / total) * 100 : 0,\n expensivePct: total ? (expensiveCount / total) * 100 : 0,\n };\n}\n\n// ── Shared message util ──────────────────────────────────────────────────────\n\n/** Extract the most recent user turn's text — what the router classifies on. */\nexport function latestUserText(messages: Message[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n const m = messages[i];\n if (m.role !== \"user\") continue;\n const text = m.content\n .filter((b): b is Extract<typeof b, { type: \"text\" }> => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\\n\")\n .trim();\n if (text) return text;\n }\n return \"\";\n}\n","import { latestUserText, selectModel } from \"../router.ts\";\nimport type {\n ContentBlock,\n Message,\n ModelProvider,\n ModelRequest,\n ModelResponse,\n} from \"../types.ts\";\n\nexport interface AnthropicOptions {\n model?: string;\n apiKey?: string;\n maxTokens?: number;\n /**\n * When true, the model is chosen per-request by the cost router (cheap vs\n * expensive) based on query complexity, instead of using a fixed `model`.\n */\n route?: boolean;\n}\n\n/**\n * Real provider backed by the Anthropic Messages API. Requires the optional\n * `@anthropic-ai/sdk` dependency and an ANTHROPIC_API_KEY. The SDK is imported\n * lazily so the package (and the mock demo) work without it installed.\n */\nexport class AnthropicProvider implements ModelProvider {\n readonly name = \"anthropic\";\n private client: any;\n private model: string;\n private maxTokens: number;\n private apiKey?: string;\n private route: boolean;\n\n constructor(opts: AnthropicOptions = {}) {\n this.model = opts.model ?? \"claude-sonnet-4-6\";\n this.maxTokens = opts.maxTokens ?? 2048;\n this.apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;\n this.route = opts.route ?? false;\n }\n\n private async ensureClient(): Promise<void> {\n if (this.client) return;\n const mod = await import(\"@anthropic-ai/sdk\").catch(() => {\n throw new Error(\n \"AnthropicProvider needs the @anthropic-ai/sdk package: run `npm i @anthropic-ai/sdk`.\",\n );\n });\n const Anthropic = (mod as any).default ?? (mod as any).Anthropic;\n this.client = new Anthropic({ apiKey: this.apiKey });\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n await this.ensureClient();\n\n // Cost routing: pick cheap vs expensive per request from the latest user\n // turn. selectModel never throws — it falls back to the expensive model.\n const model = this.route\n ? await selectModel(latestUserText(req.messages), {\n client: this.client,\n apiKey: this.apiKey,\n })\n : this.model;\n\n const res = await this.client.messages.create({\n model,\n max_tokens: this.maxTokens,\n system: req.system,\n tools: req.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema,\n })),\n messages: req.messages.map(toApiMessage),\n });\n\n const content: ContentBlock[] = res.content.map((b: any): ContentBlock => {\n if (b.type === \"tool_use\") return { type: \"tool_use\", id: b.id, name: b.name, input: b.input };\n return { type: \"text\", text: b.type === \"text\" ? b.text : \"\" };\n });\n const stopReason = res.stop_reason === \"tool_use\" ? \"tool_use\" : \"end_turn\";\n return { content, stopReason };\n }\n}\n\nfunction toApiMessage(m: Message): any {\n return {\n role: m.role,\n content: m.content.flatMap((b): any[] => {\n if (b.type === \"text\") return [{ type: \"text\", text: b.text }];\n if (b.type === \"tool_use\") return [{ type: \"tool_use\", id: b.id, name: b.name, input: b.input }];\n if (b.type === \"tool_result\") {\n return [{ type: \"tool_result\", tool_use_id: b.toolUseId, content: b.content, is_error: b.isError }];\n }\n if (b.type === \"image\") {\n const source = b.data\n ? { type: \"base64\", media_type: b.mimeType ?? \"image/png\", data: b.data }\n : { type: \"url\", url: b.url };\n return [{ type: \"image\", source }];\n }\n return []; // video unsupported on Anthropic — drop the block\n }),\n };\n}\n","import { latestUserText, selectGeminiModel } from \"../router.ts\";\nimport type {\n ContentBlock,\n Message,\n ModelProvider,\n ModelRequest,\n ModelResponse,\n} from \"../types.ts\";\n\nexport interface GeminiOptions {\n model?: string;\n apiKey?: string;\n /**\n * When true, the model is chosen per-request by the cost router (cheap vs\n * expensive Gemini) based on query complexity, instead of a fixed `model`.\n */\n route?: boolean;\n}\n\n/**\n * Provider backed by the Google Gemini API (@google/genai). Requires the\n * optional `@google/genai` dependency and a GOOGLE_API_KEY (or GEMINI_API_KEY).\n * The SDK is imported lazily so the package works without it installed.\n */\nexport class GeminiProvider implements ModelProvider {\n readonly name = \"gemini\";\n private client: any;\n private model: string;\n private apiKey?: string;\n private route: boolean;\n\n constructor(opts: GeminiOptions = {}) {\n this.model = opts.model ?? \"gemini-2.5-flash\";\n this.apiKey = opts.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;\n this.route = opts.route ?? false;\n }\n\n private async ensureClient(): Promise<void> {\n if (this.client) return;\n const mod = await import(\"@google/genai\").catch(() => {\n throw new Error(\"GeminiProvider needs the @google/genai package: run `npm i @google/genai`.\");\n });\n const GoogleGenAI = (mod as any).GoogleGenAI;\n this.client = new GoogleGenAI({ apiKey: this.apiKey });\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n await this.ensureClient();\n\n const model = this.route\n ? await selectGeminiModel(latestUserText(req.messages), {\n client: this.client,\n apiKey: this.apiKey,\n })\n : this.model;\n\n const idToName = toolUseNames(req.messages);\n\n const config: any = {};\n if (req.system) config.systemInstruction = req.system;\n if (req.tools.length) {\n config.tools = [\n {\n functionDeclarations: req.tools.map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema,\n })),\n },\n ];\n }\n\n const res = await this.client.models.generateContent({\n model,\n contents: req.messages.map((m) => toGeminiContent(m, idToName)),\n config,\n });\n\n const content: ContentBlock[] = [];\n const text: string | undefined = res.text;\n if (text && text.trim()) content.push({ type: \"text\", text });\n\n const calls: any[] = res.functionCalls ?? [];\n for (const fc of calls) {\n content.push({ type: \"tool_use\", id: fc.id ?? \"\", name: fc.name, input: fc.args ?? {} });\n }\n if (content.length === 0) content.push({ type: \"text\", text: \"\" });\n\n return { content, stopReason: calls.length ? \"tool_use\" : \"end_turn\" };\n }\n}\n\n/** Map tool_use id -> tool name (Gemini matches function responses by name). */\nfunction toolUseNames(messages: Message[]): Map<string, string> {\n const map = new Map<string, string>();\n for (const m of messages) {\n for (const b of m.content) {\n if (b.type === \"tool_use\") map.set(b.id, b.name);\n }\n }\n return map;\n}\n\n/** Translate one of our Messages into a Gemini `Content` (role + parts). */\nfunction toGeminiContent(m: Message, idToName: Map<string, string>): any {\n const role = m.role === \"assistant\" ? \"model\" : \"user\";\n const parts = m.content.map((b): any => {\n switch (b.type) {\n case \"text\":\n return { text: b.text };\n case \"image\":\n case \"video\":\n // base64 -> inlineData; remote URL -> fileData\n return b.data\n ? { inlineData: { mimeType: b.mimeType ?? \"image/png\", data: b.data } }\n : { fileData: { mimeType: b.mimeType ?? \"image/png\", fileUri: b.url ?? \"\" } };\n case \"tool_use\":\n return { functionCall: { id: b.id, name: b.name, args: b.input } };\n case \"tool_result\":\n return {\n functionResponse: {\n id: b.toolUseId,\n name: idToName.get(b.toolUseId) ?? b.toolUseId,\n response: b.isError ? { error: b.content } : { result: b.content },\n },\n };\n }\n });\n return { role, parts };\n}\n","import type {\n ContentBlock,\n MediaBlock,\n ModelProvider,\n ModelRequest,\n ModelResponse,\n} from \"../types.ts\";\n\n// NVIDIA NIM exposes an OpenAI-compatible Chat Completions API, so this provider\n// talks to it with plain `fetch` — no extra SDK dependency. Free hosted endpoints\n// (e.g. Kimi K2.6, DeepSeek V4) are the SDK's default models via the cascade.\n\nexport const NVIDIA_BASE_URL = \"https://integrate.api.nvidia.com/v1\";\n\n// Exact IDs confirmed against GET /v1/models.\nexport const KIMI_K2_6 = \"moonshotai/kimi-k2.6\"; // 256K ctx, tools, agentic — text-only on NIM (verified)\nexport const DEEPSEEK_V4_PRO = \"deepseek-ai/deepseek-v4-pro\"; // 1M ctx, tools, text-only\nexport const DEEPSEEK_V4_FLASH = \"deepseek-ai/deepseek-v4-flash\"; // faster/cheaper, text-only\nexport const LLAMA_VISION = \"meta/llama-3.2-90b-vision-instruct\"; // free NVIDIA vision model (image), verified\n\nexport interface NvidiaOptions {\n model?: string;\n apiKey?: string;\n baseURL?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport class NvidiaProvider implements ModelProvider {\n readonly name = \"nvidia\";\n private model: string;\n private apiKey?: string;\n private baseURL: string;\n private maxTokens: number;\n private temperature: number;\n\n constructor(opts: NvidiaOptions = {}) {\n this.model = opts.model ?? KIMI_K2_6;\n this.apiKey = opts.apiKey ?? process.env.NVIDIA_API_KEY;\n this.baseURL = opts.baseURL ?? NVIDIA_BASE_URL;\n this.maxTokens = opts.maxTokens ?? 2048;\n this.temperature = opts.temperature ?? 0.2; // low default for deterministic agent behavior\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n if (!this.apiKey) throw new Error(\"NvidiaProvider needs NVIDIA_API_KEY (nvapi-...).\");\n\n const body: Record<string, unknown> = {\n model: this.model,\n messages: toOpenAIMessages(req),\n max_tokens: this.maxTokens,\n temperature: this.temperature,\n };\n if (req.tools.length) {\n body.tools = req.tools.map((t) => ({\n type: \"function\",\n function: { name: t.name, description: t.description, parameters: t.inputSchema },\n }));\n body.tool_choice = \"auto\";\n }\n\n const res = await fetch(`${this.baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n throw new Error(`NVIDIA ${this.model} ${res.status}: ${(await res.text()).slice(0, 300)}`);\n }\n\n const json: any = await res.json();\n const choice = json.choices?.[0];\n const msg = choice?.message ?? {};\n\n const content: ContentBlock[] = [];\n if (typeof msg.content === \"string\" && msg.content.trim()) {\n content.push({ type: \"text\", text: msg.content });\n }\n const toolCalls: any[] = msg.tool_calls ?? [];\n for (const tc of toolCalls) {\n content.push({\n type: \"tool_use\",\n id: tc.id ?? \"\",\n name: tc.function?.name ?? \"\",\n input: safeParse(tc.function?.arguments),\n });\n }\n if (content.length === 0) content.push({ type: \"text\", text: \"\" });\n\n const stopReason =\n choice?.finish_reason === \"tool_calls\" || toolCalls.length ? \"tool_use\" : \"end_turn\";\n return { content, stopReason };\n }\n}\n\nfunction safeParse(args: unknown): Record<string, unknown> {\n if (typeof args !== \"string\") return (args as Record<string, unknown>) ?? {};\n try {\n return JSON.parse(args);\n } catch {\n return {};\n }\n}\n\n/** Map our Messages into OpenAI-style chat messages (tool calls + tool results + media). */\nfunction toOpenAIMessages(req: ModelRequest): any[] {\n const out: any[] = [];\n if (req.system) out.push({ role: \"system\", content: req.system });\n\n for (const m of req.messages) {\n if (m.role === \"user\") {\n // tool_result blocks become individual {role:\"tool\"} messages\n for (const b of m.content) {\n if (b.type === \"tool_result\") {\n out.push({ role: \"tool\", tool_call_id: b.toolUseId, content: b.content });\n }\n }\n const parts = m.content.filter(\n (b) => b.type === \"text\" || b.type === \"image\" || b.type === \"video\",\n );\n if (parts.length) {\n const multimodal = parts.some((b) => b.type !== \"text\");\n out.push({\n role: \"user\",\n content: multimodal\n ? parts.map(toOpenAIPart)\n : parts.map((b) => (b as { text: string }).text).join(\"\\n\"),\n });\n }\n } else {\n // assistant\n const text = m.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n const toolUses = m.content.filter((b) => b.type === \"tool_use\");\n const msg: any = { role: \"assistant\", content: text || null };\n if (toolUses.length) {\n msg.tool_calls = toolUses.map((b: any) => ({\n id: b.id,\n type: \"function\",\n function: { name: b.name, arguments: JSON.stringify(b.input) },\n }));\n }\n out.push(msg);\n }\n }\n return out;\n}\n\nfunction toOpenAIPart(b: ContentBlock): any {\n if (b.type === \"text\") return { type: \"text\", text: b.text };\n const media = b as MediaBlock;\n const url =\n media.url ??\n (media.data ? `data:${media.mimeType ?? \"application/octet-stream\"};base64,${media.data}` : \"\");\n if (media.type === \"video\") return { type: \"video_url\", video_url: { url } }; // experimental\n return { type: \"image_url\", image_url: { url } };\n}\n","import type { ModelProvider, ModelRequest, ModelResponse } from \"../types.ts\";\nimport { DEEPSEEK_V4_PRO, KIMI_K2_6, LLAMA_VISION, NvidiaProvider } from \"./nvidia.ts\";\nimport { GeminiProvider } from \"./gemini.ts\";\n\n// Orchestration: try a prioritized list of (provider, model) steps, falling\n// through to the next on failure (rate limit, error, or capability mismatch).\n// Capability-aware: image requests only go to vision steps; video requests only\n// to video steps — text-only models (Kimi, DeepSeek) are skipped for those.\n\nexport interface CascadeStep {\n provider: ModelProvider;\n label: string; // e.g. \"nvidia:kimi-k2.6\"\n vision: boolean; // accepts image input?\n video?: boolean; // accepts video input? (default false)\n}\n\nexport interface CascadeOptions {\n steps: CascadeStep[];\n /** Called when a step is skipped or fails and the cascade falls through. */\n onFallback?: (info: { from: string; reason: string; needsVision: boolean }) => void;\n}\n\nexport class CascadeProvider implements ModelProvider {\n readonly name = \"cascade\";\n private steps: CascadeStep[];\n private onFallback?: CascadeOptions[\"onFallback\"];\n\n constructor(opts: CascadeOptions) {\n if (!opts.steps.length) throw new Error(\"CascadeProvider needs at least one step.\");\n this.steps = opts.steps;\n this.onFallback = opts.onFallback;\n }\n\n async generate(req: ModelRequest): Promise<ModelResponse> {\n const has = (t: \"image\" | \"video\") =>\n req.messages.some((m) => m.content.some((b) => b.type === t));\n const needsVideo = has(\"video\");\n const needsImage = has(\"image\");\n const needsVision = needsImage || needsVideo;\n\n const eligible = needsVideo\n ? this.steps.filter((s) => s.video)\n : needsImage\n ? this.steps.filter((s) => s.vision)\n : this.steps;\n\n if (!eligible.length) {\n throw new Error(\n `Cascade: request needs ${needsVideo ? \"video\" : \"image\"} input but no step supports it.`,\n );\n }\n\n let lastErr: unknown;\n for (const step of eligible) {\n try {\n return await step.provider.generate(req);\n } catch (err) {\n lastErr = err;\n this.onFallback?.({\n from: step.label,\n reason: (err as Error).message?.slice(0, 200) ?? \"unknown\",\n needsVision,\n });\n }\n }\n throw new Error(`Cascade exhausted all steps. Last error: ${(lastErr as Error)?.message}`);\n }\n}\n\nexport interface DefaultProviderOptions {\n nvidiaApiKey?: string;\n googleApiKey?: string;\n /** Override the main NVIDIA model (default Kimi K2.6). */\n mainModel?: string;\n /** Override the secondary NVIDIA model (default DeepSeek V4 Pro). */\n secondaryModel?: string;\n /** NVIDIA vision model for image requests (default llama-3.2-90b-vision). */\n visionModel?: string;\n /** Gemini model used as the final fallback option (default gemini-2.5-flash). */\n geminiModel?: string;\n onFallback?: CascadeOptions[\"onFallback\"];\n}\n\n/**\n * The SDK's recommended default: free NVIDIA endpoints first, Google as one\n * fallback option. Capability-aware — image/video requests skip the text-only\n * steps automatically.\n *\n * 1. NVIDIA Kimi K2.6 — main; agentic + tools (text)\n * 2. NVIDIA DeepSeek V4 Pro — 1M-ctx text; skipped for media\n * 3. NVIDIA Llama-3.2-90B-Vision — image requests\n * 4. Gemini 2.5 Flash — final fallback; image + video\n */\nexport function createDefaultProvider(opts: DefaultProviderOptions = {}): CascadeProvider {\n const main = opts.mainModel ?? KIMI_K2_6;\n const secondary = opts.secondaryModel ?? DEEPSEEK_V4_PRO;\n const vision = opts.visionModel ?? LLAMA_VISION;\n const gemini = opts.geminiModel ?? \"gemini-2.5-flash\";\n const nv = (model: string) => new NvidiaProvider({ model, apiKey: opts.nvidiaApiKey });\n\n return new CascadeProvider({\n onFallback:\n opts.onFallback ??\n ((info) =>\n console.warn(`[cascade] ${info.from} failed (${info.reason}); trying next`)),\n steps: [\n { provider: nv(main), label: `nvidia:${main}`, vision: false, video: false },\n { provider: nv(secondary), label: `nvidia:${secondary}`, vision: false, video: false },\n { provider: nv(vision), label: `nvidia:${vision}`, vision: true, video: false },\n {\n provider: new GeminiProvider({ model: gemini, apiKey: opts.googleApiKey }),\n label: `gemini:${gemini}`,\n vision: true,\n video: true,\n },\n ],\n });\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { builtinTools } from \"./builtins.ts\";\nimport { runLoop } from \"./loop.ts\";\nimport { matchesAllow, PermissionEngine } from \"./permissions.ts\";\nimport { createCatalogServer, type CatalogItem } from \"./packkit.ts\";\nimport { createDefaultProvider } from \"./providers/cascade.ts\";\nimport { ToolRegistry } from \"./tools.ts\";\nimport type {\n AgentEvent,\n CanUseTool,\n ContentBlock,\n Message,\n ModelProvider,\n SdkMcpServer,\n} from \"./types.ts\";\n\n// Specialize the generic engine to a product by loading a *pack* (an adapter):\n// persona + sales playbook + policy + domain tools + catalog grounding + guardrails.\n// One engine, many packs — don't fork the SDK per vertical.\n\nexport interface PackKnowledge {\n /** Product catalog — auto-wired into a `search_catalog` tool for grounding. */\n catalog?: CatalogItem[];\n /** Short reference text (policies, FAQs) appended to the system prompt. */\n faqs?: string;\n}\n\nexport interface PackGuardrails {\n /** Allowlist of tool names the agent may call (namespaced, wildcards ok). */\n allowedTools?: string[];\n /** Tools that require explicit confirmation before running (namespaced names). */\n confirm?: string[];\n /** Extra custom gate, evaluated after allow/confirm. */\n canUseTool?: CanUseTool;\n /** Rules text (discount authority, no-overpromise, escalation) added to the prompt. */\n policy?: string;\n}\n\nexport interface AgentPack {\n name: string;\n persona: string; // who it is + voice (system prompt core)\n playbook?: string; // sales stages + goal\n tools?: SdkMcpServer[]; // domain actions (quote, reserve, invoice, handoff, ...)\n knowledge?: PackKnowledge;\n guardrails?: PackGuardrails;\n model?: ModelProvider; // defaults to the free-first cascade\n}\n\nexport interface SpecializeOptions {\n provider?: ModelProvider;\n /** Called when a `confirm` tool wants to run; return true to allow. */\n onConfirm?: (toolName: string, input: Record<string, unknown>) => boolean | Promise<boolean>;\n /** Allow built-in file tools (read/write/list). Off by default for packs. */\n includeBuiltins?: boolean;\n maxTurns?: number;\n}\n\nexport interface SpecializedAgent {\n pack: AgentPack;\n system: string;\n servers: SdkMcpServer[];\n query(prompt: string | ContentBlock[], extra?: { maxTurns?: number }): AsyncGenerator<AgentEvent>;\n}\n\n/** Build a ready-to-run specialized agent from a pack. */\nexport function createSpecializedAgent(pack: AgentPack, opts: SpecializeOptions = {}): SpecializedAgent {\n // Assemble the system prompt from persona + playbook + policy + grounding + faqs.\n const servers: SdkMcpServer[] = [...(pack.tools ?? [])];\n if (pack.knowledge?.catalog?.length) servers.unshift(createCatalogServer(pack.knowledge.catalog));\n\n const parts = [pack.persona.trim()];\n if (pack.playbook) parts.push(`## Playbook\\n${pack.playbook.trim()}`);\n if (pack.guardrails?.policy) parts.push(`## Policy\\n${pack.guardrails.policy.trim()}`);\n if (servers.some((s) => s.tools.some((t) => t.name === \"search_catalog\"))) {\n parts.push(\n \"Use the `search_catalog` tool for every product, price, or availability question. Never invent a price or claim availability you did not look up.\",\n );\n }\n if (pack.knowledge?.faqs) parts.push(`## Reference\\n${pack.knowledge.faqs.trim()}`);\n const system = parts.join(\"\\n\\n\");\n\n const confirmTools = pack.guardrails?.confirm ?? [];\n const allow = pack.guardrails?.allowedTools;\n const base = pack.guardrails?.canUseTool;\n\n const canUseTool: CanUseTool = async (name, input) => {\n if (confirmTools.includes(name)) {\n const ok = opts.onConfirm ? await opts.onConfirm(name, input) : false;\n if (!ok) return { behavior: \"deny\", message: `${name} requires confirmation and it was not granted.` };\n }\n if (allow && !matchesAllow(name, allow)) {\n return { behavior: \"deny\", message: `${name} is not allowed by this pack's guardrails.` };\n }\n return base ? base(name, input) : { behavior: \"allow\" };\n };\n\n const provider = opts.provider ?? pack.model ?? createDefaultProvider();\n const includeBuiltins = opts.includeBuiltins ?? false;\n\n return {\n pack,\n system,\n servers,\n async *query(prompt, extra) {\n const registry = new ToolRegistry();\n if (includeBuiltins) registry.addBuiltins(builtinTools);\n for (const s of servers) registry.addServer(s);\n\n const content: ContentBlock[] =\n typeof prompt === \"string\" ? [{ type: \"text\", text: prompt }] : prompt;\n const messages: Message[] = [{ role: \"user\", content }];\n\n const result = yield* runLoop({\n provider,\n registry,\n permissions: new PermissionEngine({ canUseTool }),\n system,\n messages,\n toolContext: { workspaceDir: process.cwd() },\n maxTurns: extra?.maxTurns ?? opts.maxTurns,\n });\n yield { type: \"result\", finalText: result.finalText, turns: result.turns };\n },\n };\n}\n\n/**\n * Load a pack's content from a folder (so non-devs can edit it):\n * persona.md · playbook.md · policy.md · catalog.json · faqs.md\n * Code tools (quote/reserve/invoice/...) are passed via `opts.tools`.\n */\nexport async function loadPack(\n dir: string,\n opts: { tools?: SdkMcpServer[] } = {},\n): Promise<AgentPack> {\n const read = async (f: string): Promise<string | undefined> => {\n const p = join(dir, f);\n return existsSync(p) ? await readFile(p, \"utf8\") : undefined;\n };\n const catalogRaw = await read(\"catalog.json\");\n const policy = await read(\"policy.md\");\n return {\n name: dir.split(/[\\\\/]/).filter(Boolean).pop() ?? \"pack\",\n persona: (await read(\"persona.md\")) ?? \"\",\n playbook: await read(\"playbook.md\"),\n knowledge: {\n catalog: catalogRaw ? (JSON.parse(catalogRaw) as CatalogItem[]) : undefined,\n faqs: await read(\"faqs.md\"),\n },\n guardrails: policy ? { policy } : undefined,\n tools: opts.tools,\n };\n}\n","import { createSdkMcpServer, tool } from \"./tools.ts\";\nimport type { SdkMcpServer } from \"./types.ts\";\n\n// Reusable tool patterns for specializing an agent to a vertical (a \"pack\").\n// Compose these into a pack's `tools`. They are deliberately backend-agnostic —\n// swap the in-memory stubs for real catalog/CRM/payment integrations later.\n\nexport type CatalogItem = Record<string, unknown> & {\n id?: string;\n name?: string;\n price?: number;\n tags?: string[];\n available?: boolean;\n};\n\n/** A `search_catalog` tool over an in-memory product list (text + price + tags). */\nexport function createCatalogServer(\n items: CatalogItem[],\n opts: { serverName?: string } = {},\n): SdkMcpServer {\n const search = tool(\n \"search_catalog\",\n \"Search the product catalog by text, max price, and tags. Returns matching items with prices and availability. Use this for every product/price/availability question — never guess.\",\n {\n type: \"object\",\n properties: {\n query: { type: \"string\" },\n maxPrice: { type: \"number\" },\n tags: { type: \"array\", items: { type: \"string\" } },\n limit: { type: \"number\" },\n },\n },\n (input: { query?: string; maxPrice?: number; tags?: string[]; limit?: number }) => {\n let res = items.filter((it) => it.available !== false);\n if (input.query) {\n const words = input.query.toLowerCase().split(/\\s+/).filter(Boolean);\n res = res.filter((it) => {\n const hay = JSON.stringify(it).toLowerCase();\n return words.every((w) => hay.includes(w));\n });\n }\n if (typeof input.maxPrice === \"number\") {\n res = res.filter((it) => typeof it.price !== \"number\" || it.price <= input.maxPrice!);\n }\n if (Array.isArray(input.tags) && input.tags.length) {\n res = res.filter((it) => Array.isArray(it.tags) && input.tags!.some((t) => it.tags!.includes(t)));\n }\n const out = res.slice(0, input.limit ?? 5);\n return { content: out.length ? JSON.stringify(out, null, 2) : \"No matching items.\" };\n },\n );\n return createSdkMcpServer({ name: opts.serverName ?? \"catalog\", tools: [search] });\n}\n\n/** `get_lead` / `update_lead` over an in-memory customer profile (the funnel state). */\nexport function createLeadMemoryServer(\n initial: Record<string, unknown> = {},\n): SdkMcpServer & { lead: Record<string, unknown> } {\n const lead: Record<string, unknown> = { ...initial };\n const get = tool(\n \"get_lead\",\n \"Get what we know about the current customer (name, date, budget, stage, items seen).\",\n { type: \"object\", properties: {} },\n () => ({ content: JSON.stringify(lead, null, 2) }),\n );\n const update = tool(\n \"update_lead\",\n \"Merge fields into the customer profile, e.g. { budget: 2000, stage: 'recommend' }.\",\n { type: \"object\", properties: { fields: { type: \"object\" } }, required: [\"fields\"] },\n (input: { fields: Record<string, unknown> }) => {\n Object.assign(lead, input.fields ?? {});\n return { content: `updated: ${Object.keys(input.fields ?? {}).join(\", \") || \"(none)\"}` };\n },\n );\n return Object.assign(createSdkMcpServer({ name: \"lead\", tools: [get, update] }), { lead });\n}\n\nexport interface Invoice {\n id: string;\n amount: number;\n currency: string;\n items?: unknown;\n customer?: unknown;\n status: \"pending\";\n}\n\n/**\n * A generic `create_invoice` settle tool: records an order + amount as pending\n * and returns an invoice id. Provider-agnostic — wire your processor via\n * `onCreate` (e.g. create a real payment link, then confirm via webhook).\n */\nexport function createInvoiceServer(\n opts: { onCreate?: (inv: Invoice) => void } = {},\n): SdkMcpServer & { invoices: Invoice[] } {\n const invoices: Invoice[] = [];\n let n = 0;\n const create = tool(\n \"create_invoice\",\n \"Record an order and amount as a pending invoice to settle, returning an invoice id. Call this only after the customer has agreed to buy.\",\n {\n type: \"object\",\n properties: {\n amount: { type: \"number\" },\n currency: { type: \"string\" },\n items: {},\n customer: {},\n },\n required: [\"amount\"],\n },\n (input: { amount: number; currency?: string; items?: unknown; customer?: unknown }) => {\n const inv: Invoice = {\n id: `inv_${++n}`,\n amount: input.amount,\n currency: input.currency ?? \"USD\",\n items: input.items,\n customer: input.customer,\n status: \"pending\",\n };\n invoices.push(inv);\n opts.onCreate?.(inv);\n return {\n content: JSON.stringify({ invoiceId: inv.id, status: inv.status, amount: inv.amount, currency: inv.currency }),\n };\n },\n );\n return Object.assign(createSdkMcpServer({ name: \"billing\", tools: [create] }), { invoices });\n}\n\n/** A `handoff_human` escalation tool. Wire `onHandoff` to notify a real agent. */\nexport function createHandoffServer(\n opts: { onHandoff?: (info: { reason: string; summary: string }) => void } = {},\n): SdkMcpServer {\n const handoff = tool(\n \"handoff_human\",\n \"Escalate to a human agent with a reason and a short summary of the conversation so far. Use when you're stuck, the request is high-value, or the customer asks for a person.\",\n {\n type: \"object\",\n properties: { reason: { type: \"string\" }, summary: { type: \"string\" } },\n required: [\"reason\"],\n },\n (input: { reason: string; summary?: string }) => {\n opts.onHandoff?.({ reason: input.reason, summary: input.summary ?? \"\" });\n return { content: \"Escalated to a human; they will take over shortly.\" };\n },\n );\n return createSdkMcpServer({ name: \"support\", tools: [handoff] });\n}\n","import { createSdkMcpServer, tool } from \"./tools.ts\";\nimport type { SdkMcpServer, ToolDefinition } from \"./types.ts\";\n\n// MCP client: connect to EXTERNAL Model Context Protocol servers (local stdio\n// subprocesses or remote HTTP) and expose their tools to the agent. Each remote\n// tool is wrapped as a normal SdkMcpServer tool, so it flows through the same\n// registry, namespacing (mcp__<server>__<tool>), loop, and permission allowlist\n// as in-process tools. Requires the optional `@modelcontextprotocol/sdk` package.\n\nexport type McpServerConfig =\n | {\n type?: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n }\n | {\n type: \"http\";\n url: string;\n headers?: Record<string, string>;\n };\n\nexport interface McpConnection {\n /** Namespaced server — its tools become mcp__<name>__<tool>. */\n server: SdkMcpServer;\n /** Tear down the MCP client + transport. */\n close(): Promise<void>;\n}\n\nasync function connect(config: McpServerConfig): Promise<any> {\n const clientMod = await import(\"@modelcontextprotocol/sdk/client/index.js\").catch(() => {\n throw new Error(\"MCP client needs @modelcontextprotocol/sdk: run `npm i @modelcontextprotocol/sdk`.\");\n });\n const Client = (clientMod as any).Client;\n\n let transport: any;\n if (config.type === \"http\") {\n const mod = await import(\"@modelcontextprotocol/sdk/client/streamableHttp.js\");\n transport = new (mod as any).StreamableHTTPClientTransport(\n new URL(config.url),\n config.headers ? { requestInit: { headers: config.headers } } : undefined,\n );\n } else {\n const mod = await import(\"@modelcontextprotocol/sdk/client/stdio.js\");\n transport = new (mod as any).StdioClientTransport({\n command: config.command,\n args: config.args ?? [],\n env: { ...process.env, ...(config.env ?? {}) } as Record<string, string>,\n });\n }\n\n const client = new Client({ name: \"torus\", version: \"0.4.0\" }, { capabilities: {} });\n await client.connect(transport);\n return client;\n}\n\n/** Connect to one external MCP server and expose its tools as an SdkMcpServer. */\nexport async function connectMcpServer(name: string, config: McpServerConfig): Promise<McpConnection> {\n const client = await connect(config);\n const listed = await client.listTools();\n\n const tools: ToolDefinition[] = (listed.tools ?? []).map((t: any) =>\n tool(\n t.name,\n t.description ?? \"\",\n (t.inputSchema as Record<string, unknown>) ?? { type: \"object\", properties: {} },\n async (input: Record<string, unknown>) => {\n const res: any = await client.callTool({ name: t.name, arguments: input ?? {} });\n const text =\n (res.content ?? [])\n .filter((c: any) => c?.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\") || JSON.stringify(res.content ?? res);\n return { content: text, isError: !!res.isError };\n },\n ),\n );\n\n return {\n server: createSdkMcpServer({ name, version: \"1.0.0\", tools }),\n close: async () => {\n try {\n await client.close();\n } catch {\n // best-effort teardown\n }\n },\n };\n}\n\n/**\n * Connect to several external MCP servers at once.\n *\n * const { servers, close } = await connectMcpServers({\n * github: { command: \"npx\", args: [\"-y\", \"@modelcontextprotocol/server-github\"], env: { GITHUB_TOKEN } },\n * docs: { type: \"http\", url: \"https://example.com/mcp\" },\n * });\n * for await (const ev of query(\"...\", { mcpServers: servers,\n * permissions: { allowedTools: [\"mcp__github__*\"] } })) { ... }\n * await close();\n */\nexport async function connectMcpServers(\n configs: Record<string, McpServerConfig>,\n): Promise<{ servers: SdkMcpServer[]; close(): Promise<void> }> {\n const conns = await Promise.all(\n Object.entries(configs).map(([name, cfg]) => connectMcpServer(name, cfg)),\n );\n return {\n servers: conns.map((c) => c.server),\n close: async () => {\n await Promise.all(conns.map((c) => c.close()));\n },\n };\n}\n","// Public API for Torus.\n\nexport * from \"./types.ts\";\nexport { tool, createSdkMcpServer, ToolRegistry, type RegisteredTool } from \"./tools.ts\";\nexport { PermissionEngine, matchesAllow, type PermissionConfig } from \"./permissions.ts\";\nexport { runLoop, type LoopOptions, type LoopResult } from \"./loop.ts\";\nexport { runPipeline, type PipelineOptions } from \"./pipeline.ts\";\nexport { builtinTools, readFileTool, writeFileTool, listDirTool } from \"./builtins.ts\";\nexport { loadStages, parseContract, type StageContract, type StageInput } from \"./subagents.ts\";\nexport { loadStageContext, type LoadedContext } from \"./context.ts\";\nexport { MockProvider, type MockOptions } from \"./providers/mock.ts\";\nexport { AnthropicProvider, type AnthropicOptions } from \"./providers/anthropic.ts\";\nexport { GeminiProvider, type GeminiOptions } from \"./providers/gemini.ts\";\nexport {\n NvidiaProvider,\n type NvidiaOptions,\n NVIDIA_BASE_URL,\n KIMI_K2_6,\n DEEPSEEK_V4_PRO,\n DEEPSEEK_V4_FLASH,\n LLAMA_VISION,\n} from \"./providers/nvidia.ts\";\nexport {\n CascadeProvider,\n createDefaultProvider,\n type CascadeStep,\n type CascadeOptions,\n type DefaultProviderOptions,\n} from \"./providers/cascade.ts\";\n\n// Specialization: turn the generic engine into a vertical agent via a \"pack\".\nexport {\n createSpecializedAgent,\n loadPack,\n type AgentPack,\n type PackKnowledge,\n type PackGuardrails,\n type SpecializeOptions,\n type SpecializedAgent,\n} from \"./pack.ts\";\nexport {\n createCatalogServer,\n createLeadMemoryServer,\n createInvoiceServer,\n createHandoffServer,\n type CatalogItem,\n type Invoice,\n} from \"./packkit.ts\";\n\n// MCP host: connect to external Model Context Protocol servers (stdio / HTTP).\nexport {\n connectMcpServer,\n connectMcpServers,\n type McpServerConfig,\n type McpConnection,\n} from \"./mcp-client.ts\";\nexport {\n // Anthropic (Claude) routing\n CHEAP_MODEL,\n EXPENSIVE_MODEL,\n selectModel,\n classifyComplexity,\n judgeComplexity,\n // Gemini routing — same mechanism, Gemini models\n GEMINI_CHEAP_MODEL,\n GEMINI_EXPENSIVE_MODEL,\n selectGeminiModel,\n classifyComplexityGemini,\n judgeComplexityGemini,\n // Shared\n fastHeuristic,\n getRoutingStats,\n latestUserText,\n type Complexity,\n type RouterOptions,\n type RoutingStats,\n} from \"./router.ts\";\n\nimport { builtinTools } from \"./builtins.ts\";\nimport { createDefaultProvider } from \"./providers/cascade.ts\";\nimport { runLoop } from \"./loop.ts\";\nimport { PermissionEngine, type PermissionConfig } from \"./permissions.ts\";\nimport { ToolRegistry } from \"./tools.ts\";\nimport type { AgentEvent, ContentBlock, Message, ModelProvider, SdkMcpServer } from \"./types.ts\";\n\nexport interface QueryOptions {\n /** Defaults to the NVIDIA-first cascade (Kimi K2.6 → DeepSeek V4 → Gemini). */\n provider?: ModelProvider;\n system?: string;\n mcpServers?: SdkMcpServer[];\n includeBuiltins?: boolean; // default true\n permissions?: PermissionConfig;\n workspaceDir?: string;\n maxTurns?: number;\n}\n\n/**\n * Single-shot agent run (no pipeline). Mirrors the Claude Agent SDK's streaming\n * `query()`: yields events as they happen and a final `result` event. The prompt\n * may be a string or an array of content blocks (e.g. text + image for vision).\n *\n * for await (const ev of query(\"Summarize X\", { mcpServers: [srv] })) { ... }\n * for await (const ev of query([{ type: \"text\", text: \"What's this?\" },\n * { type: \"image\", url: \"https://...\" }])) { ... }\n */\nexport async function* query(\n prompt: string | ContentBlock[],\n options: QueryOptions = {},\n): AsyncGenerator<AgentEvent> {\n const registry = new ToolRegistry();\n if (options.includeBuiltins ?? true) registry.addBuiltins(builtinTools);\n for (const s of options.mcpServers ?? []) registry.addServer(s);\n\n const content: ContentBlock[] =\n typeof prompt === \"string\" ? [{ type: \"text\", text: prompt }] : prompt;\n const messages: Message[] = [{ role: \"user\", content }];\n const result = yield* runLoop({\n provider: options.provider ?? createDefaultProvider(),\n registry,\n permissions: new PermissionEngine(options.permissions ?? {}),\n system: options.system ?? \"You are a helpful agent.\",\n messages,\n toolContext: { workspaceDir: options.workspaceDir ?? process.cwd() },\n maxTurns: options.maxTurns,\n });\n yield { type: \"result\", finalText: result.finalText, turns: result.turns };\n}\n"],"mappings":"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","names":["mkdir","writeFile","join","readFile","readFile","readFile","readdir","join","join","mkdir","writeFile","estimateTokens","existsSync","readFile","join","join","existsSync","readFile"]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "torus-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Torus — a minimal, ICM-structured Agent SDK: agent loop, tools, in-process MCP, markdown-contract subagents, multimodal input, and a free-first model cascade (NVIDIA Kimi K2.6 / DeepSeek V4 → Gemini → Claude) with cost routing.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "aenfr",
|
|
8
|
-
"repository": {
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/aenfr/torus-ai.git"
|
|
11
|
+
},
|
|
9
12
|
"homepage": "https://github.com/aenfr/torus-ai#readme",
|
|
10
|
-
"bugs": {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/aenfr/torus-ai/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"agent",
|
|
18
|
+
"sdk",
|
|
19
|
+
"llm",
|
|
20
|
+
"mcp",
|
|
21
|
+
"nvidia",
|
|
22
|
+
"nim",
|
|
23
|
+
"kimi",
|
|
24
|
+
"deepseek",
|
|
25
|
+
"anthropic",
|
|
26
|
+
"claude",
|
|
27
|
+
"gemini",
|
|
28
|
+
"google",
|
|
29
|
+
"multimodal",
|
|
30
|
+
"icm",
|
|
31
|
+
"pipeline",
|
|
32
|
+
"router",
|
|
33
|
+
"cascade"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=22.6"
|
|
37
|
+
},
|
|
13
38
|
"main": "./dist/index.js",
|
|
14
39
|
"module": "./dist/index.js",
|
|
15
40
|
"types": "./dist/index.d.ts",
|
|
@@ -19,8 +44,18 @@
|
|
|
19
44
|
"import": "./dist/index.js"
|
|
20
45
|
}
|
|
21
46
|
},
|
|
22
|
-
"files": [
|
|
23
|
-
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"src",
|
|
50
|
+
"models",
|
|
51
|
+
"AGENT.md",
|
|
52
|
+
"CONTEXT.md",
|
|
53
|
+
"LICENSE",
|
|
54
|
+
"README.md"
|
|
55
|
+
],
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
24
59
|
"scripts": {
|
|
25
60
|
"demo": "node examples/blog-pipeline/run.ts",
|
|
26
61
|
"model-watch": "node scripts/model-watch.ts",
|
|
@@ -35,6 +70,7 @@
|
|
|
35
70
|
},
|
|
36
71
|
"optionalDependencies": {
|
|
37
72
|
"@anthropic-ai/sdk": "^0.32.1",
|
|
38
|
-
"@google/genai": "^2.8.0"
|
|
73
|
+
"@google/genai": "^2.8.0",
|
|
74
|
+
"@modelcontextprotocol/sdk": "1.29.0"
|
|
39
75
|
}
|
|
40
76
|
}
|
package/src/index.ts
CHANGED
|
@@ -46,6 +46,14 @@ export {
|
|
|
46
46
|
type CatalogItem,
|
|
47
47
|
type Invoice,
|
|
48
48
|
} from "./packkit.ts";
|
|
49
|
+
|
|
50
|
+
// MCP host: connect to external Model Context Protocol servers (stdio / HTTP).
|
|
51
|
+
export {
|
|
52
|
+
connectMcpServer,
|
|
53
|
+
connectMcpServers,
|
|
54
|
+
type McpServerConfig,
|
|
55
|
+
type McpConnection,
|
|
56
|
+
} from "./mcp-client.ts";
|
|
49
57
|
export {
|
|
50
58
|
// Anthropic (Claude) routing
|
|
51
59
|
CHEAP_MODEL,
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { createSdkMcpServer, tool } from "./tools.ts";
|
|
2
|
+
import type { SdkMcpServer, ToolDefinition } from "./types.ts";
|
|
3
|
+
|
|
4
|
+
// MCP client: connect to EXTERNAL Model Context Protocol servers (local stdio
|
|
5
|
+
// subprocesses or remote HTTP) and expose their tools to the agent. Each remote
|
|
6
|
+
// tool is wrapped as a normal SdkMcpServer tool, so it flows through the same
|
|
7
|
+
// registry, namespacing (mcp__<server>__<tool>), loop, and permission allowlist
|
|
8
|
+
// as in-process tools. Requires the optional `@modelcontextprotocol/sdk` package.
|
|
9
|
+
|
|
10
|
+
export type McpServerConfig =
|
|
11
|
+
| {
|
|
12
|
+
type?: "stdio";
|
|
13
|
+
command: string;
|
|
14
|
+
args?: string[];
|
|
15
|
+
env?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
type: "http";
|
|
19
|
+
url: string;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export interface McpConnection {
|
|
24
|
+
/** Namespaced server — its tools become mcp__<name>__<tool>. */
|
|
25
|
+
server: SdkMcpServer;
|
|
26
|
+
/** Tear down the MCP client + transport. */
|
|
27
|
+
close(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function connect(config: McpServerConfig): Promise<any> {
|
|
31
|
+
const clientMod = await import("@modelcontextprotocol/sdk/client/index.js").catch(() => {
|
|
32
|
+
throw new Error("MCP client needs @modelcontextprotocol/sdk: run `npm i @modelcontextprotocol/sdk`.");
|
|
33
|
+
});
|
|
34
|
+
const Client = (clientMod as any).Client;
|
|
35
|
+
|
|
36
|
+
let transport: any;
|
|
37
|
+
if (config.type === "http") {
|
|
38
|
+
const mod = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
39
|
+
transport = new (mod as any).StreamableHTTPClientTransport(
|
|
40
|
+
new URL(config.url),
|
|
41
|
+
config.headers ? { requestInit: { headers: config.headers } } : undefined,
|
|
42
|
+
);
|
|
43
|
+
} else {
|
|
44
|
+
const mod = await import("@modelcontextprotocol/sdk/client/stdio.js");
|
|
45
|
+
transport = new (mod as any).StdioClientTransport({
|
|
46
|
+
command: config.command,
|
|
47
|
+
args: config.args ?? [],
|
|
48
|
+
env: { ...process.env, ...(config.env ?? {}) } as Record<string, string>,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const client = new Client({ name: "torus", version: "0.4.0" }, { capabilities: {} });
|
|
53
|
+
await client.connect(transport);
|
|
54
|
+
return client;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Connect to one external MCP server and expose its tools as an SdkMcpServer. */
|
|
58
|
+
export async function connectMcpServer(name: string, config: McpServerConfig): Promise<McpConnection> {
|
|
59
|
+
const client = await connect(config);
|
|
60
|
+
const listed = await client.listTools();
|
|
61
|
+
|
|
62
|
+
const tools: ToolDefinition[] = (listed.tools ?? []).map((t: any) =>
|
|
63
|
+
tool(
|
|
64
|
+
t.name,
|
|
65
|
+
t.description ?? "",
|
|
66
|
+
(t.inputSchema as Record<string, unknown>) ?? { type: "object", properties: {} },
|
|
67
|
+
async (input: Record<string, unknown>) => {
|
|
68
|
+
const res: any = await client.callTool({ name: t.name, arguments: input ?? {} });
|
|
69
|
+
const text =
|
|
70
|
+
(res.content ?? [])
|
|
71
|
+
.filter((c: any) => c?.type === "text")
|
|
72
|
+
.map((c: any) => c.text)
|
|
73
|
+
.join("\n") || JSON.stringify(res.content ?? res);
|
|
74
|
+
return { content: text, isError: !!res.isError };
|
|
75
|
+
},
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
server: createSdkMcpServer({ name, version: "1.0.0", tools }),
|
|
81
|
+
close: async () => {
|
|
82
|
+
try {
|
|
83
|
+
await client.close();
|
|
84
|
+
} catch {
|
|
85
|
+
// best-effort teardown
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Connect to several external MCP servers at once.
|
|
93
|
+
*
|
|
94
|
+
* const { servers, close } = await connectMcpServers({
|
|
95
|
+
* github: { command: "npx", args: ["-y", "@modelcontextprotocol/server-github"], env: { GITHUB_TOKEN } },
|
|
96
|
+
* docs: { type: "http", url: "https://example.com/mcp" },
|
|
97
|
+
* });
|
|
98
|
+
* for await (const ev of query("...", { mcpServers: servers,
|
|
99
|
+
* permissions: { allowedTools: ["mcp__github__*"] } })) { ... }
|
|
100
|
+
* await close();
|
|
101
|
+
*/
|
|
102
|
+
export async function connectMcpServers(
|
|
103
|
+
configs: Record<string, McpServerConfig>,
|
|
104
|
+
): Promise<{ servers: SdkMcpServer[]; close(): Promise<void> }> {
|
|
105
|
+
const conns = await Promise.all(
|
|
106
|
+
Object.entries(configs).map(([name, cfg]) => connectMcpServer(name, cfg)),
|
|
107
|
+
);
|
|
108
|
+
return {
|
|
109
|
+
servers: conns.map((c) => c.server),
|
|
110
|
+
close: async () => {
|
|
111
|
+
await Promise.all(conns.map((c) => c.close()));
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|