neuro-cli 4.1.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 +510 -0
- package/dist/advisor/advisor.d.ts +50 -0
- package/dist/advisor/advisor.js +178 -0
- package/dist/agents/base.d.ts +62 -0
- package/dist/agents/base.js +215 -0
- package/dist/agents/orchestrator.d.ts +46 -0
- package/dist/agents/orchestrator.js +192 -0
- package/dist/agents/team.d.ts +51 -0
- package/dist/agents/team.js +210 -0
- package/dist/api/models.d.ts +23 -0
- package/dist/api/models.js +514 -0
- package/dist/api/ollama.d.ts +153 -0
- package/dist/api/ollama.js +751 -0
- package/dist/api/openrouter.d.ts +55 -0
- package/dist/api/openrouter.js +223 -0
- package/dist/commands/commands.d.ts +43 -0
- package/dist/commands/commands.js +308 -0
- package/dist/config/config.d.ts +8 -0
- package/dist/config/config.js +311 -0
- package/dist/context/compaction.d.ts +54 -0
- package/dist/context/compaction.js +251 -0
- package/dist/context/custom-agents.d.ts +107 -0
- package/dist/context/custom-agents.js +397 -0
- package/dist/context/custom-tools.d.ts +120 -0
- package/dist/context/custom-tools.js +564 -0
- package/dist/context/git-checkpoint.d.ts +52 -0
- package/dist/context/git-checkpoint.js +240 -0
- package/dist/context/neuro-md.d.ts +48 -0
- package/dist/context/neuro-md.js +202 -0
- package/dist/context/neuroignore.d.ts +102 -0
- package/dist/context/neuroignore.js +441 -0
- package/dist/context/repo-map.d.ts +38 -0
- package/dist/context/repo-map.js +220 -0
- package/dist/context/skill-standard.d.ts +262 -0
- package/dist/context/skill-standard.js +1156 -0
- package/dist/context/skill-system.d.ts +75 -0
- package/dist/context/skill-system.js +578 -0
- package/dist/context/tree-sitter.d.ts +99 -0
- package/dist/context/tree-sitter.js +1956 -0
- package/dist/core/acp.d.ts +325 -0
- package/dist/core/acp.js +1498 -0
- package/dist/core/api-server.d.ts +143 -0
- package/dist/core/api-server.js +550 -0
- package/dist/core/approval.d.ts +81 -0
- package/dist/core/approval.js +432 -0
- package/dist/core/auto-compact.d.ts +127 -0
- package/dist/core/auto-compact.js +436 -0
- package/dist/core/auto-mode.d.ts +232 -0
- package/dist/core/auto-mode.js +831 -0
- package/dist/core/background-session.d.ts +166 -0
- package/dist/core/background-session.js +696 -0
- package/dist/core/cicd.d.ts +257 -0
- package/dist/core/cicd.js +1443 -0
- package/dist/core/cloud-sync.d.ts +156 -0
- package/dist/core/cloud-sync.js +582 -0
- package/dist/core/code-review.d.ts +132 -0
- package/dist/core/code-review.js +1191 -0
- package/dist/core/completion.d.ts +49 -0
- package/dist/core/completion.js +384 -0
- package/dist/core/context.d.ts +38 -0
- package/dist/core/context.js +144 -0
- package/dist/core/diff-preview.d.ts +35 -0
- package/dist/core/diff-preview.js +173 -0
- package/dist/core/doom-loop.d.ts +51 -0
- package/dist/core/doom-loop.js +179 -0
- package/dist/core/engine.d.ts +183 -0
- package/dist/core/engine.js +942 -0
- package/dist/core/extended-thinking.d.ts +103 -0
- package/dist/core/extended-thinking.js +269 -0
- package/dist/core/fallback.d.ts +54 -0
- package/dist/core/fallback.js +104 -0
- package/dist/core/git-worktree.d.ts +139 -0
- package/dist/core/git-worktree.js +614 -0
- package/dist/core/headless.d.ts +30 -0
- package/dist/core/headless.js +101 -0
- package/dist/core/i18n.d.ts +83 -0
- package/dist/core/i18n.js +739 -0
- package/dist/core/linting.d.ts +129 -0
- package/dist/core/linting.js +699 -0
- package/dist/core/model-router.d.ts +109 -0
- package/dist/core/model-router.js +581 -0
- package/dist/core/multi-model.d.ts +243 -0
- package/dist/core/multi-model.js +1099 -0
- package/dist/core/multi-session.d.ts +144 -0
- package/dist/core/multi-session.js +442 -0
- package/dist/core/multimodal.d.ts +125 -0
- package/dist/core/multimodal.js +286 -0
- package/dist/core/observability.d.ts +93 -0
- package/dist/core/observability.js +737 -0
- package/dist/core/os-sandbox.d.ts +122 -0
- package/dist/core/os-sandbox.js +1193 -0
- package/dist/core/outcome-grading.d.ts +228 -0
- package/dist/core/outcome-grading.js +1123 -0
- package/dist/core/output-styles.d.ts +57 -0
- package/dist/core/output-styles.js +382 -0
- package/dist/core/parallel-agents.d.ts +183 -0
- package/dist/core/parallel-agents.js +563 -0
- package/dist/core/plugin-bundle.d.ts +236 -0
- package/dist/core/plugin-bundle.js +887 -0
- package/dist/core/plugin-sdk.d.ts +139 -0
- package/dist/core/plugin-sdk.js +273 -0
- package/dist/core/prompt-cache.d.ts +163 -0
- package/dist/core/prompt-cache.js +599 -0
- package/dist/core/sandbox.d.ts +127 -0
- package/dist/core/sandbox.js +369 -0
- package/dist/core/scheduled-tasks.d.ts +151 -0
- package/dist/core/scheduled-tasks.js +502 -0
- package/dist/core/security-scanner.d.ts +160 -0
- package/dist/core/security-scanner.js +1494 -0
- package/dist/core/session.d.ts +83 -0
- package/dist/core/session.js +269 -0
- package/dist/core/shell-completion.d.ts +51 -0
- package/dist/core/shell-completion.js +674 -0
- package/dist/core/smart-monitor.d.ts +146 -0
- package/dist/core/smart-monitor.js +1199 -0
- package/dist/core/spec-driven.d.ts +233 -0
- package/dist/core/spec-driven.js +1485 -0
- package/dist/core/spending-warnings.d.ts +123 -0
- package/dist/core/spending-warnings.js +456 -0
- package/dist/core/sub-agent.d.ts +298 -0
- package/dist/core/sub-agent.js +1023 -0
- package/dist/core/telemetry.d.ts +157 -0
- package/dist/core/telemetry.js +412 -0
- package/dist/core/terminal-ux.d.ts +134 -0
- package/dist/core/terminal-ux.js +649 -0
- package/dist/core/testing.d.ts +146 -0
- package/dist/core/testing.js +1200 -0
- package/dist/core/types.d.ts +439 -0
- package/dist/core/types.js +6 -0
- package/dist/core/undo-redo.d.ts +112 -0
- package/dist/core/undo-redo.js +290 -0
- package/dist/core/updater.d.ts +159 -0
- package/dist/core/updater.js +608 -0
- package/dist/core/vim-mode.d.ts +151 -0
- package/dist/core/vim-mode.js +771 -0
- package/dist/core/voice.d.ts +137 -0
- package/dist/core/voice.js +538 -0
- package/dist/core/web-dashboard.d.ts +109 -0
- package/dist/core/web-dashboard.js +484 -0
- package/dist/hooks/hooks.d.ts +74 -0
- package/dist/hooks/hooks.js +160 -0
- package/dist/hooks/llm-evaluator.d.ts +165 -0
- package/dist/hooks/llm-evaluator.js +560 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1186 -0
- package/dist/lsp/lsp-manager.d.ts +63 -0
- package/dist/lsp/lsp-manager.js +351 -0
- package/dist/mcp/client.d.ts +133 -0
- package/dist/mcp/client.js +684 -0
- package/dist/mcp/mcp-apps.d.ts +70 -0
- package/dist/mcp/mcp-apps.js +1007 -0
- package/dist/tools/bash.d.ts +5 -0
- package/dist/tools/bash.js +195 -0
- package/dist/tools/browser.d.ts +92 -0
- package/dist/tools/browser.js +1570 -0
- package/dist/tools/extended.d.ts +6 -0
- package/dist/tools/extended.js +191 -0
- package/dist/tools/file.d.ts +10 -0
- package/dist/tools/file.js +382 -0
- package/dist/tools/github.d.ts +389 -0
- package/dist/tools/github.js +759 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.js +40 -0
- package/dist/tools/memory.d.ts +6 -0
- package/dist/tools/memory.js +197 -0
- package/dist/tools/registry.d.ts +29 -0
- package/dist/tools/registry.js +64 -0
- package/dist/tools/web.d.ts +6 -0
- package/dist/tools/web.js +150 -0
- package/dist/ui/renderer.d.ts +97 -0
- package/dist/ui/renderer.js +279 -0
- package/dist/ui/theme.d.ts +27 -0
- package/dist/ui/theme.js +106 -0
- package/package.json +83 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export type Complexity = 'simple' | 'moderate' | 'complex';
|
|
2
|
+
export type EffortLevel = 'low' | 'medium' | 'high' | 'ultrathink';
|
|
3
|
+
export type TaskCategory = 'code' | 'reasoning' | 'creative' | 'analysis' | 'conversation' | 'debugging' | 'review' | 'refactoring';
|
|
4
|
+
export interface RoutingDecision {
|
|
5
|
+
model: string;
|
|
6
|
+
complexity: Complexity;
|
|
7
|
+
category: TaskCategory;
|
|
8
|
+
effort: EffortLevel;
|
|
9
|
+
estimatedTokens: number;
|
|
10
|
+
reasoning: string;
|
|
11
|
+
alternatives: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface RouterConfig {
|
|
14
|
+
defaultModel: string;
|
|
15
|
+
simpleModel: string;
|
|
16
|
+
moderateModel: string;
|
|
17
|
+
complexModel: string;
|
|
18
|
+
effortModels: Record<EffortLevel, string>;
|
|
19
|
+
categoryOverrides: Partial<Record<TaskCategory, string>>;
|
|
20
|
+
maxTokenBudget: number;
|
|
21
|
+
}
|
|
22
|
+
export interface ModelInfo {
|
|
23
|
+
name: string;
|
|
24
|
+
contextWindow: number;
|
|
25
|
+
maxOutput: number;
|
|
26
|
+
}
|
|
27
|
+
export declare class ModelRouter {
|
|
28
|
+
private config;
|
|
29
|
+
private availableModels;
|
|
30
|
+
private currentEffort;
|
|
31
|
+
private forcedModel;
|
|
32
|
+
constructor(config: RouterConfig, availableModels: Record<string, ModelInfo>);
|
|
33
|
+
/**
|
|
34
|
+
* Route a prompt to the best available model.
|
|
35
|
+
*/
|
|
36
|
+
route(prompt: string, effort?: EffortLevel): RoutingDecision;
|
|
37
|
+
/**
|
|
38
|
+
* Set the default effort level for subsequent routing calls.
|
|
39
|
+
*/
|
|
40
|
+
setEffort(level: EffortLevel): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get the current effort level.
|
|
43
|
+
*/
|
|
44
|
+
getEffort(): EffortLevel;
|
|
45
|
+
/**
|
|
46
|
+
* Force all routing decisions to use a specific model.
|
|
47
|
+
*/
|
|
48
|
+
overrideModel(modelId: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Remove any forced model override.
|
|
51
|
+
*/
|
|
52
|
+
clearOverride(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Classify the task category of a prompt.
|
|
55
|
+
*/
|
|
56
|
+
getCategory(prompt: string): TaskCategory;
|
|
57
|
+
/**
|
|
58
|
+
* Classify the complexity of a prompt.
|
|
59
|
+
*/
|
|
60
|
+
getComplexity(prompt: string): Complexity;
|
|
61
|
+
/**
|
|
62
|
+
* Estimate the number of tokens a prompt will consume.
|
|
63
|
+
* Uses a character-based heuristic (~4 chars per token for English,
|
|
64
|
+
* with adjustments for code-heavy content).
|
|
65
|
+
*/
|
|
66
|
+
estimateTokens(prompt: string): number;
|
|
67
|
+
/**
|
|
68
|
+
* Print a human-readable routing decision to stdout.
|
|
69
|
+
*/
|
|
70
|
+
printDecision(decision: RoutingDecision): void;
|
|
71
|
+
private analyzePrompt;
|
|
72
|
+
/**
|
|
73
|
+
* Score each category based on how many pattern groups match.
|
|
74
|
+
* Each group in CATEGORY_PATTERNS is worth 1 point when at least one
|
|
75
|
+
* pattern in the group matches.
|
|
76
|
+
*/
|
|
77
|
+
private scoreCategories;
|
|
78
|
+
/**
|
|
79
|
+
* Determine the winning category and record indicators.
|
|
80
|
+
*/
|
|
81
|
+
private pickTopCategory;
|
|
82
|
+
/**
|
|
83
|
+
* Score complexity using a weighted combination of:
|
|
84
|
+
* 1. Pattern match signals
|
|
85
|
+
* 2. Prompt length
|
|
86
|
+
* 3. Multi-step indicators
|
|
87
|
+
*/
|
|
88
|
+
private scoreComplexity;
|
|
89
|
+
/**
|
|
90
|
+
* Count the approximate number of distinct steps or sub-tasks in a prompt.
|
|
91
|
+
*/
|
|
92
|
+
private countSteps;
|
|
93
|
+
/**
|
|
94
|
+
* Extract a short snippet from the prompt that matched a pattern,
|
|
95
|
+
* for use as a human-readable indicator.
|
|
96
|
+
*/
|
|
97
|
+
private truncateMatch;
|
|
98
|
+
private selectModel;
|
|
99
|
+
/**
|
|
100
|
+
* Return alternative models that could handle the same task but were not
|
|
101
|
+
* selected as the primary choice.
|
|
102
|
+
*/
|
|
103
|
+
private getAlternatives;
|
|
104
|
+
private buildReasoning;
|
|
105
|
+
private validateConfig;
|
|
106
|
+
}
|
|
107
|
+
export declare const DEFAULT_ROUTER_CONFIG: RouterConfig;
|
|
108
|
+
export declare const DEFAULT_AVAILABLE_MODELS: Record<string, ModelInfo>;
|
|
109
|
+
//# sourceMappingURL=model-router.d.ts.map
|
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// NeuroCLI - Model Router
|
|
3
|
+
// Automatically selects the best model based on task complexity,
|
|
4
|
+
// category, and effort level using local heuristic analysis.
|
|
5
|
+
// ============================================================
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Keyword / pattern tables
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const CATEGORY_PATTERNS = {
|
|
10
|
+
code: [
|
|
11
|
+
/\b(write|create|implement|build|develop|code|program|function|class|method|module|api|endpoint|component|hook|middleware|service|library|package|script|utility|helper|factory|adapter|decorator|singleton|interface|type|enum|struct|trait|impl|abstract)\b/i,
|
|
12
|
+
/\b(generat|scaffold|bootstrap|setup|init|boilerplate|snippet|algorithm|data\s*structure|parse|serialize|deserialize|encode|decode|compile|transpil|bundl)\b/i,
|
|
13
|
+
/\b(react|vue|angular|svelte|next|nuxt|express|fastify|nestjs|django|flask|spring|rails|laravel)\b/i,
|
|
14
|
+
/\b(sql|graphql|rest|grpc|websocket|rpc|crud|orm|migration|schema|query|mutation|subscription)\b/i,
|
|
15
|
+
/\b(typescript|javascript|python|rust|go|java|c\+\+|ruby|swift|kotlin|scala|php|perl|shell|bash)\b/i,
|
|
16
|
+
],
|
|
17
|
+
reasoning: [
|
|
18
|
+
/\b(analy[zs]|evaluat|reason|deduc|infer|logic|propositional|syllogism|premise|conclusion|argument|proof|theorem|lemma)\b/i,
|
|
19
|
+
/\b(why\s+does|how\s+does|what\s+causes|explain\s+why|explain\s+how|causal|correlat|implication|contradiction|paradox)\b/i,
|
|
20
|
+
/\b(compare|contrast|weigh|trade[\s-]?off|pros?\s+and\s+cons?|advantage|disadvantage|merit|drawback|criterion|criteria)\b/i,
|
|
21
|
+
/\b(decide|decision|choose|select\s+between|opt\s+for|rational|optimal|strategy|heuristic|judg[ei]|assess)\b/i,
|
|
22
|
+
/\b(philosoph|ethical|moral|epistem|ontolog|metaphys|dialectic|hypothesis|hypothes[ie]s)\b/i,
|
|
23
|
+
],
|
|
24
|
+
creative: [
|
|
25
|
+
/\b(write|creat|compos|draft|story|poem|poetry|novel|fiction|narrative|tale|fable|myth|lore)\b/i,
|
|
26
|
+
/\b(song|lyric|rap|ballad|haiku|limerick|sonnet|verse|stanza|rhyme)\b/i,
|
|
27
|
+
/\b(creative|imagin|inspir|brainstorm|ideat|invent|original|unique|innovative|artistic|expressive)\b/i,
|
|
28
|
+
/\b(screenplay|dialog|monologu|script|scene|plot|character|protagonist|antagonist|setting|world[\s-]?build)\b/i,
|
|
29
|
+
/\b(marketing|copy|slogan|tagline|headline|pitch|campaign|brand|motto|manifesto)\b/i,
|
|
30
|
+
],
|
|
31
|
+
analysis: [
|
|
32
|
+
/\b(analy[zs]|assess|evaluat|measur|metric|statistic|quantif|quantif|data|dataset|insight|trend|pattern)\b/i,
|
|
33
|
+
/\b(report|dashboard|chart|graph|visuali[zs]|plot|histogram|distribution|correlation|regression|outlier|anomal)\b/i,
|
|
34
|
+
/\b(kpi|roi|conversion|retention|churn|funnel|cohort|segment|benchmark|baseline|variance|deviation)\b/i,
|
|
35
|
+
/\b(survey|questionnaire|feedback|sentiment|opinion|poll|research|study|finding|conclusion|recommendation)\b/i,
|
|
36
|
+
/\b(performance|latency|throughput|bottleneck|profiling|benchmark|load\s*test|stress\s*test|capacity)\b/i,
|
|
37
|
+
],
|
|
38
|
+
conversation: [
|
|
39
|
+
/^(hi|hello|hey|greetings|good\s+(morning|afternoon|evening)|howdy|sup|yo)\b/i,
|
|
40
|
+
/\b(what\s+is|what\s+are|who\s+is|who\s+are|when\s+did|where\s+is|tell\s+me\s+about|explain\s+briefly)\b/i,
|
|
41
|
+
/\b(how\s+do\s+i|how\s+can\s+i|help\s+me|can\s+you|could\s+you|would\s+you|please\s+(help|explain|tell|show))\b/i,
|
|
42
|
+
/\b(thanks?|thank\s+you|appreciate|got\s*it|understood|makes?\s+sense|right|ok|okay|sure|cool|great|nice|awesome)\b/i,
|
|
43
|
+
/\b(chat|talk|discuss|convers|question|answer|curious|wondering)\b/i,
|
|
44
|
+
],
|
|
45
|
+
debugging: [
|
|
46
|
+
/\b(debug|bug|error|issue|problem|crash|exception|traceback|stack\s*trace|fault|failure|faulty)\b/i,
|
|
47
|
+
/\b(fix|repair|patch|resolve|troubleshoot|diagnos|investigat|root\s*cause|bisect|pinpoint|isolate)\b/i,
|
|
48
|
+
/\b(not\s+work|broken|wrong|unexpected|incorrect|misbehav|regression|side\s*effect|glitch|hang|freeze)\b/i,
|
|
49
|
+
/\b(log|stderr|stdout|assert|throw|catch|try|raise|panic|fatal|segfault|overflow|underflow|null\s*pointer|nil)\b/i,
|
|
50
|
+
/\b(reproduce|repro|minimal\s+(repro|example|case)|step\s+to\s+reproduce|stack\s*overflow|memory\s*leak)\b/i,
|
|
51
|
+
],
|
|
52
|
+
review: [
|
|
53
|
+
/\b(review|audit|inspect|examine|check|verify|validat|ensure|confirm|certif|compliance)\b/i,
|
|
54
|
+
/\b(code\s*review|pull\s*request|pr|merge\s*request|diff|change|change\s*set|patch|commit)\b/i,
|
|
55
|
+
/\b(quality|standard|guideline|convention|style|lint|best\s*practice|clean\s*code|solid|dry|kiss)\b/i,
|
|
56
|
+
/\b(secur|vulnerab|exploit|cve|owasp|injection|xss|csrf|sanitize|escape|encrypt|auth|perm)\b/i,
|
|
57
|
+
/\b(performance\s*review|architectur(e|al)\s*review|design\s*review|security\s*review|readability)\b/i,
|
|
58
|
+
],
|
|
59
|
+
refactoring: [
|
|
60
|
+
/\b(refactor|restructur|reorganiz|rearrang|rearchitect|rewrite|overhaul|moderniz|migrate|port)\b/i,
|
|
61
|
+
/\b(clean\s*up|simplif|duplicat|dead\s*code|unused|redundant|consolidat|merge|split|extract|inline)\b/i,
|
|
62
|
+
/\b(design\s*pattern|solid|dry|kiss|yagni|coupling|cohesion|separation\s*of\s*concerns|single\s*responsib)\b/i,
|
|
63
|
+
/\b(rename|rename|move|promote|demote|encapsulat|abstract|generaliz|speciali[zs]|parametri[zs])\b/i,
|
|
64
|
+
/\b(improv(e|ing)|enhanc(e|ing)|optimi[zs]|speed\s*up|reduc(e|ing)|streamlin|declutter|tidy)\b/i,
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
const COMPLEXITY_SIGNALS = {
|
|
68
|
+
simple: {
|
|
69
|
+
patterns: [
|
|
70
|
+
/^(what\s+is|what\s+are|who\s+is|define|explain\s+briefly|list|show\s+me|tell\s+me|give\s+me\s+a)\b/i,
|
|
71
|
+
/\b(simple|basic|quick|easy|short|small|single|one|trivial|minor|tiny|brief)\b/i,
|
|
72
|
+
/\b(hello|hi|thanks|yes|no|ok|sure|done|correct|right|please)\b/i,
|
|
73
|
+
],
|
|
74
|
+
lengthThreshold: 80,
|
|
75
|
+
maxSteps: 1,
|
|
76
|
+
},
|
|
77
|
+
moderate: {
|
|
78
|
+
patterns: [
|
|
79
|
+
/\b(add|modify|update|change|extend|enhance|improve|adjust|configure|customize)\b/i,
|
|
80
|
+
/\b(fix|debug|solve|resolve|handle|implement\s+a|write\s+a|create\s+a)\b/i,
|
|
81
|
+
/\b(test|spec|assert|validate|verify)\b/i,
|
|
82
|
+
/\b(review|check|audit|inspect|compare|evaluate)\b/i,
|
|
83
|
+
/\b(refactor|clean|simplify|optimize|restructure)\b/i,
|
|
84
|
+
],
|
|
85
|
+
lengthThreshold: 300,
|
|
86
|
+
maxSteps: 3,
|
|
87
|
+
},
|
|
88
|
+
complex: {
|
|
89
|
+
patterns: [
|
|
90
|
+
/\b(implement\s+(a\s+)?(full|complete|entire|comprehensive|end[\s-]to[\s-]end|production|scalable|robust))\b/i,
|
|
91
|
+
/\b(build\s+(a\s+)?(system|application|platform|framework|service|architecture|infrastructure|pipeline))\b/i,
|
|
92
|
+
/\b(design\s+(and\s+implement|the\s+architecture|a\s+system|from\s+scratch))\b/i,
|
|
93
|
+
/\b(migrate|migration|port\s+from|rewrite\s+(from|the|entire)|overhaul|modernize)\b/i,
|
|
94
|
+
/\b(multi[\s-]*(step|phase|stage|part|agent|service|module|component)|micro[\s-]*service|distributed)\b/i,
|
|
95
|
+
/\b(orchestrat|coordinat|integrat|synchron[iz]|pipeline|workflow|state\s*machine)\b/i,
|
|
96
|
+
/\b(complex|comprehensive|intricate|sophisticated|elaborate|advanced|enterprise|large[\s-]*scale)\b/i,
|
|
97
|
+
/\b(security\s+(audit|review|hardening)|performance\s+(optim|tuning|profiling)|scalab(ility|le))\b/i,
|
|
98
|
+
],
|
|
99
|
+
lengthThreshold: 500,
|
|
100
|
+
maxSteps: 6,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Step-counting heuristics
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
const STEP_INDICATORS = [
|
|
107
|
+
/\band\b/gi,
|
|
108
|
+
/\bthen\b/gi,
|
|
109
|
+
/\bafter\s+(that|which|complet|finish|done)\b/gi,
|
|
110
|
+
/\bfinally\b/gi,
|
|
111
|
+
/\bnext\b/gi,
|
|
112
|
+
/\bfollowed\s+by\b/gi,
|
|
113
|
+
/\bonce\s+(that|it|complete|done|finish)\b/gi,
|
|
114
|
+
/\bsubsequently\b/gi,
|
|
115
|
+
/\badditionally\b/gi,
|
|
116
|
+
/\bfurthermore\b/gi,
|
|
117
|
+
/\bmoreover\b/gi,
|
|
118
|
+
];
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// ModelRouter
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
export class ModelRouter {
|
|
123
|
+
config;
|
|
124
|
+
availableModels;
|
|
125
|
+
currentEffort = 'medium';
|
|
126
|
+
forcedModel = null;
|
|
127
|
+
// -----------------------------------------------------------------------
|
|
128
|
+
// Construction
|
|
129
|
+
// -----------------------------------------------------------------------
|
|
130
|
+
constructor(config, availableModels) {
|
|
131
|
+
this.config = config;
|
|
132
|
+
this.availableModels = availableModels;
|
|
133
|
+
this.validateConfig();
|
|
134
|
+
}
|
|
135
|
+
// -----------------------------------------------------------------------
|
|
136
|
+
// Public API
|
|
137
|
+
// -----------------------------------------------------------------------
|
|
138
|
+
/**
|
|
139
|
+
* Route a prompt to the best available model.
|
|
140
|
+
*/
|
|
141
|
+
route(prompt, effort) {
|
|
142
|
+
const effectiveEffort = effort ?? this.currentEffort;
|
|
143
|
+
const analysis = this.analyzePrompt(prompt);
|
|
144
|
+
const estimatedTokens = this.estimateTokens(prompt);
|
|
145
|
+
const model = this.selectModel(analysis.complexity, analysis.category, effectiveEffort);
|
|
146
|
+
const alternatives = this.getAlternatives(analysis.complexity, analysis.category);
|
|
147
|
+
const reasoning = this.buildReasoning(analysis, effectiveEffort, model);
|
|
148
|
+
return {
|
|
149
|
+
model,
|
|
150
|
+
complexity: analysis.complexity,
|
|
151
|
+
category: analysis.category,
|
|
152
|
+
effort: effectiveEffort,
|
|
153
|
+
estimatedTokens,
|
|
154
|
+
reasoning,
|
|
155
|
+
alternatives,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Set the default effort level for subsequent routing calls.
|
|
160
|
+
*/
|
|
161
|
+
setEffort(level) {
|
|
162
|
+
this.currentEffort = level;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get the current effort level.
|
|
166
|
+
*/
|
|
167
|
+
getEffort() {
|
|
168
|
+
return this.currentEffort;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Force all routing decisions to use a specific model.
|
|
172
|
+
*/
|
|
173
|
+
overrideModel(modelId) {
|
|
174
|
+
if (!this.availableModels[modelId]) {
|
|
175
|
+
throw new Error(`Cannot override to unknown model "${modelId}". Available: ${Object.keys(this.availableModels).join(', ')}`);
|
|
176
|
+
}
|
|
177
|
+
this.forcedModel = modelId;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Remove any forced model override.
|
|
181
|
+
*/
|
|
182
|
+
clearOverride() {
|
|
183
|
+
this.forcedModel = null;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Classify the task category of a prompt.
|
|
187
|
+
*/
|
|
188
|
+
getCategory(prompt) {
|
|
189
|
+
return this.analyzePrompt(prompt).category;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Classify the complexity of a prompt.
|
|
193
|
+
*/
|
|
194
|
+
getComplexity(prompt) {
|
|
195
|
+
return this.analyzePrompt(prompt).complexity;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Estimate the number of tokens a prompt will consume.
|
|
199
|
+
* Uses a character-based heuristic (~4 chars per token for English,
|
|
200
|
+
* with adjustments for code-heavy content).
|
|
201
|
+
*/
|
|
202
|
+
estimateTokens(prompt) {
|
|
203
|
+
if (prompt.length === 0)
|
|
204
|
+
return 0;
|
|
205
|
+
// Base estimate: ~4 characters per token for typical English text
|
|
206
|
+
let charPerToken = 4;
|
|
207
|
+
// Code-heavy prompts tend to have higher token density
|
|
208
|
+
const codeIndicators = [
|
|
209
|
+
/```[\s\S]*?```/, // fenced code blocks
|
|
210
|
+
/\bfunction\b/, // function keyword
|
|
211
|
+
/\bconst\b|\blet\b|\bvar\b/, // variable declarations
|
|
212
|
+
/[{}()\[\];]/, // braces and brackets
|
|
213
|
+
/=>/, // arrow functions
|
|
214
|
+
/import\s+.+\s+from/, // imports
|
|
215
|
+
];
|
|
216
|
+
const codeSignalCount = codeIndicators.filter(p => p.test(prompt)).length;
|
|
217
|
+
if (codeSignalCount >= 3) {
|
|
218
|
+
charPerToken = 3.2; // code is denser
|
|
219
|
+
}
|
|
220
|
+
else if (codeSignalCount >= 1) {
|
|
221
|
+
charPerToken = 3.6;
|
|
222
|
+
}
|
|
223
|
+
// Whitespace-heavy prompts have lower density
|
|
224
|
+
const whitespaceRatio = (prompt.match(/\s/g) ?? []).length / prompt.length;
|
|
225
|
+
if (whitespaceRatio > 0.4) {
|
|
226
|
+
charPerToken = 4.5;
|
|
227
|
+
}
|
|
228
|
+
const baseTokens = Math.ceil(prompt.length / charPerToken);
|
|
229
|
+
// Add overhead for special tokens (system, role markers, etc.)
|
|
230
|
+
const overhead = 8;
|
|
231
|
+
return baseTokens + overhead;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Print a human-readable routing decision to stdout.
|
|
235
|
+
*/
|
|
236
|
+
printDecision(decision) {
|
|
237
|
+
const border = '-'.repeat(60);
|
|
238
|
+
const lines = [
|
|
239
|
+
border,
|
|
240
|
+
' MODEL ROUTING DECISION',
|
|
241
|
+
border,
|
|
242
|
+
` Model : ${decision.model}`,
|
|
243
|
+
` Complexity : ${decision.complexity}`,
|
|
244
|
+
` Category : ${decision.category}`,
|
|
245
|
+
` Effort : ${decision.effort}`,
|
|
246
|
+
` Est. Tokens : ${decision.estimatedTokens.toLocaleString()}`,
|
|
247
|
+
` Reasoning : ${decision.reasoning}`,
|
|
248
|
+
];
|
|
249
|
+
if (decision.alternatives.length > 0) {
|
|
250
|
+
lines.push(` Alternatives: ${decision.alternatives.join(', ')}`);
|
|
251
|
+
}
|
|
252
|
+
lines.push(border);
|
|
253
|
+
for (const line of lines) {
|
|
254
|
+
console.log(line);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// -----------------------------------------------------------------------
|
|
258
|
+
// Private: prompt analysis
|
|
259
|
+
// -----------------------------------------------------------------------
|
|
260
|
+
analyzePrompt(prompt) {
|
|
261
|
+
const indicators = [];
|
|
262
|
+
// --- Category detection (scored) ---
|
|
263
|
+
const categoryScores = this.scoreCategories(prompt);
|
|
264
|
+
const category = this.pickTopCategory(categoryScores, indicators);
|
|
265
|
+
// --- Complexity detection (scored) ---
|
|
266
|
+
const complexity = this.scoreComplexity(prompt, indicators);
|
|
267
|
+
return { complexity, category, indicators };
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Score each category based on how many pattern groups match.
|
|
271
|
+
* Each group in CATEGORY_PATTERNS is worth 1 point when at least one
|
|
272
|
+
* pattern in the group matches.
|
|
273
|
+
*/
|
|
274
|
+
scoreCategories(prompt) {
|
|
275
|
+
const scores = new Map();
|
|
276
|
+
for (const [cat, patternGroups] of Object.entries(CATEGORY_PATTERNS)) {
|
|
277
|
+
let score = 0;
|
|
278
|
+
for (const pattern of patternGroups) {
|
|
279
|
+
if (pattern.test(prompt)) {
|
|
280
|
+
score += 1;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
scores.set(cat, score);
|
|
284
|
+
}
|
|
285
|
+
return scores;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Determine the winning category and record indicators.
|
|
289
|
+
*/
|
|
290
|
+
pickTopCategory(scores, indicators) {
|
|
291
|
+
let bestCategory = 'conversation';
|
|
292
|
+
let bestScore = 0;
|
|
293
|
+
for (const [cat, score] of scores) {
|
|
294
|
+
if (score > bestScore) {
|
|
295
|
+
bestScore = score;
|
|
296
|
+
bestCategory = cat;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// If nothing matched at all, default to conversation
|
|
300
|
+
if (bestScore === 0) {
|
|
301
|
+
indicators.push('no strong category signals -- defaulting to conversation');
|
|
302
|
+
return 'conversation';
|
|
303
|
+
}
|
|
304
|
+
indicators.push(`category "${bestCategory}" matched with score ${bestScore}`);
|
|
305
|
+
return bestCategory;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Score complexity using a weighted combination of:
|
|
309
|
+
* 1. Pattern match signals
|
|
310
|
+
* 2. Prompt length
|
|
311
|
+
* 3. Multi-step indicators
|
|
312
|
+
*/
|
|
313
|
+
scoreComplexity(prompt, indicators) {
|
|
314
|
+
let simpleScore = 0;
|
|
315
|
+
let moderateScore = 0;
|
|
316
|
+
let complexScore = 0;
|
|
317
|
+
// --- Pattern-based scoring ---
|
|
318
|
+
for (const pattern of COMPLEXITY_SIGNALS.simple.patterns) {
|
|
319
|
+
if (pattern.test(prompt)) {
|
|
320
|
+
simpleScore += 2;
|
|
321
|
+
indicators.push(`simple signal: "${this.truncateMatch(prompt, pattern)}"`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
for (const pattern of COMPLEXITY_SIGNALS.moderate.patterns) {
|
|
325
|
+
if (pattern.test(prompt)) {
|
|
326
|
+
moderateScore += 2;
|
|
327
|
+
indicators.push(`moderate signal: "${this.truncateMatch(prompt, pattern)}"`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
for (const pattern of COMPLEXITY_SIGNALS.complex.patterns) {
|
|
331
|
+
if (pattern.test(prompt)) {
|
|
332
|
+
complexScore += 3;
|
|
333
|
+
indicators.push(`complex signal: "${this.truncateMatch(prompt, pattern)}"`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// --- Length-based scoring ---
|
|
337
|
+
const length = prompt.length;
|
|
338
|
+
if (length <= COMPLEXITY_SIGNALS.simple.lengthThreshold) {
|
|
339
|
+
simpleScore += 1;
|
|
340
|
+
indicators.push(`short prompt (${length} chars)`);
|
|
341
|
+
}
|
|
342
|
+
else if (length <= COMPLEXITY_SIGNALS.moderate.lengthThreshold) {
|
|
343
|
+
moderateScore += 1;
|
|
344
|
+
indicators.push(`medium prompt (${length} chars)`);
|
|
345
|
+
}
|
|
346
|
+
else if (length <= COMPLEXITY_SIGNALS.complex.lengthThreshold) {
|
|
347
|
+
moderateScore += 1;
|
|
348
|
+
complexScore += 1;
|
|
349
|
+
indicators.push(`long prompt (${length} chars)`);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
complexScore += 2;
|
|
353
|
+
indicators.push(`very long prompt (${length} chars)`);
|
|
354
|
+
}
|
|
355
|
+
// --- Step-count scoring ---
|
|
356
|
+
const stepCount = this.countSteps(prompt);
|
|
357
|
+
if (stepCount <= COMPLEXITY_SIGNALS.simple.maxSteps) {
|
|
358
|
+
simpleScore += 1;
|
|
359
|
+
}
|
|
360
|
+
else if (stepCount <= COMPLEXITY_SIGNALS.moderate.maxSteps) {
|
|
361
|
+
moderateScore += 1;
|
|
362
|
+
indicators.push(`multi-step request (${stepCount} steps detected)`);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
complexScore += 2;
|
|
366
|
+
indicators.push(`many-step request (${stepCount} steps detected)`);
|
|
367
|
+
}
|
|
368
|
+
// --- Final decision ---
|
|
369
|
+
const maxScore = Math.max(simpleScore, moderateScore, complexScore);
|
|
370
|
+
// Ties go to the higher complexity (safer default)
|
|
371
|
+
if (complexScore === maxScore)
|
|
372
|
+
return 'complex';
|
|
373
|
+
if (moderateScore === maxScore)
|
|
374
|
+
return 'moderate';
|
|
375
|
+
return 'simple';
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Count the approximate number of distinct steps or sub-tasks in a prompt.
|
|
379
|
+
*/
|
|
380
|
+
countSteps(prompt) {
|
|
381
|
+
let steps = 1; // at least one step
|
|
382
|
+
for (const pattern of STEP_INDICATORS) {
|
|
383
|
+
const matches = prompt.match(pattern);
|
|
384
|
+
if (matches) {
|
|
385
|
+
steps += matches.length;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return steps;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Extract a short snippet from the prompt that matched a pattern,
|
|
392
|
+
* for use as a human-readable indicator.
|
|
393
|
+
*/
|
|
394
|
+
truncateMatch(prompt, pattern) {
|
|
395
|
+
const match = prompt.match(pattern);
|
|
396
|
+
if (!match)
|
|
397
|
+
return '(no match)';
|
|
398
|
+
const text = match[0];
|
|
399
|
+
return text.length > 40 ? text.slice(0, 37) + '...' : text;
|
|
400
|
+
}
|
|
401
|
+
// -----------------------------------------------------------------------
|
|
402
|
+
// Private: model selection
|
|
403
|
+
// -----------------------------------------------------------------------
|
|
404
|
+
selectModel(complexity, category, effort) {
|
|
405
|
+
// 1. User override takes absolute precedence
|
|
406
|
+
if (this.forcedModel) {
|
|
407
|
+
return this.forcedModel;
|
|
408
|
+
}
|
|
409
|
+
// 2. Effort-level model mapping takes precedence when the effort is
|
|
410
|
+
// explicitly above "medium". This lets users escalate thinking
|
|
411
|
+
// without changing the prompt.
|
|
412
|
+
if (effort === 'ultrathink' || effort === 'high') {
|
|
413
|
+
const effortModel = this.config.effortModels[effort];
|
|
414
|
+
if (effortModel && this.availableModels[effortModel]) {
|
|
415
|
+
return effortModel;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// 3. Category-specific override
|
|
419
|
+
const categoryModel = this.config.categoryOverrides[category];
|
|
420
|
+
if (categoryModel && this.availableModels[categoryModel]) {
|
|
421
|
+
return categoryModel;
|
|
422
|
+
}
|
|
423
|
+
// 4. Effort-level mapping for low/medium
|
|
424
|
+
if (effort === 'low' || effort === 'medium') {
|
|
425
|
+
const effortModel = this.config.effortModels[effort];
|
|
426
|
+
if (effortModel && this.availableModels[effortModel]) {
|
|
427
|
+
return effortModel;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
// 5. Complexity-based default
|
|
431
|
+
switch (complexity) {
|
|
432
|
+
case 'simple':
|
|
433
|
+
return this.config.simpleModel;
|
|
434
|
+
case 'moderate':
|
|
435
|
+
return this.config.moderateModel;
|
|
436
|
+
case 'complex':
|
|
437
|
+
return this.config.complexModel;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Return alternative models that could handle the same task but were not
|
|
442
|
+
* selected as the primary choice.
|
|
443
|
+
*/
|
|
444
|
+
getAlternatives(complexity, category) {
|
|
445
|
+
const selected = this.selectModel(complexity, category, this.currentEffort);
|
|
446
|
+
const candidates = new Set();
|
|
447
|
+
// Add complexity-adjacent models
|
|
448
|
+
candidates.add(this.config.simpleModel);
|
|
449
|
+
candidates.add(this.config.moderateModel);
|
|
450
|
+
candidates.add(this.config.complexModel);
|
|
451
|
+
// Add effort models
|
|
452
|
+
for (const model of Object.values(this.config.effortModels)) {
|
|
453
|
+
candidates.add(model);
|
|
454
|
+
}
|
|
455
|
+
// Add category override if present
|
|
456
|
+
const categoryModel = this.config.categoryOverrides[category];
|
|
457
|
+
if (categoryModel) {
|
|
458
|
+
candidates.add(categoryModel);
|
|
459
|
+
}
|
|
460
|
+
// Remove the selected model and any models not in the available set
|
|
461
|
+
candidates.delete(selected);
|
|
462
|
+
for (const candidate of [...candidates]) {
|
|
463
|
+
if (!this.availableModels[candidate]) {
|
|
464
|
+
candidates.delete(candidate);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return [...candidates];
|
|
468
|
+
}
|
|
469
|
+
// -----------------------------------------------------------------------
|
|
470
|
+
// Private: reasoning string
|
|
471
|
+
// -----------------------------------------------------------------------
|
|
472
|
+
buildReasoning(analysis, effort, model) {
|
|
473
|
+
const parts = [];
|
|
474
|
+
if (this.forcedModel) {
|
|
475
|
+
parts.push(`User override forced model to "${this.forcedModel}".`);
|
|
476
|
+
return parts.join(' ');
|
|
477
|
+
}
|
|
478
|
+
parts.push(`Prompt classified as ${analysis.complexity} ${analysis.category} task.`);
|
|
479
|
+
switch (analysis.complexity) {
|
|
480
|
+
case 'simple':
|
|
481
|
+
parts.push('Routed to fast model for quick response.');
|
|
482
|
+
break;
|
|
483
|
+
case 'moderate':
|
|
484
|
+
parts.push('Routed to balanced model for capable response.');
|
|
485
|
+
break;
|
|
486
|
+
case 'complex':
|
|
487
|
+
parts.push('Routed to powerful model for thorough analysis.');
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
if (effort === 'ultrathink') {
|
|
491
|
+
parts.push('Ultrathink mode: using highest-capability model for deep reasoning.');
|
|
492
|
+
}
|
|
493
|
+
else if (effort === 'high') {
|
|
494
|
+
parts.push('High effort: using advanced model for detailed output.');
|
|
495
|
+
}
|
|
496
|
+
else if (effort === 'low') {
|
|
497
|
+
parts.push('Low effort: using fast model for concise response.');
|
|
498
|
+
}
|
|
499
|
+
parts.push(`Selected "${model}".`);
|
|
500
|
+
return parts.join(' ');
|
|
501
|
+
}
|
|
502
|
+
// -----------------------------------------------------------------------
|
|
503
|
+
// Private: config validation
|
|
504
|
+
// -----------------------------------------------------------------------
|
|
505
|
+
validateConfig() {
|
|
506
|
+
const requiredModels = [
|
|
507
|
+
this.config.defaultModel,
|
|
508
|
+
this.config.simpleModel,
|
|
509
|
+
this.config.moderateModel,
|
|
510
|
+
this.config.complexModel,
|
|
511
|
+
];
|
|
512
|
+
for (const modelId of requiredModels) {
|
|
513
|
+
if (!this.availableModels[modelId]) {
|
|
514
|
+
throw new Error(`RouterConfig references model "${modelId}" which is not in the available models list. ` +
|
|
515
|
+
`Available: ${Object.keys(this.availableModels).join(', ')}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
for (const [level, modelId] of Object.entries(this.config.effortModels)) {
|
|
519
|
+
if (!this.availableModels[modelId]) {
|
|
520
|
+
throw new Error(`RouterConfig effortModels.${level} references model "${modelId}" which is not in the available models list. ` +
|
|
521
|
+
`Available: ${Object.keys(this.availableModels).join(', ')}`);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
for (const [category, modelId] of Object.entries(this.config.categoryOverrides)) {
|
|
525
|
+
if (modelId && !this.availableModels[modelId]) {
|
|
526
|
+
throw new Error(`RouterConfig categoryOverrides.${category} references model "${modelId}" which is not in the available models list. ` +
|
|
527
|
+
`Available: ${Object.keys(this.availableModels).join(', ')}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (this.config.maxTokenBudget <= 0) {
|
|
531
|
+
throw new Error('RouterConfig.maxTokenBudget must be a positive integer.');
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
// ---------------------------------------------------------------------------
|
|
536
|
+
// Default configuration factory
|
|
537
|
+
// ---------------------------------------------------------------------------
|
|
538
|
+
export const DEFAULT_ROUTER_CONFIG = {
|
|
539
|
+
defaultModel: 'anthropic/claude-sonnet-4',
|
|
540
|
+
simpleModel: 'google/gemini-2.0-flash-001',
|
|
541
|
+
moderateModel: 'anthropic/claude-sonnet-4',
|
|
542
|
+
complexModel: 'anthropic/claude-opus-4',
|
|
543
|
+
effortModels: {
|
|
544
|
+
low: 'google/gemini-2.0-flash-001',
|
|
545
|
+
medium: 'anthropic/claude-sonnet-4',
|
|
546
|
+
high: 'anthropic/claude-opus-4',
|
|
547
|
+
ultrathink: 'openai/o3',
|
|
548
|
+
},
|
|
549
|
+
categoryOverrides: {
|
|
550
|
+
code: 'anthropic/claude-sonnet-4',
|
|
551
|
+
reasoning: 'openai/o3',
|
|
552
|
+
creative: 'anthropic/claude-sonnet-4',
|
|
553
|
+
debugging: 'anthropic/claude-sonnet-4',
|
|
554
|
+
review: 'anthropic/claude-sonnet-4',
|
|
555
|
+
refactoring: 'anthropic/claude-sonnet-4',
|
|
556
|
+
},
|
|
557
|
+
maxTokenBudget: 200_000,
|
|
558
|
+
};
|
|
559
|
+
export const DEFAULT_AVAILABLE_MODELS = {
|
|
560
|
+
'google/gemini-2.0-flash-001': {
|
|
561
|
+
name: 'Gemini 2.0 Flash',
|
|
562
|
+
contextWindow: 1_048_576,
|
|
563
|
+
maxOutput: 8_192,
|
|
564
|
+
},
|
|
565
|
+
'anthropic/claude-sonnet-4': {
|
|
566
|
+
name: 'Claude Sonnet 4',
|
|
567
|
+
contextWindow: 200_000,
|
|
568
|
+
maxOutput: 16_384,
|
|
569
|
+
},
|
|
570
|
+
'anthropic/claude-opus-4': {
|
|
571
|
+
name: 'Claude Opus 4',
|
|
572
|
+
contextWindow: 200_000,
|
|
573
|
+
maxOutput: 32_000,
|
|
574
|
+
},
|
|
575
|
+
'openai/o3': {
|
|
576
|
+
name: 'OpenAI o3',
|
|
577
|
+
contextWindow: 200_000,
|
|
578
|
+
maxOutput: 100_000,
|
|
579
|
+
},
|
|
580
|
+
};
|
|
581
|
+
//# sourceMappingURL=model-router.js.map
|