torus-ai 0.2.0 → 0.2.1

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 CHANGED
@@ -92,9 +92,10 @@ into `query()`, `runPipeline()`, or `runLoop()` interchangeably:
92
92
  **The default is a free-first cascade.** If you don't pass a provider, `query()`
93
93
  uses `createDefaultProvider()` — it tries each step and falls through on failure:
94
94
 
95
- 1. **NVIDIA Kimi K2.6** — main; agentic + multimodal (image/video), free NIM endpoint
96
- 2. **NVIDIA DeepSeek V4 Pro** — 1M-context text model, free; *skipped for image/video*
97
- 3. **Gemini 2.5 Flash** — final fallback, different provider for resilience
95
+ 1. **NVIDIA Kimi K2.6** — main; agentic + tools (text), free NIM endpoint
96
+ 2. **NVIDIA DeepSeek V4 Pro** — 1M-context text model, free; *skipped for media*
97
+ 3. **NVIDIA Llama-3.2-90B-Vision** — image requests, free
98
+ 4. **Gemini 2.5 Flash** — final fallback (image + video), different provider for resilience
98
99
 
99
100
  ```ts
100
101
  import { query } from "torus-ai"; // NVIDIA_API_KEY in env → cascade default
@@ -104,20 +105,25 @@ import { createDefaultProvider } from "torus-ai";
104
105
  const provider = createDefaultProvider({ mainModel: "moonshotai/kimi-k2.6" });
105
106
  ```
106
107
 
107
- It's **capability-aware**: image/video requests automatically skip text-only steps.
108
+ It's **capability-aware**: image requests skip text-only steps and route to a
109
+ vision model; video requests route only to a video-capable step.
108
110
 
109
- ### Multimodal (image now, video experimental)
111
+ ### Multimodal (image verified, video experimental)
110
112
 
111
- Pass content blocks instead of a string. Images route to a vision-capable step
112
- (Kimi / Gemini / Claude); video is best-effort to Kimi.
113
+ Pass content blocks instead of a string. Images route to a vision step
114
+ (NVIDIA Llama-Vision Gemini); video routes to Gemini.
113
115
 
114
116
  ```ts
115
117
  await query([
116
- { type: "text", text: "What's in this image?" },
117
- { type: "image", url: "https://example.com/cat.png" }, // or { data, mimeType }
118
+ { type: "text", text: "What animal is this?" },
119
+ { type: "image", url: "https://example.com/cat.jpg" }, // or { data: base64, mimeType }
118
120
  ]);
119
121
  ```
120
122
 
123
+ > Note: Kimi K2.6's docs claim vision, but its NIM endpoint is **text-only in
124
+ > practice** (verified) — so the cascade sends images to a real vision model
125
+ > instead. Video is experimental and currently served only by Gemini.
126
+
121
127
  ### Cost routing (per provider)
122
128
 
123
129
  Each model provider also supports `route: true` — fast heuristics, then a
package/dist/index.d.ts CHANGED
@@ -329,6 +329,7 @@ declare const NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1";
329
329
  declare const KIMI_K2_6 = "moonshotai/kimi-k2.6";
330
330
  declare const DEEPSEEK_V4_PRO = "deepseek-ai/deepseek-v4-pro";
331
331
  declare const DEEPSEEK_V4_FLASH = "deepseek-ai/deepseek-v4-flash";
332
+ declare const LLAMA_VISION = "meta/llama-3.2-90b-vision-instruct";
332
333
  interface NvidiaOptions {
333
334
  model?: string;
334
335
  apiKey?: string;
@@ -351,6 +352,7 @@ interface CascadeStep {
351
352
  provider: ModelProvider;
352
353
  label: string;
353
354
  vision: boolean;
355
+ video?: boolean;
354
356
  }
355
357
  interface CascadeOptions {
356
358
  steps: CascadeStep[];
@@ -375,17 +377,21 @@ interface DefaultProviderOptions {
375
377
  mainModel?: string;
376
378
  /** Override the secondary NVIDIA model (default DeepSeek V4 Pro). */
377
379
  secondaryModel?: string;
380
+ /** NVIDIA vision model for image requests (default llama-3.2-90b-vision). */
381
+ visionModel?: string;
378
382
  /** Gemini model used as the final fallback option (default gemini-2.5-flash). */
379
383
  geminiModel?: string;
380
384
  onFallback?: CascadeOptions["onFallback"];
381
385
  }
382
386
  /**
383
387
  * The SDK's recommended default: free NVIDIA endpoints first, Google as one
384
- * fallback option.
388
+ * fallback option. Capability-aware — image/video requests skip the text-only
389
+ * steps automatically.
385
390
  *
386
- * 1. NVIDIA Kimi K2.6 — main; agentic + multimodal (image/video)
387
- * 2. NVIDIA DeepSeek V4 Pro — text-only; skipped for image/video requests
388
- * 3. Gemini 2.5 Flash final fallback; multimodal
391
+ * 1. NVIDIA Kimi K2.6 — main; agentic + tools (text)
392
+ * 2. NVIDIA DeepSeek V4 Pro 1M-ctx text; skipped for media
393
+ * 3. NVIDIA Llama-3.2-90B-Vision image requests
394
+ * 4. Gemini 2.5 Flash — final fallback; image + video
389
395
  */
390
396
  declare function createDefaultProvider(opts?: DefaultProviderOptions): CascadeProvider;
391
397
 
@@ -451,4 +457,4 @@ interface QueryOptions {
451
457
  */
452
458
  declare function query(prompt: string | ContentBlock[], options?: QueryOptions): AsyncGenerator<AgentEvent>;
453
459
 
454
- export { type AgentEvent, type AnthropicOptions, AnthropicProvider, CHEAP_MODEL, type CanUseTool, type CascadeOptions, CascadeProvider, type CascadeStep, type Complexity, type ContentBlock, DEEPSEEK_V4_FLASH, DEEPSEEK_V4_PRO, type DefaultProviderOptions, EXPENSIVE_MODEL, GEMINI_CHEAP_MODEL, GEMINI_EXPENSIVE_MODEL, type GeminiOptions, GeminiProvider, type JSONSchema, KIMI_K2_6, 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 PermissionConfig, type PermissionDecision, PermissionEngine, type PipelineOptions, type QueryOptions, type RegisteredTool, type Role, type RouterOptions, type RoutingStats, type SdkMcpServer, type StageContract, type StageInput, type StopReason, type TextBlock, type ToolContext, type ToolDefinition, ToolRegistry, type ToolResultBlock, type ToolResultPayload, type ToolSchema, type ToolUseBlock, builtinTools, classifyComplexity, classifyComplexityGemini, createDefaultProvider, createSdkMcpServer, fastHeuristic, getRoutingStats, hasMedia, judgeComplexity, judgeComplexityGemini, latestUserText, listDirTool, loadStageContext, loadStages, matchesAllow, parseContract, query, readFileTool, runLoop, runPipeline, selectGeminiModel, selectModel, tool, writeFileTool };
460
+ export { type AgentEvent, type AnthropicOptions, AnthropicProvider, CHEAP_MODEL, type CanUseTool, type CascadeOptions, CascadeProvider, type CascadeStep, type Complexity, type ContentBlock, DEEPSEEK_V4_FLASH, DEEPSEEK_V4_PRO, type DefaultProviderOptions, EXPENSIVE_MODEL, GEMINI_CHEAP_MODEL, GEMINI_EXPENSIVE_MODEL, type GeminiOptions, GeminiProvider, 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 PermissionConfig, type PermissionDecision, PermissionEngine, type PipelineOptions, type QueryOptions, type RegisteredTool, type Role, type RouterOptions, type RoutingStats, type SdkMcpServer, type StageContract, type StageInput, type StopReason, type TextBlock, type ToolContext, type ToolDefinition, ToolRegistry, type ToolResultBlock, type ToolResultPayload, type ToolSchema, type ToolUseBlock, builtinTools, classifyComplexity, classifyComplexityGemini, createDefaultProvider, createSdkMcpServer, fastHeuristic, getRoutingStats, hasMedia, judgeComplexity, judgeComplexityGemini, latestUserText, listDirTool, loadStageContext, loadStages, matchesAllow, parseContract, query, readFileTool, runLoop, runPipeline, selectGeminiModel, selectModel, tool, writeFileTool };
package/dist/index.js CHANGED
@@ -705,6 +705,7 @@ var NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1";
705
705
  var KIMI_K2_6 = "moonshotai/kimi-k2.6";
706
706
  var DEEPSEEK_V4_PRO = "deepseek-ai/deepseek-v4-pro";
707
707
  var DEEPSEEK_V4_FLASH = "deepseek-ai/deepseek-v4-flash";
708
+ var LLAMA_VISION = "meta/llama-3.2-90b-vision-instruct";
708
709
  var NvidiaProvider = class {
709
710
  name = "nvidia";
710
711
  model;
@@ -717,7 +718,7 @@ var NvidiaProvider = class {
717
718
  this.apiKey = opts.apiKey ?? process.env.NVIDIA_API_KEY;
718
719
  this.baseURL = opts.baseURL ?? NVIDIA_BASE_URL;
719
720
  this.maxTokens = opts.maxTokens ?? 2048;
720
- this.temperature = opts.temperature ?? 0.6;
721
+ this.temperature = opts.temperature ?? 0.2;
721
722
  }
722
723
  async generate(req) {
723
724
  if (!this.apiKey) throw new Error("NvidiaProvider needs NVIDIA_API_KEY (nvapi-...).");
@@ -830,10 +831,15 @@ var CascadeProvider = class {
830
831
  this.onFallback = opts.onFallback;
831
832
  }
832
833
  async generate(req) {
833
- const needsVision = hasMedia(req.messages);
834
- const eligible = this.steps.filter((s) => !needsVision || s.vision);
834
+ const has = (t) => req.messages.some((m) => m.content.some((b) => b.type === t));
835
+ const needsVideo = has("video");
836
+ const needsImage = has("image");
837
+ const needsVision = needsImage || needsVideo;
838
+ const eligible = needsVideo ? this.steps.filter((s) => s.video) : needsImage ? this.steps.filter((s) => s.vision) : this.steps;
835
839
  if (!eligible.length) {
836
- throw new Error("Cascade: request needs vision but no step supports image/video input.");
840
+ throw new Error(
841
+ `Cascade: request needs ${needsVideo ? "video" : "image"} input but no step supports it.`
842
+ );
837
843
  }
838
844
  let lastErr;
839
845
  for (const step of eligible) {
@@ -854,26 +860,20 @@ var CascadeProvider = class {
854
860
  function createDefaultProvider(opts = {}) {
855
861
  const main = opts.mainModel ?? KIMI_K2_6;
856
862
  const secondary = opts.secondaryModel ?? DEEPSEEK_V4_PRO;
863
+ const vision = opts.visionModel ?? LLAMA_VISION;
857
864
  const gemini = opts.geminiModel ?? "gemini-2.5-flash";
865
+ const nv = (model) => new NvidiaProvider({ model, apiKey: opts.nvidiaApiKey });
858
866
  return new CascadeProvider({
859
867
  onFallback: opts.onFallback ?? ((info) => console.warn(`[cascade] ${info.from} failed (${info.reason}); trying next`)),
860
868
  steps: [
861
- {
862
- provider: new NvidiaProvider({ model: main, apiKey: opts.nvidiaApiKey }),
863
- label: `nvidia:${main}`,
864
- vision: true
865
- // Kimi K2.6 accepts image + video
866
- },
867
- {
868
- provider: new NvidiaProvider({ model: secondary, apiKey: opts.nvidiaApiKey }),
869
- label: `nvidia:${secondary}`,
870
- vision: false
871
- // DeepSeek V4 is text-only
872
- },
869
+ { provider: nv(main), label: `nvidia:${main}`, vision: false, video: false },
870
+ { provider: nv(secondary), label: `nvidia:${secondary}`, vision: false, video: false },
871
+ { provider: nv(vision), label: `nvidia:${vision}`, vision: true, video: false },
873
872
  {
874
873
  provider: new GeminiProvider({ model: gemini, apiKey: opts.googleApiKey }),
875
874
  label: `gemini:${gemini}`,
876
- vision: true
875
+ vision: true,
876
+ video: true
877
877
  }
878
878
  ]
879
879
  });
@@ -908,6 +908,7 @@ export {
908
908
  GEMINI_EXPENSIVE_MODEL,
909
909
  GeminiProvider,
910
910
  KIMI_K2_6,
911
+ LLAMA_VISION,
911
912
  MockProvider,
912
913
  NVIDIA_BASE_URL,
913
914
  NvidiaProvider,
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/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, vision (image+video)\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\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.6;\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 { hasMedia } from \"../types.ts\";\nimport type { ModelProvider, ModelRequest, ModelResponse } from \"../types.ts\";\nimport { DEEPSEEK_V4_PRO, KIMI_K2_6, 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: requests that carry image/video are only sent to steps that\n// support vision — text-only models (e.g. DeepSeek) are skipped for those.\n\nexport interface CascadeStep {\n provider: ModelProvider;\n label: string; // e.g. \"nvidia:kimi-k2.6\"\n vision: boolean; // does this step's model accept image/video input?\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 needsVision = hasMedia(req.messages);\n const eligible = this.steps.filter((s) => !needsVision || s.vision);\n\n if (!eligible.length) {\n throw new Error(\"Cascade: request needs vision but no step supports image/video input.\");\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 /** 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.\n *\n * 1. NVIDIA Kimi K2.6 — main; agentic + multimodal (image/video)\n * 2. NVIDIA DeepSeek V4 Pro — text-only; skipped for image/video requests\n * 3. Gemini 2.5 Flash — final fallback; multimodal\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 gemini = opts.geminiModel ?? \"gemini-2.5-flash\";\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 {\n provider: new NvidiaProvider({ model: main, apiKey: opts.nvidiaApiKey }),\n label: `nvidia:${main}`,\n vision: true, // Kimi K2.6 accepts image + video\n },\n {\n provider: new NvidiaProvider({ model: secondary, apiKey: opts.nvidiaApiKey }),\n label: `nvidia:${secondary}`,\n vision: false, // DeepSeek V4 is text-only\n },\n {\n provider: new GeminiProvider({ model: gemini, apiKey: opts.googleApiKey }),\n label: `gemini:${gemini}`,\n vision: true,\n },\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} from \"./providers/nvidia.ts\";\nexport {\n CascadeProvider,\n createDefaultProvider,\n type CascadeStep,\n type CascadeOptions,\n type DefaultProviderOptions,\n} from \"./providers/cascade.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"]}
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/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","// 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\";\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"]}
@@ -8,6 +8,7 @@
8
8
  "cascade": [
9
9
  "moonshotai/kimi-k2.6",
10
10
  "deepseek-ai/deepseek-v4-pro",
11
+ "meta/llama-3.2-90b-vision-instruct",
11
12
  "gemini-2.5-flash"
12
13
  ],
13
14
  "models": [
@@ -18,7 +19,17 @@
18
19
  "free": true,
19
20
  "available": true,
20
21
  "context": 262144,
21
- "capabilities": { "tools": true, "vision": true, "video": true, "reasoning": false }
22
+ "note": "Agentic + tools. Vision claimed in docs but text-only on this NIM endpoint (verified 2026-06-14).",
23
+ "capabilities": { "tools": true, "vision": false, "video": false, "reasoning": false }
24
+ },
25
+ {
26
+ "id": "meta/llama-3.2-90b-vision-instruct",
27
+ "provider": "nvidia",
28
+ "role": "vision",
29
+ "free": true,
30
+ "available": true,
31
+ "context": 128000,
32
+ "capabilities": { "tools": false, "vision": true, "video": false, "reasoning": false }
22
33
  },
23
34
  {
24
35
  "id": "deepseek-ai/deepseek-v4-pro",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "torus-ai",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
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",
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@ export {
18
18
  KIMI_K2_6,
19
19
  DEEPSEEK_V4_PRO,
20
20
  DEEPSEEK_V4_FLASH,
21
+ LLAMA_VISION,
21
22
  } from "./providers/nvidia.ts";
22
23
  export {
23
24
  CascadeProvider,
@@ -1,17 +1,17 @@
1
- import { hasMedia } from "../types.ts";
2
1
  import type { ModelProvider, ModelRequest, ModelResponse } from "../types.ts";
3
- import { DEEPSEEK_V4_PRO, KIMI_K2_6, NvidiaProvider } from "./nvidia.ts";
2
+ import { DEEPSEEK_V4_PRO, KIMI_K2_6, LLAMA_VISION, NvidiaProvider } from "./nvidia.ts";
4
3
  import { GeminiProvider } from "./gemini.ts";
5
4
 
6
5
  // Orchestration: try a prioritized list of (provider, model) steps, falling
7
6
  // through to the next on failure (rate limit, error, or capability mismatch).
8
- // Capability-aware: requests that carry image/video are only sent to steps that
9
- // support vision — text-only models (e.g. DeepSeek) are skipped for those.
7
+ // Capability-aware: image requests only go to vision steps; video requests only
8
+ // to video steps — text-only models (Kimi, DeepSeek) are skipped for those.
10
9
 
11
10
  export interface CascadeStep {
12
11
  provider: ModelProvider;
13
12
  label: string; // e.g. "nvidia:kimi-k2.6"
14
- vision: boolean; // does this step's model accept image/video input?
13
+ vision: boolean; // accepts image input?
14
+ video?: boolean; // accepts video input? (default false)
15
15
  }
16
16
 
17
17
  export interface CascadeOptions {
@@ -32,11 +32,22 @@ export class CascadeProvider implements ModelProvider {
32
32
  }
33
33
 
34
34
  async generate(req: ModelRequest): Promise<ModelResponse> {
35
- const needsVision = hasMedia(req.messages);
36
- const eligible = this.steps.filter((s) => !needsVision || s.vision);
35
+ const has = (t: "image" | "video") =>
36
+ req.messages.some((m) => m.content.some((b) => b.type === t));
37
+ const needsVideo = has("video");
38
+ const needsImage = has("image");
39
+ const needsVision = needsImage || needsVideo;
40
+
41
+ const eligible = needsVideo
42
+ ? this.steps.filter((s) => s.video)
43
+ : needsImage
44
+ ? this.steps.filter((s) => s.vision)
45
+ : this.steps;
37
46
 
38
47
  if (!eligible.length) {
39
- throw new Error("Cascade: request needs vision but no step supports image/video input.");
48
+ throw new Error(
49
+ `Cascade: request needs ${needsVideo ? "video" : "image"} input but no step supports it.`,
50
+ );
40
51
  }
41
52
 
42
53
  let lastErr: unknown;
@@ -63,6 +74,8 @@ export interface DefaultProviderOptions {
63
74
  mainModel?: string;
64
75
  /** Override the secondary NVIDIA model (default DeepSeek V4 Pro). */
65
76
  secondaryModel?: string;
77
+ /** NVIDIA vision model for image requests (default llama-3.2-90b-vision). */
78
+ visionModel?: string;
66
79
  /** Gemini model used as the final fallback option (default gemini-2.5-flash). */
67
80
  geminiModel?: string;
68
81
  onFallback?: CascadeOptions["onFallback"];
@@ -70,16 +83,20 @@ export interface DefaultProviderOptions {
70
83
 
71
84
  /**
72
85
  * The SDK's recommended default: free NVIDIA endpoints first, Google as one
73
- * fallback option.
86
+ * fallback option. Capability-aware — image/video requests skip the text-only
87
+ * steps automatically.
74
88
  *
75
- * 1. NVIDIA Kimi K2.6 — main; agentic + multimodal (image/video)
76
- * 2. NVIDIA DeepSeek V4 Pro — text-only; skipped for image/video requests
77
- * 3. Gemini 2.5 Flash final fallback; multimodal
89
+ * 1. NVIDIA Kimi K2.6 — main; agentic + tools (text)
90
+ * 2. NVIDIA DeepSeek V4 Pro 1M-ctx text; skipped for media
91
+ * 3. NVIDIA Llama-3.2-90B-Vision image requests
92
+ * 4. Gemini 2.5 Flash — final fallback; image + video
78
93
  */
79
94
  export function createDefaultProvider(opts: DefaultProviderOptions = {}): CascadeProvider {
80
95
  const main = opts.mainModel ?? KIMI_K2_6;
81
96
  const secondary = opts.secondaryModel ?? DEEPSEEK_V4_PRO;
97
+ const vision = opts.visionModel ?? LLAMA_VISION;
82
98
  const gemini = opts.geminiModel ?? "gemini-2.5-flash";
99
+ const nv = (model: string) => new NvidiaProvider({ model, apiKey: opts.nvidiaApiKey });
83
100
 
84
101
  return new CascadeProvider({
85
102
  onFallback:
@@ -87,20 +104,14 @@ export function createDefaultProvider(opts: DefaultProviderOptions = {}): Cascad
87
104
  ((info) =>
88
105
  console.warn(`[cascade] ${info.from} failed (${info.reason}); trying next`)),
89
106
  steps: [
90
- {
91
- provider: new NvidiaProvider({ model: main, apiKey: opts.nvidiaApiKey }),
92
- label: `nvidia:${main}`,
93
- vision: true, // Kimi K2.6 accepts image + video
94
- },
95
- {
96
- provider: new NvidiaProvider({ model: secondary, apiKey: opts.nvidiaApiKey }),
97
- label: `nvidia:${secondary}`,
98
- vision: false, // DeepSeek V4 is text-only
99
- },
107
+ { provider: nv(main), label: `nvidia:${main}`, vision: false, video: false },
108
+ { provider: nv(secondary), label: `nvidia:${secondary}`, vision: false, video: false },
109
+ { provider: nv(vision), label: `nvidia:${vision}`, vision: true, video: false },
100
110
  {
101
111
  provider: new GeminiProvider({ model: gemini, apiKey: opts.googleApiKey }),
102
112
  label: `gemini:${gemini}`,
103
113
  vision: true,
114
+ video: true,
104
115
  },
105
116
  ],
106
117
  });
@@ -13,9 +13,10 @@ import type {
13
13
  export const NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1";
14
14
 
15
15
  // Exact IDs confirmed against GET /v1/models.
16
- export const KIMI_K2_6 = "moonshotai/kimi-k2.6"; // 256K ctx, tools, vision (image+video)
16
+ export const KIMI_K2_6 = "moonshotai/kimi-k2.6"; // 256K ctx, tools, agentic — text-only on NIM (verified)
17
17
  export const DEEPSEEK_V4_PRO = "deepseek-ai/deepseek-v4-pro"; // 1M ctx, tools, text-only
18
18
  export const DEEPSEEK_V4_FLASH = "deepseek-ai/deepseek-v4-flash"; // faster/cheaper, text-only
19
+ export const LLAMA_VISION = "meta/llama-3.2-90b-vision-instruct"; // free NVIDIA vision model (image), verified
19
20
 
20
21
  export interface NvidiaOptions {
21
22
  model?: string;
@@ -38,7 +39,7 @@ export class NvidiaProvider implements ModelProvider {
38
39
  this.apiKey = opts.apiKey ?? process.env.NVIDIA_API_KEY;
39
40
  this.baseURL = opts.baseURL ?? NVIDIA_BASE_URL;
40
41
  this.maxTokens = opts.maxTokens ?? 2048;
41
- this.temperature = opts.temperature ?? 0.6;
42
+ this.temperature = opts.temperature ?? 0.2; // low default for deterministic agent behavior
42
43
  }
43
44
 
44
45
  async generate(req: ModelRequest): Promise<ModelResponse> {