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.
- package/LICENSE +21 -0
- package/README.md +260 -0
- package/bin/mcp.mjs +61 -0
- package/bin/swarm.mjs +45 -0
- package/dist/agents/aider.d.ts +12 -0
- package/dist/agents/aider.js +192 -0
- package/dist/agents/aider.js.map +1 -0
- package/dist/agents/claude-code.d.ts +9 -0
- package/dist/agents/claude-code.js +236 -0
- package/dist/agents/claude-code.js.map +1 -0
- package/dist/agents/codex.d.ts +14 -0
- package/dist/agents/codex.js +203 -0
- package/dist/agents/codex.js.map +1 -0
- package/dist/agents/direct-llm.d.ts +22 -0
- package/dist/agents/direct-llm.js +254 -0
- package/dist/agents/direct-llm.js.map +1 -0
- package/dist/agents/mock.d.ts +10 -0
- package/dist/agents/mock.js +170 -0
- package/dist/agents/mock.js.map +1 -0
- package/dist/agents/opencode.d.ts +23 -0
- package/dist/agents/opencode.js +631 -0
- package/dist/agents/opencode.js.map +1 -0
- package/dist/agents/provider.d.ts +11 -0
- package/dist/agents/provider.js +31 -0
- package/dist/agents/provider.js.map +1 -0
- package/dist/compression/compressor.d.ts +28 -0
- package/dist/compression/compressor.js +268 -0
- package/dist/compression/compressor.js.map +1 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.js +172 -0
- package/dist/config.js.map +1 -0
- package/dist/contextos/loader.d.ts +46 -0
- package/dist/contextos/loader.js +120 -0
- package/dist/contextos/loader.js.map +1 -0
- package/dist/contextos/selector.d.ts +46 -0
- package/dist/contextos/selector.js +80 -0
- package/dist/contextos/selector.js.map +1 -0
- package/dist/core/action-dispatcher.d.ts +15 -0
- package/dist/core/action-dispatcher.js +28 -0
- package/dist/core/action-dispatcher.js.map +1 -0
- package/dist/core/action-schema.d.ts +72 -0
- package/dist/core/action-schema.js +86 -0
- package/dist/core/action-schema.js.map +1 -0
- package/dist/core/repl-interface.d.ts +48 -0
- package/dist/core/repl-interface.js +5 -0
- package/dist/core/repl-interface.js.map +1 -0
- package/dist/core/repl.d.ts +59 -0
- package/dist/core/repl.js +353 -0
- package/dist/core/repl.js.map +1 -0
- package/dist/core/rlm.d.ts +65 -0
- package/dist/core/rlm.js +564 -0
- package/dist/core/rlm.js.map +1 -0
- package/dist/core/runtime.py +470 -0
- package/dist/core/types.d.ts +265 -0
- package/dist/core/types.js +19 -0
- package/dist/core/types.js.map +1 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.js +75 -0
- package/dist/env.js.map +1 -0
- package/dist/hooks/runner.d.ts +43 -0
- package/dist/hooks/runner.js +173 -0
- package/dist/hooks/runner.js.map +1 -0
- package/dist/labs/cli.d.ts +15 -0
- package/dist/labs/cli.js +295 -0
- package/dist/labs/cli.js.map +1 -0
- package/dist/labs/episodic-memory.d.ts +132 -0
- package/dist/labs/episodic-memory.js +391 -0
- package/dist/labs/episodic-memory.js.map +1 -0
- package/dist/labs/interactive-swarm.d.ts +20 -0
- package/dist/labs/interactive-swarm.js +1173 -0
- package/dist/labs/interactive-swarm.js.map +1 -0
- package/dist/labs/interactive.d.ts +10 -0
- package/dist/labs/interactive.js +2099 -0
- package/dist/labs/interactive.js.map +1 -0
- package/dist/labs/ts-analyzer.d.ts +74 -0
- package/dist/labs/ts-analyzer.js +379 -0
- package/dist/labs/ts-analyzer.js.map +1 -0
- package/dist/labs/viewer.d.ts +12 -0
- package/dist/labs/viewer.js +1284 -0
- package/dist/labs/viewer.js.map +1 -0
- package/dist/main.d.ts +15 -0
- package/dist/main.js +247 -0
- package/dist/main.js.map +1 -0
- package/dist/mcp/server.d.ts +16 -0
- package/dist/mcp/server.js +192775 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/session.d.ts +117 -0
- package/dist/mcp/session.js +450 -0
- package/dist/mcp/session.js.map +1 -0
- package/dist/mcp/state.d.ts +42 -0
- package/dist/mcp/state.js +537 -0
- package/dist/mcp/state.js.map +1 -0
- package/dist/mcp/tools/contextos.d.ts +17 -0
- package/dist/mcp/tools/contextos.js +583 -0
- package/dist/mcp/tools/contextos.js.map +1 -0
- package/dist/mcp/tools.d.ts +15 -0
- package/dist/mcp/tools.js +393 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/orchestration/reviewer-gate.d.ts +43 -0
- package/dist/orchestration/reviewer-gate.js +280 -0
- package/dist/orchestration/reviewer-gate.js.map +1 -0
- package/dist/orchestration/reviewer-prompt.d.ts +18 -0
- package/dist/orchestration/reviewer-prompt.js +67 -0
- package/dist/orchestration/reviewer-prompt.js.map +1 -0
- package/dist/orchestration/verification-runner.d.ts +53 -0
- package/dist/orchestration/verification-runner.js +352 -0
- package/dist/orchestration/verification-runner.js.map +1 -0
- package/dist/plugins/adapter.d.ts +11 -0
- package/dist/plugins/adapter.js +11 -0
- package/dist/plugins/adapter.js.map +1 -0
- package/dist/plugins/core/archive.d.ts +9 -0
- package/dist/plugins/core/archive.js +128 -0
- package/dist/plugins/core/archive.js.map +1 -0
- package/dist/plugins/core/digest.d.ts +11 -0
- package/dist/plugins/core/digest.js +70 -0
- package/dist/plugins/core/digest.js.map +1 -0
- package/dist/plugins/core/grants.d.ts +22 -0
- package/dist/plugins/core/grants.js +90 -0
- package/dist/plugins/core/grants.js.map +1 -0
- package/dist/plugins/core/index.d.ts +10 -0
- package/dist/plugins/core/index.js +11 -0
- package/dist/plugins/core/index.js.map +1 -0
- package/dist/plugins/core/pinning.d.ts +15 -0
- package/dist/plugins/core/pinning.js +86 -0
- package/dist/plugins/core/pinning.js.map +1 -0
- package/dist/plugins/core/types.d.ts +105 -0
- package/dist/plugins/core/types.js +22 -0
- package/dist/plugins/core/types.js.map +1 -0
- package/dist/plugins/core/updater.d.ts +16 -0
- package/dist/plugins/core/updater.js +64 -0
- package/dist/plugins/core/updater.js.map +1 -0
- package/dist/plugins/loader.d.ts +65 -0
- package/dist/plugins/loader.js +110 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/prompts/orchestrator.d.ts +6 -0
- package/dist/prompts/orchestrator.js +114 -0
- package/dist/prompts/orchestrator.js.map +1 -0
- package/dist/routing/model-resolver.d.ts +27 -0
- package/dist/routing/model-resolver.js +265 -0
- package/dist/routing/model-resolver.js.map +1 -0
- package/dist/routing/model-router.d.ts +130 -0
- package/dist/routing/model-router.js +515 -0
- package/dist/routing/model-router.js.map +1 -0
- package/dist/runtime/attestations.cjs +260 -0
- package/dist/runtime/reviewer-pipeline.cjs +319 -0
- package/dist/runtime/sandbox.cjs +468 -0
- package/dist/runtime/state-machine.cjs +885 -0
- package/dist/runtime/thread-store.cjs +175 -0
- package/dist/runtime/transactional-git.cjs +315 -0
- package/dist/runtime/verification-pipeline.cjs +435 -0
- package/dist/sandbox/execution.d.ts +165 -0
- package/dist/sandbox/execution.js +497 -0
- package/dist/sandbox/execution.js.map +1 -0
- package/dist/security/file-policy.d.ts +22 -0
- package/dist/security/file-policy.js +53 -0
- package/dist/security/file-policy.js.map +1 -0
- package/dist/security/repository-boundary.d.ts +21 -0
- package/dist/security/repository-boundary.js +119 -0
- package/dist/security/repository-boundary.js.map +1 -0
- package/dist/security/secret-filter.d.ts +36 -0
- package/dist/security/secret-filter.js +149 -0
- package/dist/security/secret-filter.js.map +1 -0
- package/dist/swarm.d.ts +14 -0
- package/dist/swarm.js +624 -0
- package/dist/swarm.js.map +1 -0
- package/dist/threads/cache.d.ts +64 -0
- package/dist/threads/cache.js +241 -0
- package/dist/threads/cache.js.map +1 -0
- package/dist/threads/manager.d.ts +94 -0
- package/dist/threads/manager.js +914 -0
- package/dist/threads/manager.js.map +1 -0
- package/dist/ui/banner.d.ts +14 -0
- package/dist/ui/banner.js +42 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/dashboard.d.ts +33 -0
- package/dist/ui/dashboard.js +135 -0
- package/dist/ui/dashboard.js.map +1 -0
- package/dist/ui/index.d.ts +11 -0
- package/dist/ui/index.js +12 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/log.d.ts +39 -0
- package/dist/ui/log.js +126 -0
- package/dist/ui/log.js.map +1 -0
- package/dist/ui/onboarding.d.ts +14 -0
- package/dist/ui/onboarding.js +755 -0
- package/dist/ui/onboarding.js.map +1 -0
- package/dist/ui/run-log.d.ts +50 -0
- package/dist/ui/run-log.js +60 -0
- package/dist/ui/run-log.js.map +1 -0
- package/dist/ui/spinner.d.ts +41 -0
- package/dist/ui/spinner.js +172 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/streaming-feed.d.ts +72 -0
- package/dist/ui/streaming-feed.js +386 -0
- package/dist/ui/streaming-feed.js.map +1 -0
- package/dist/ui/summary.d.ts +18 -0
- package/dist/ui/summary.js +113 -0
- package/dist/ui/summary.js.map +1 -0
- package/dist/ui/text-input.d.ts +19 -0
- package/dist/ui/text-input.js +266 -0
- package/dist/ui/text-input.js.map +1 -0
- package/dist/ui/theme.d.ts +63 -0
- package/dist/ui/theme.js +97 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/utils/command-exists.d.ts +11 -0
- package/dist/utils/command-exists.js +41 -0
- package/dist/utils/command-exists.js.map +1 -0
- package/dist/utils/process-security.d.ts +19 -0
- package/dist/utils/process-security.js +90 -0
- package/dist/utils/process-security.js.map +1 -0
- package/dist/utils/rolling-buffer.d.ts +16 -0
- package/dist/utils/rolling-buffer.js +30 -0
- package/dist/utils/rolling-buffer.js.map +1 -0
- package/dist/utils/safe-spawn.d.ts +13 -0
- package/dist/utils/safe-spawn.js +49 -0
- package/dist/utils/safe-spawn.js.map +1 -0
- package/dist/worktree/manager.d.ts +69 -0
- package/dist/worktree/manager.js +593 -0
- package/dist/worktree/manager.js.map +1 -0
- package/dist/worktree/merge.d.ts +58 -0
- package/dist/worktree/merge.js +389 -0
- package/dist/worktree/merge.js.map +1 -0
- 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>;
|