contextos-mcp 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +260 -0
  3. package/bin/mcp.mjs +61 -0
  4. package/bin/swarm.mjs +45 -0
  5. package/dist/agents/aider.d.ts +12 -0
  6. package/dist/agents/aider.js +192 -0
  7. package/dist/agents/aider.js.map +1 -0
  8. package/dist/agents/claude-code.d.ts +9 -0
  9. package/dist/agents/claude-code.js +236 -0
  10. package/dist/agents/claude-code.js.map +1 -0
  11. package/dist/agents/codex.d.ts +14 -0
  12. package/dist/agents/codex.js +203 -0
  13. package/dist/agents/codex.js.map +1 -0
  14. package/dist/agents/direct-llm.d.ts +22 -0
  15. package/dist/agents/direct-llm.js +254 -0
  16. package/dist/agents/direct-llm.js.map +1 -0
  17. package/dist/agents/mock.d.ts +10 -0
  18. package/dist/agents/mock.js +170 -0
  19. package/dist/agents/mock.js.map +1 -0
  20. package/dist/agents/opencode.d.ts +23 -0
  21. package/dist/agents/opencode.js +631 -0
  22. package/dist/agents/opencode.js.map +1 -0
  23. package/dist/agents/provider.d.ts +11 -0
  24. package/dist/agents/provider.js +31 -0
  25. package/dist/agents/provider.js.map +1 -0
  26. package/dist/compression/compressor.d.ts +28 -0
  27. package/dist/compression/compressor.js +268 -0
  28. package/dist/compression/compressor.js.map +1 -0
  29. package/dist/config.d.ts +43 -0
  30. package/dist/config.js +172 -0
  31. package/dist/config.js.map +1 -0
  32. package/dist/contextos/loader.d.ts +46 -0
  33. package/dist/contextos/loader.js +120 -0
  34. package/dist/contextos/loader.js.map +1 -0
  35. package/dist/contextos/selector.d.ts +46 -0
  36. package/dist/contextos/selector.js +80 -0
  37. package/dist/contextos/selector.js.map +1 -0
  38. package/dist/core/action-dispatcher.d.ts +15 -0
  39. package/dist/core/action-dispatcher.js +28 -0
  40. package/dist/core/action-dispatcher.js.map +1 -0
  41. package/dist/core/action-schema.d.ts +72 -0
  42. package/dist/core/action-schema.js +86 -0
  43. package/dist/core/action-schema.js.map +1 -0
  44. package/dist/core/repl-interface.d.ts +48 -0
  45. package/dist/core/repl-interface.js +5 -0
  46. package/dist/core/repl-interface.js.map +1 -0
  47. package/dist/core/repl.d.ts +59 -0
  48. package/dist/core/repl.js +353 -0
  49. package/dist/core/repl.js.map +1 -0
  50. package/dist/core/rlm.d.ts +65 -0
  51. package/dist/core/rlm.js +564 -0
  52. package/dist/core/rlm.js.map +1 -0
  53. package/dist/core/runtime.py +470 -0
  54. package/dist/core/types.d.ts +265 -0
  55. package/dist/core/types.js +19 -0
  56. package/dist/core/types.js.map +1 -0
  57. package/dist/env.d.ts +10 -0
  58. package/dist/env.js +75 -0
  59. package/dist/env.js.map +1 -0
  60. package/dist/hooks/runner.d.ts +43 -0
  61. package/dist/hooks/runner.js +173 -0
  62. package/dist/hooks/runner.js.map +1 -0
  63. package/dist/labs/cli.d.ts +15 -0
  64. package/dist/labs/cli.js +295 -0
  65. package/dist/labs/cli.js.map +1 -0
  66. package/dist/labs/episodic-memory.d.ts +132 -0
  67. package/dist/labs/episodic-memory.js +391 -0
  68. package/dist/labs/episodic-memory.js.map +1 -0
  69. package/dist/labs/interactive-swarm.d.ts +20 -0
  70. package/dist/labs/interactive-swarm.js +1173 -0
  71. package/dist/labs/interactive-swarm.js.map +1 -0
  72. package/dist/labs/interactive.d.ts +10 -0
  73. package/dist/labs/interactive.js +2099 -0
  74. package/dist/labs/interactive.js.map +1 -0
  75. package/dist/labs/ts-analyzer.d.ts +74 -0
  76. package/dist/labs/ts-analyzer.js +379 -0
  77. package/dist/labs/ts-analyzer.js.map +1 -0
  78. package/dist/labs/viewer.d.ts +12 -0
  79. package/dist/labs/viewer.js +1284 -0
  80. package/dist/labs/viewer.js.map +1 -0
  81. package/dist/main.d.ts +15 -0
  82. package/dist/main.js +247 -0
  83. package/dist/main.js.map +1 -0
  84. package/dist/mcp/server.d.ts +16 -0
  85. package/dist/mcp/server.js +192775 -0
  86. package/dist/mcp/server.js.map +1 -0
  87. package/dist/mcp/session.d.ts +117 -0
  88. package/dist/mcp/session.js +450 -0
  89. package/dist/mcp/session.js.map +1 -0
  90. package/dist/mcp/state.d.ts +42 -0
  91. package/dist/mcp/state.js +537 -0
  92. package/dist/mcp/state.js.map +1 -0
  93. package/dist/mcp/tools/contextos.d.ts +17 -0
  94. package/dist/mcp/tools/contextos.js +583 -0
  95. package/dist/mcp/tools/contextos.js.map +1 -0
  96. package/dist/mcp/tools.d.ts +15 -0
  97. package/dist/mcp/tools.js +393 -0
  98. package/dist/mcp/tools.js.map +1 -0
  99. package/dist/orchestration/reviewer-gate.d.ts +43 -0
  100. package/dist/orchestration/reviewer-gate.js +280 -0
  101. package/dist/orchestration/reviewer-gate.js.map +1 -0
  102. package/dist/orchestration/reviewer-prompt.d.ts +18 -0
  103. package/dist/orchestration/reviewer-prompt.js +67 -0
  104. package/dist/orchestration/reviewer-prompt.js.map +1 -0
  105. package/dist/orchestration/verification-runner.d.ts +53 -0
  106. package/dist/orchestration/verification-runner.js +352 -0
  107. package/dist/orchestration/verification-runner.js.map +1 -0
  108. package/dist/plugins/adapter.d.ts +11 -0
  109. package/dist/plugins/adapter.js +11 -0
  110. package/dist/plugins/adapter.js.map +1 -0
  111. package/dist/plugins/core/archive.d.ts +9 -0
  112. package/dist/plugins/core/archive.js +128 -0
  113. package/dist/plugins/core/archive.js.map +1 -0
  114. package/dist/plugins/core/digest.d.ts +11 -0
  115. package/dist/plugins/core/digest.js +70 -0
  116. package/dist/plugins/core/digest.js.map +1 -0
  117. package/dist/plugins/core/grants.d.ts +22 -0
  118. package/dist/plugins/core/grants.js +90 -0
  119. package/dist/plugins/core/grants.js.map +1 -0
  120. package/dist/plugins/core/index.d.ts +10 -0
  121. package/dist/plugins/core/index.js +11 -0
  122. package/dist/plugins/core/index.js.map +1 -0
  123. package/dist/plugins/core/pinning.d.ts +15 -0
  124. package/dist/plugins/core/pinning.js +86 -0
  125. package/dist/plugins/core/pinning.js.map +1 -0
  126. package/dist/plugins/core/types.d.ts +105 -0
  127. package/dist/plugins/core/types.js +22 -0
  128. package/dist/plugins/core/types.js.map +1 -0
  129. package/dist/plugins/core/updater.d.ts +16 -0
  130. package/dist/plugins/core/updater.js +64 -0
  131. package/dist/plugins/core/updater.js.map +1 -0
  132. package/dist/plugins/loader.d.ts +65 -0
  133. package/dist/plugins/loader.js +110 -0
  134. package/dist/plugins/loader.js.map +1 -0
  135. package/dist/prompts/orchestrator.d.ts +6 -0
  136. package/dist/prompts/orchestrator.js +114 -0
  137. package/dist/prompts/orchestrator.js.map +1 -0
  138. package/dist/routing/model-resolver.d.ts +27 -0
  139. package/dist/routing/model-resolver.js +265 -0
  140. package/dist/routing/model-resolver.js.map +1 -0
  141. package/dist/routing/model-router.d.ts +130 -0
  142. package/dist/routing/model-router.js +515 -0
  143. package/dist/routing/model-router.js.map +1 -0
  144. package/dist/runtime/attestations.cjs +260 -0
  145. package/dist/runtime/reviewer-pipeline.cjs +319 -0
  146. package/dist/runtime/sandbox.cjs +468 -0
  147. package/dist/runtime/state-machine.cjs +885 -0
  148. package/dist/runtime/thread-store.cjs +175 -0
  149. package/dist/runtime/transactional-git.cjs +315 -0
  150. package/dist/runtime/verification-pipeline.cjs +435 -0
  151. package/dist/sandbox/execution.d.ts +165 -0
  152. package/dist/sandbox/execution.js +497 -0
  153. package/dist/sandbox/execution.js.map +1 -0
  154. package/dist/security/file-policy.d.ts +22 -0
  155. package/dist/security/file-policy.js +53 -0
  156. package/dist/security/file-policy.js.map +1 -0
  157. package/dist/security/repository-boundary.d.ts +21 -0
  158. package/dist/security/repository-boundary.js +119 -0
  159. package/dist/security/repository-boundary.js.map +1 -0
  160. package/dist/security/secret-filter.d.ts +36 -0
  161. package/dist/security/secret-filter.js +149 -0
  162. package/dist/security/secret-filter.js.map +1 -0
  163. package/dist/swarm.d.ts +14 -0
  164. package/dist/swarm.js +624 -0
  165. package/dist/swarm.js.map +1 -0
  166. package/dist/threads/cache.d.ts +64 -0
  167. package/dist/threads/cache.js +241 -0
  168. package/dist/threads/cache.js.map +1 -0
  169. package/dist/threads/manager.d.ts +94 -0
  170. package/dist/threads/manager.js +914 -0
  171. package/dist/threads/manager.js.map +1 -0
  172. package/dist/ui/banner.d.ts +14 -0
  173. package/dist/ui/banner.js +42 -0
  174. package/dist/ui/banner.js.map +1 -0
  175. package/dist/ui/dashboard.d.ts +33 -0
  176. package/dist/ui/dashboard.js +135 -0
  177. package/dist/ui/dashboard.js.map +1 -0
  178. package/dist/ui/index.d.ts +11 -0
  179. package/dist/ui/index.js +12 -0
  180. package/dist/ui/index.js.map +1 -0
  181. package/dist/ui/log.d.ts +39 -0
  182. package/dist/ui/log.js +126 -0
  183. package/dist/ui/log.js.map +1 -0
  184. package/dist/ui/onboarding.d.ts +14 -0
  185. package/dist/ui/onboarding.js +755 -0
  186. package/dist/ui/onboarding.js.map +1 -0
  187. package/dist/ui/run-log.d.ts +50 -0
  188. package/dist/ui/run-log.js +60 -0
  189. package/dist/ui/run-log.js.map +1 -0
  190. package/dist/ui/spinner.d.ts +41 -0
  191. package/dist/ui/spinner.js +172 -0
  192. package/dist/ui/spinner.js.map +1 -0
  193. package/dist/ui/streaming-feed.d.ts +72 -0
  194. package/dist/ui/streaming-feed.js +386 -0
  195. package/dist/ui/streaming-feed.js.map +1 -0
  196. package/dist/ui/summary.d.ts +18 -0
  197. package/dist/ui/summary.js +113 -0
  198. package/dist/ui/summary.js.map +1 -0
  199. package/dist/ui/text-input.d.ts +19 -0
  200. package/dist/ui/text-input.js +266 -0
  201. package/dist/ui/text-input.js.map +1 -0
  202. package/dist/ui/theme.d.ts +63 -0
  203. package/dist/ui/theme.js +97 -0
  204. package/dist/ui/theme.js.map +1 -0
  205. package/dist/utils/command-exists.d.ts +11 -0
  206. package/dist/utils/command-exists.js +41 -0
  207. package/dist/utils/command-exists.js.map +1 -0
  208. package/dist/utils/process-security.d.ts +19 -0
  209. package/dist/utils/process-security.js +90 -0
  210. package/dist/utils/process-security.js.map +1 -0
  211. package/dist/utils/rolling-buffer.d.ts +16 -0
  212. package/dist/utils/rolling-buffer.js +30 -0
  213. package/dist/utils/rolling-buffer.js.map +1 -0
  214. package/dist/utils/safe-spawn.d.ts +13 -0
  215. package/dist/utils/safe-spawn.js +49 -0
  216. package/dist/utils/safe-spawn.js.map +1 -0
  217. package/dist/worktree/manager.d.ts +69 -0
  218. package/dist/worktree/manager.js +593 -0
  219. package/dist/worktree/manager.js.map +1 -0
  220. package/dist/worktree/merge.d.ts +58 -0
  221. package/dist/worktree/merge.js +389 -0
  222. package/dist/worktree/merge.js.map +1 -0
  223. package/package.json +63 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Orchestrator system prompt — teaches the LLM how to orchestrate swarm tasks
3
+ * via declarative, typed JSON actions.
4
+ */
5
+ import type { SwarmConfig } from "../core/types.js";
6
+ export declare function buildSwarmSystemPrompt(config: SwarmConfig, agentDescriptions?: string, language?: "javascript" | "python" | "json"): string;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Orchestrator system prompt — teaches the LLM how to orchestrate swarm tasks
3
+ * via declarative, typed JSON actions.
4
+ */
5
+ export function buildSwarmSystemPrompt(config, agentDescriptions, language) {
6
+ if (language === "python") {
7
+ return `You are a text analysis agent assisting with codebase decomposition. Analyze the provided context and return structured findings.`;
8
+ }
9
+ return `You are a Swarm Orchestrator — an AI agent coordinating parallel coding agents across isolated git worktrees using declarative JSON actions.
10
+
11
+ ## Action Protocol
12
+
13
+ You do not write or execute arbitrary scripts. Every turn you MUST respond with a single JSON action object conforming to version 1 of the action schema.
14
+
15
+ Available actions:
16
+ 1. \`spawn\` — Spawn a subagent thread in an isolated git worktree with an explicit write scope.
17
+ 2. \`wait\` — Await completion of specified thread IDs.
18
+ 3. \`inspect_diff\` — Inspect the git diff produced by a thread.
19
+ 4. \`review\` — Mark a thread as reviewed after verifying changes.
20
+ 5. \`merge\` — Merge a thread's branch into the workspace.
21
+ 6. \`finish\` — Conclude orchestration and return the final report.
22
+
23
+ ## Action Schemas
24
+
25
+ ### 1. \`spawn\`
26
+ \`\`\`json
27
+ {
28
+ "version": 1,
29
+ "action": "spawn",
30
+ "task": "Precise description of the task for the subagent",
31
+ "writeScope": ["src/module.ts", "tests/module.test.ts"],
32
+ "model": "${config.default_model}"
33
+ }
34
+ \`\`\`
35
+ - \`writeScope\`: Array of repository-relative file paths the agent is permitted to touch.
36
+ - \`model\`: Optional model override.
37
+
38
+ ### 2. \`wait\`
39
+ \`\`\`json
40
+ {
41
+ "version": 1,
42
+ "action": "wait",
43
+ "threadIds": ["thread_id_1", "thread_id_2"]
44
+ }
45
+ \`\`\`
46
+
47
+ ### 3. \`inspect_diff\`
48
+ \`\`\`json
49
+ {
50
+ "version": 1,
51
+ "action": "inspect_diff",
52
+ "threadId": "thread_id_1"
53
+ }
54
+ \`\`\`
55
+
56
+ ### 4. \`review\`
57
+ \`\`\`json
58
+ {
59
+ "version": 1,
60
+ "action": "review",
61
+ "threadId": "thread_id_1"
62
+ }
63
+ \`\`\`
64
+
65
+ ### 5. \`merge\`
66
+ \`\`\`json
67
+ {
68
+ "version": 1,
69
+ "action": "merge",
70
+ "threadId": "thread_id_1"
71
+ }
72
+ \`\`\`
73
+
74
+ ### 6. \`finish\`
75
+ \`\`\`json
76
+ {
77
+ "version": 1,
78
+ "action": "finish",
79
+ "summary": "Comprehensive summary of changes, verification results, and next steps."
80
+ }
81
+ \`\`\`
82
+
83
+ ${agentDescriptions
84
+ ? `## Available Agents
85
+
86
+ ${agentDescriptions}
87
+
88
+ `
89
+ : ""}## Orchestration Rules
90
+
91
+ 1. Decompose the objective into independent tasks with explicit, isolated \`writeScope\` file lists.
92
+ 2. Spawn tasks using \`spawn\`.
93
+ 3. Use \`wait\` to check completion of running threads.
94
+ 4. Use \`inspect_diff\` to inspect the exact diff produced by each thread.
95
+ 5. Review the changes with \`review\`.
96
+ 6. Merge valid completed threads with \`merge\`.
97
+ 7. Conclude the session with \`finish\`.
98
+ 8. Never output executable code, scripts, or placeholders.
99
+ 9. Always respond with a single JSON object matching the action schema.
100
+
101
+ ## Output format
102
+
103
+ Respond with ONLY a JSON code block. No explanations before or after.
104
+
105
+ \`\`\`json
106
+ {
107
+ "version": 1,
108
+ "action": "spawn",
109
+ "task": "Example task",
110
+ "writeScope": ["src/example.ts"]
111
+ }
112
+ \`\`\``;
113
+ }
114
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/prompts/orchestrator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,UAAU,sBAAsB,CACrC,MAAmB,EACnB,iBAA0B,EAC1B,QAA2C;IAE3C,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,mIAAmI,CAAC;IAC5I,CAAC;IAED,OAAO;;;;;;;;;;;;;;;;;;;;;;;cAuBM,MAAM,CAAC,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoDjC,iBAAiB;QAChB,CAAC,CAAC;;EAEF,iBAAiB;;CAElB;QACC,CAAC,CAAC,EACJ;;;;;;;;;;;;;;;;;;;;;;;OAuBO,CAAC;AACR,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Model resolver — resolves model IDs to pi-ai Model objects.
3
+ *
4
+ * Handles three cases:
5
+ * 1. Standard pi-ai models (anthropic, openai, google) — looked up from pi-ai registry
6
+ * 2. Ollama models (ollama/*) — creates synthetic Model<"openai-completions"> pointing at localhost:11434
7
+ * 3. OpenRouter models (openrouter/*) — creates synthetic Model<"openai-completions"> pointing at openrouter.ai
8
+ *
9
+ * This preserves the RLM loop for all backends — the orchestrator always uses pi-ai's completeSimple().
10
+ */
11
+ import { type Model } from "@mariozechner/pi-ai";
12
+ type Api = "openai-completions" | "openai-responses";
13
+ export interface ResolvedModel {
14
+ model: Model<Api>;
15
+ provider: string;
16
+ }
17
+ /**
18
+ * Resolve a model ID to a pi-ai Model object.
19
+ *
20
+ * Supports:
21
+ * - "ollama/deepseek-coder-v2" → Ollama local model
22
+ * - "openrouter/auto" → OpenRouter cloud model
23
+ * - "claude-sonnet-4-6" → standard pi-ai model lookup
24
+ * - Falls back to any available provider's default model
25
+ */
26
+ export declare function resolveModel(modelId: string, warnFn?: (msg: string) => void): ResolvedModel | null;
27
+ export {};
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Model resolver — resolves model IDs to pi-ai Model objects.
3
+ *
4
+ * Handles three cases:
5
+ * 1. Standard pi-ai models (anthropic, openai, google) — looked up from pi-ai registry
6
+ * 2. Ollama models (ollama/*) — creates synthetic Model<"openai-completions"> pointing at localhost:11434
7
+ * 3. OpenRouter models (openrouter/*) — creates synthetic Model<"openai-completions"> pointing at openrouter.ai
8
+ *
9
+ * This preserves the RLM loop for all backends — the orchestrator always uses pi-ai's completeSimple().
10
+ */
11
+ import { getEnvApiKey, getModels, getProviders } from "@mariozechner/pi-ai";
12
+ // Patch global fetch to bypass WAFs that block Node.js by default
13
+ const originalFetch = globalThis.fetch;
14
+ globalThis.fetch = async function (url, options) {
15
+ if (url.toString().includes("air-outer.com") || url.toString().includes("agentrouter.org")) {
16
+ options = options || {};
17
+ options.headers = {
18
+ ...options.headers,
19
+ "User-Agent": "OpenCode",
20
+ };
21
+ }
22
+ return originalFetch.apply(this, [url, options]);
23
+ };
24
+ const DEFAULT_MODELS = {
25
+ anthropic: "claude-sonnet-4-6",
26
+ openai: "gpt-4o",
27
+ google: "gemini-2.5-flash",
28
+ };
29
+ /**
30
+ * Create a synthetic pi-ai Model for Ollama (OpenAI-compatible API at localhost:11434).
31
+ *
32
+ * Uses provider "openai" so pi-ai's API key lookup resolves to OPENAI_API_KEY.
33
+ * We set a dummy OPENAI_API_KEY if none exists — Ollama ignores auth headers.
34
+ */
35
+ function createOllamaModel(modelId) {
36
+ const shortId = modelId.replace("ollama/", "");
37
+ // pi-ai requires an API key for the "openai" provider. Ollama doesn't need one,
38
+ // but we must satisfy pi-ai's check. Set a dummy key if no real one exists.
39
+ if (!process.env.OPENAI_API_KEY) {
40
+ process.env.OPENAI_API_KEY = "ollama-local";
41
+ }
42
+ return {
43
+ id: shortId,
44
+ name: shortId,
45
+ api: "openai-completions",
46
+ provider: "openai",
47
+ baseUrl: "http://localhost:11434/v1",
48
+ reasoning: false,
49
+ input: ["text"],
50
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
51
+ contextWindow: 32768,
52
+ maxTokens: 4096,
53
+ compat: {
54
+ supportsStore: false,
55
+ supportsDeveloperRole: false,
56
+ supportsReasoningEffort: false,
57
+ supportsUsageInStreaming: false,
58
+ maxTokensField: "max_tokens",
59
+ requiresToolResultName: false,
60
+ requiresAssistantAfterToolResult: false,
61
+ requiresThinkingAsText: false,
62
+ requiresMistralToolIds: false,
63
+ thinkingFormat: "openai",
64
+ supportsStrictMode: false,
65
+ },
66
+ };
67
+ }
68
+ /**
69
+ * Create a synthetic pi-ai Model for OpenRouter (OpenAI-compatible API).
70
+ */
71
+ function createOpenRouterModel(modelId) {
72
+ const shortId = modelId.replace("openrouter/", "");
73
+ const apiKey = process.env.OPENROUTER_API_KEY || "";
74
+ return {
75
+ id: shortId,
76
+ name: shortId,
77
+ api: "openai-completions",
78
+ provider: "openrouter",
79
+ baseUrl: "https://openrouter.ai/api/v1",
80
+ reasoning: false,
81
+ input: ["text"],
82
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
83
+ contextWindow: 128000,
84
+ maxTokens: 4096,
85
+ headers: {
86
+ Authorization: `Bearer ${apiKey}`,
87
+ "HTTP-Referer": "https://github.com/kok-o/contextos-agents",
88
+ "X-Title": "contextos-agents",
89
+ },
90
+ compat: {
91
+ supportsStore: false,
92
+ supportsDeveloperRole: false,
93
+ supportsReasoningEffort: false,
94
+ supportsUsageInStreaming: true,
95
+ maxTokensField: "max_tokens",
96
+ requiresToolResultName: false,
97
+ requiresAssistantAfterToolResult: false,
98
+ requiresThinkingAsText: false,
99
+ requiresMistralToolIds: false,
100
+ thinkingFormat: "openai",
101
+ supportsStrictMode: false,
102
+ openRouterRouting: undefined,
103
+ },
104
+ };
105
+ }
106
+ /**
107
+ * Create a synthetic pi-ai Model for AgentRouter (OpenAI-compatible API).
108
+ */
109
+ function createAgentRouterModel(modelId) {
110
+ const shortId = modelId.replace("agentrouter/", "");
111
+ const apiKey = process.env.OPENAI_API_KEY || "";
112
+ return {
113
+ id: shortId,
114
+ name: shortId,
115
+ api: "openai-completions",
116
+ provider: "openai",
117
+ baseUrl: "https://agentrouter.org/v1",
118
+ reasoning: false,
119
+ input: ["text"],
120
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
121
+ contextWindow: 128000,
122
+ maxTokens: 4096,
123
+ headers: {
124
+ Authorization: `Bearer ${apiKey}`,
125
+ },
126
+ compat: {
127
+ supportsStore: false,
128
+ supportsDeveloperRole: false,
129
+ supportsReasoningEffort: false,
130
+ supportsUsageInStreaming: true,
131
+ maxTokensField: "max_tokens",
132
+ requiresToolResultName: false,
133
+ requiresAssistantAfterToolResult: false,
134
+ requiresThinkingAsText: false,
135
+ requiresMistralToolIds: false,
136
+ thinkingFormat: "openai",
137
+ supportsStrictMode: false,
138
+ },
139
+ };
140
+ }
141
+ /**
142
+ * Resolve a model ID to a pi-ai Model object.
143
+ *
144
+ * Supports:
145
+ * - "ollama/deepseek-coder-v2" → Ollama local model
146
+ * - "openrouter/auto" → OpenRouter cloud model
147
+ * - "claude-sonnet-4-6" → standard pi-ai model lookup
148
+ * - Falls back to any available provider's default model
149
+ */
150
+ export function resolveModel(modelId, warnFn) {
151
+ // Ollama models — create synthetic model
152
+ if (modelId.startsWith("ollama/")) {
153
+ return { model: createOllamaModel(modelId), provider: "ollama" };
154
+ }
155
+ // OpenRouter models — create synthetic model
156
+ if (modelId.startsWith("openrouter/")) {
157
+ return { model: createOpenRouterModel(modelId), provider: "openrouter" };
158
+ }
159
+ // AgentRouter models — create synthetic model
160
+ if (modelId.startsWith("agentrouter/")) {
161
+ return { model: createAgentRouterModel(modelId), provider: "agentrouter" };
162
+ }
163
+ // Transparent proxy via OPENAI_BASE_URL
164
+ if (process.env.OPENAI_BASE_URL && !modelId.includes("/")) {
165
+ const apiKey = process.env.OPENAI_API_KEY || "";
166
+ const syntheticModel = {
167
+ id: modelId,
168
+ name: modelId,
169
+ api: "openai-completions",
170
+ provider: "openai",
171
+ baseUrl: process.env.OPENAI_BASE_URL,
172
+ reasoning: false,
173
+ input: ["text"],
174
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
175
+ contextWindow: 128000,
176
+ maxTokens: 4096,
177
+ headers: apiKey
178
+ ? {
179
+ Authorization: `Bearer ${apiKey}`,
180
+ "User-Agent": "OpenCode",
181
+ }
182
+ : {
183
+ "User-Agent": "OpenCode",
184
+ },
185
+ compat: {
186
+ supportsStore: false,
187
+ supportsDeveloperRole: false,
188
+ supportsReasoningEffort: false,
189
+ supportsUsageInStreaming: true,
190
+ maxTokensField: "max_tokens",
191
+ requiresToolResultName: false,
192
+ requiresAssistantAfterToolResult: false,
193
+ requiresThinkingAsText: false,
194
+ requiresMistralToolIds: false,
195
+ thinkingFormat: "openai",
196
+ supportsStrictMode: false,
197
+ },
198
+ };
199
+ return { model: syntheticModel, provider: "openai" };
200
+ }
201
+ // Standard pi-ai model lookup
202
+ const knownProviders = new Set(["anthropic", "openai", "google", "groq", "cerebras", "xai", "openrouter", "mistral"]);
203
+ let model;
204
+ let resolvedProvider = "";
205
+ // Try known providers with API keys first
206
+ for (const provider of getProviders()) {
207
+ if (!knownProviders.has(provider))
208
+ continue;
209
+ if (!getEnvApiKey(provider))
210
+ continue;
211
+ for (const m of getModels(provider)) {
212
+ if (m.id === modelId) {
213
+ model = m;
214
+ resolvedProvider = provider;
215
+ break;
216
+ }
217
+ }
218
+ if (model)
219
+ break;
220
+ }
221
+ // Try unknown providers
222
+ if (!model) {
223
+ for (const provider of getProviders()) {
224
+ if (knownProviders.has(provider))
225
+ continue;
226
+ for (const m of getModels(provider)) {
227
+ if (m.id === modelId) {
228
+ model = m;
229
+ resolvedProvider = provider;
230
+ break;
231
+ }
232
+ }
233
+ if (model)
234
+ break;
235
+ }
236
+ }
237
+ // Fallback: try default model for any provider that has a key
238
+ if (!model) {
239
+ for (const [prov, fallbackId] of Object.entries(DEFAULT_MODELS)) {
240
+ if (!getEnvApiKey(prov))
241
+ continue;
242
+ for (const p of getProviders()) {
243
+ if (p !== prov)
244
+ continue;
245
+ for (const m of getModels(p)) {
246
+ if (m.id === fallbackId) {
247
+ model = m;
248
+ resolvedProvider = prov;
249
+ if (warnFn)
250
+ warnFn(`Using ${fallbackId} (${prov}) — model "${modelId}" not found`);
251
+ break;
252
+ }
253
+ }
254
+ if (model)
255
+ break;
256
+ }
257
+ if (model)
258
+ break;
259
+ }
260
+ }
261
+ if (!model)
262
+ return null;
263
+ return { model, provider: resolvedProvider };
264
+ }
265
+ //# sourceMappingURL=model-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/routing/model-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Model router — auto-selects the best agent + model combination per task.
3
+ *
4
+ * Inspired by Slate's approach: the orchestrator LLM naturally selects agents
5
+ * and models based on task complexity. This module provides a fallback
6
+ * rule-based router for when auto_model_selection is enabled, ensuring
7
+ * cost-efficient defaults even when the orchestrator doesn't explicitly choose.
8
+ *
9
+ * Two routing dimensions:
10
+ * 1. Task complexity (simple/medium/complex) → picks model tier
11
+ * 2. Task slot (execution/search/reasoning/planning) → picks agent + model specialty
12
+ *
13
+ * Two routing modes:
14
+ * 1. Orchestrator-driven (default): The orchestrator prompt teaches the LLM
15
+ * about agent strengths, and the LLM passes agent/model in thread() calls.
16
+ * 2. Auto-routing (auto_model_selection=true): This router overrides the
17
+ * orchestrator's choice with a cost-optimal selection based on task analysis.
18
+ *
19
+ * Enhanced with:
20
+ * - FailureTracker: session-level failure tracking with decay weighting
21
+ * - Success rate weighting: penalizes agents with high failure rates
22
+ * - File pattern matching: boosts agents that historically handle specific file types
23
+ * - Aggregate episodic stats: fallback to best-performing agent per slot
24
+ */
25
+ import type { ModelSlots } from "../config.js";
26
+ import type { SwarmConfig } from "../core/types.js";
27
+ import type { EpisodicMemory } from "../labs/episodic-memory.js";
28
+ export interface AgentCapability {
29
+ name: string;
30
+ /** Cost tier: 1 = cheapest, 5 = most expensive */
31
+ costTier: number;
32
+ /** Speed tier: 1 = fastest, 5 = slowest */
33
+ speedTier: number;
34
+ /** What this agent excels at */
35
+ strengths: string[];
36
+ /** Best model for this agent (provider/model-id format) */
37
+ defaultModel: string;
38
+ /** Cheaper model for simple tasks */
39
+ cheapModel: string;
40
+ /** Premium model for complex tasks */
41
+ premiumModel: string;
42
+ }
43
+ export declare const AGENT_CAPABILITIES: Record<string, AgentCapability>;
44
+ export type TaskComplexity = "simple" | "medium" | "complex";
45
+ /** Simple keyword-based complexity classifier. */
46
+ export declare function classifyTaskComplexity(task: string): TaskComplexity;
47
+ /**
48
+ * Task slots — named categories that map to specialized model/agent combos.
49
+ * Inspired by Slate's model slots (main, subagent, search, reasoning).
50
+ */
51
+ export type TaskSlot = "execution" | "search" | "reasoning" | "planning";
52
+ export declare const DEFAULT_MODEL_SLOTS: ModelSlots;
53
+ /** Classify a task into a named slot based on keyword analysis. */
54
+ export declare function classifyTaskSlot(task: string): TaskSlot;
55
+ export interface FailureRecord {
56
+ agent: string;
57
+ model: string;
58
+ task: string;
59
+ error: string;
60
+ timestamp: number;
61
+ /** Transient errors (rate limit, timeout) decay faster than permanent ones. */
62
+ isTransient: boolean;
63
+ }
64
+ /**
65
+ * Tracks agent/model failures within a session to inform routing decisions.
66
+ *
67
+ * Failure records decay over time — recent failures weigh more heavily.
68
+ * Transient errors (rate limits, timeouts) decay faster than permanent ones.
69
+ */
70
+ export declare class FailureTracker {
71
+ private failures;
72
+ /** Half-life for permanent failure decay (ms). Failures lose half their weight after this. */
73
+ private readonly permanentHalfLifeMs;
74
+ /** Half-life for transient failure decay (ms). Shorter — transient issues resolve quickly. */
75
+ private readonly transientHalfLifeMs;
76
+ constructor(permanentHalfLifeMs?: number, transientHalfLifeMs?: number);
77
+ /**
78
+ * Record a failure for an agent+model pair.
79
+ * Classifies the error as transient or permanent based on pattern matching.
80
+ */
81
+ recordFailure(agent: string, model: string, task: string, error: string): void;
82
+ /**
83
+ * Get the weighted failure rate for an agent+model pair (0-1).
84
+ *
85
+ * Uses exponential decay so recent failures count more than old ones.
86
+ * The rate is capped at 1.0 (effectively: agent is completely unreliable).
87
+ */
88
+ getFailureRate(agent: string, model?: string): number;
89
+ /**
90
+ * Check if an agent has a 100% failure rate (all recent attempts failed,
91
+ * with no significant decay). Used to skip completely broken agents.
92
+ */
93
+ isFullyFailed(agent: string): boolean;
94
+ /** Get all failure records (for debugging/inspection). */
95
+ getFailures(): FailureRecord[];
96
+ /** Get the number of raw (undecayed) failures for an agent. */
97
+ getFailureCount(agent: string): number;
98
+ /** Clear all failure records. */
99
+ clear(): void;
100
+ }
101
+ /**
102
+ * Extract file extensions mentioned in a task description.
103
+ * Returns unique lowercase extensions (e.g., [".ts", ".py"]).
104
+ */
105
+ export declare function extractFileExtensions(task: string): string[];
106
+ export interface RouteResult {
107
+ agent: string;
108
+ model: string;
109
+ slot: TaskSlot;
110
+ reason: string;
111
+ }
112
+ /**
113
+ * Route a task to the best agent + model combination.
114
+ *
115
+ * Logic:
116
+ * 1. Classify task complexity (simple/medium/complex)
117
+ * 2. Classify task slot (execution/search/reasoning/planning)
118
+ * 3. Check for slot-specific model overrides in config
119
+ * 4. Score agents with slot preference bonus
120
+ * 5. Apply failure rate penalty (skip fully-failed agents)
121
+ * 6. Apply file pattern matching bonus from episodic memory
122
+ * 7. Fallback to aggregate episodic stats when no high-confidence match
123
+ * 8. Pick the highest-scoring capable option
124
+ */
125
+ export declare function routeTask(task: string, config: SwarmConfig, memory?: EpisodicMemory, failureTracker?: FailureTracker): Promise<RouteResult>;
126
+ /**
127
+ * Get a description of available agents and their capabilities
128
+ * for inclusion in the orchestrator prompt.
129
+ */
130
+ export declare function describeAvailableAgents(): Promise<string>;