@phi-code-admin/phi-code 0.57.1 โ 0.57.3
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/extensions/phi/init.ts +26 -17
- package/extensions/phi/smart-router.ts +172 -190
- package/package.json +1 -1
package/extensions/phi/init.ts
CHANGED
|
@@ -246,6 +246,7 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
246
246
|
|
|
247
247
|
if (existingResults?.results?.length > 0) {
|
|
248
248
|
const useExisting = await ctx.ui.confirm(
|
|
249
|
+
"Use existing benchmarks?",
|
|
249
250
|
`Found ${existingResults.results.length} existing benchmark results. Use them instead of re-running?`
|
|
250
251
|
);
|
|
251
252
|
if (useExisting) {
|
|
@@ -298,15 +299,18 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
298
299
|
ctx.ui.notify("๐๏ธ Manual mode: assign a model to each task category.\n", "info");
|
|
299
300
|
|
|
300
301
|
const modelList = availableModels.map((m, i) => ` ${i + 1}. ${m}`).join("\n");
|
|
302
|
+
ctx.ui.notify(`Available models:\n${modelList}\n`, "info");
|
|
301
303
|
const assignments: Record<string, { preferred: string; fallback: string }> = {};
|
|
302
304
|
|
|
303
305
|
for (const role of TASK_ROLES) {
|
|
306
|
+
ctx.ui.notify(`\n**${role.label}** โ ${role.desc}\nDefault: ${role.defaultModel}`, "info");
|
|
304
307
|
const input = await ctx.ui.input(
|
|
305
|
-
|
|
308
|
+
`${role.label}`,
|
|
309
|
+
`Model name or # (default: ${role.defaultModel})`
|
|
306
310
|
);
|
|
307
311
|
|
|
308
312
|
let chosen = role.defaultModel;
|
|
309
|
-
const trimmed = input.trim();
|
|
313
|
+
const trimmed = (input ?? "").trim();
|
|
310
314
|
|
|
311
315
|
if (trimmed) {
|
|
312
316
|
// Try as number
|
|
@@ -323,16 +327,17 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
323
327
|
// Fallback selection
|
|
324
328
|
const fallbackDefault = availableModels.find(m => m !== chosen) || chosen;
|
|
325
329
|
const fallbackInput = await ctx.ui.input(
|
|
326
|
-
`Fallback
|
|
330
|
+
`Fallback for ${role.label}`,
|
|
331
|
+
`Fallback model (default: ${fallbackDefault})`
|
|
327
332
|
);
|
|
328
333
|
|
|
329
334
|
let fallback = fallbackDefault;
|
|
330
|
-
if (fallbackInput.trim()) {
|
|
331
|
-
const num = parseInt(fallbackInput.trim());
|
|
335
|
+
if ((fallbackInput ?? "").trim()) {
|
|
336
|
+
const num = parseInt((fallbackInput ?? "").trim());
|
|
332
337
|
if (num >= 1 && num <= availableModels.length) {
|
|
333
338
|
fallback = availableModels[num - 1];
|
|
334
339
|
} else {
|
|
335
|
-
const match = availableModels.find(m => m.toLowerCase().includes(fallbackInput.trim().toLowerCase()));
|
|
340
|
+
const match = availableModels.find(m => m.toLowerCase().includes((fallbackInput ?? "").trim().toLowerCase()));
|
|
336
341
|
if (match) fallback = match;
|
|
337
342
|
}
|
|
338
343
|
}
|
|
@@ -343,15 +348,16 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
343
348
|
|
|
344
349
|
// Default model
|
|
345
350
|
const defaultInput = await ctx.ui.input(
|
|
346
|
-
|
|
351
|
+
"Default model",
|
|
352
|
+
`Model for general tasks (default: ${availableModels[0]})`
|
|
347
353
|
);
|
|
348
354
|
let defaultModel = availableModels[0];
|
|
349
|
-
if (defaultInput.trim()) {
|
|
350
|
-
const num = parseInt(defaultInput.trim());
|
|
355
|
+
if ((defaultInput ?? "").trim()) {
|
|
356
|
+
const num = parseInt((defaultInput ?? "").trim());
|
|
351
357
|
if (num >= 1 && num <= availableModels.length) {
|
|
352
358
|
defaultModel = availableModels[num - 1];
|
|
353
359
|
} else {
|
|
354
|
-
const match = availableModels.find(m => m.toLowerCase().includes(defaultInput.trim().toLowerCase()));
|
|
360
|
+
const match = availableModels.find(m => m.toLowerCase().includes((defaultInput ?? "").trim().toLowerCase()));
|
|
355
361
|
if (match) defaultModel = match;
|
|
356
362
|
}
|
|
357
363
|
}
|
|
@@ -391,16 +397,19 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
391
397
|
ctx.ui.notify(` Total: ${allModels.length} models available\n`, "info");
|
|
392
398
|
|
|
393
399
|
// 2. Choose mode
|
|
400
|
+
ctx.ui.notify("Choose setup mode:\n" +
|
|
401
|
+
" 1. auto โ Use optimal defaults (instant)\n" +
|
|
402
|
+
" 2. benchmark โ Test models first, assign by results (10-15 min)\n" +
|
|
403
|
+
" 3. manual โ Choose each model yourself\n", "info");
|
|
404
|
+
|
|
394
405
|
const modeInput = await ctx.ui.input(
|
|
395
|
-
"
|
|
396
|
-
"
|
|
397
|
-
" 2. benchmark โ Test models with coding tasks, assign by results (10-15 min)\n" +
|
|
398
|
-
" 3. manual โ Choose each model assignment yourself\n\n" +
|
|
399
|
-
"Enter 1, 2, or 3:"
|
|
406
|
+
"Setup mode",
|
|
407
|
+
"1=auto, 2=benchmark, 3=manual"
|
|
400
408
|
);
|
|
401
409
|
|
|
402
|
-
const
|
|
403
|
-
|
|
410
|
+
const modeStr = (modeInput ?? "").trim().toLowerCase();
|
|
411
|
+
const mode = modeStr.startsWith("2") || modeStr.startsWith("b") ? "benchmark"
|
|
412
|
+
: modeStr.startsWith("3") || modeStr.startsWith("m") ? "manual"
|
|
404
413
|
: "auto";
|
|
405
414
|
|
|
406
415
|
ctx.ui.notify(`\n๐ Mode: **${mode}**\n`, "info");
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Smart Router Extension - Intelligent model routing for different task types
|
|
3
3
|
*
|
|
4
|
-
* Analyzes user input
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
4
|
+
* Analyzes user input keywords and suggests the optimal model:
|
|
5
|
+
* - code: implement, create, build, refactor โ qwen3-coder-plus
|
|
6
|
+
* - debug: fix, bug, error, crash โ qwen3-max-2026-01-23
|
|
7
|
+
* - explore: read, analyze, explain, understand โ kimi-k2.5
|
|
8
|
+
* - plan: plan, design, architect, spec โ qwen3-max-2026-01-23
|
|
9
|
+
* - test: test, verify, validate, check โ kimi-k2.5
|
|
10
|
+
* - review: review, audit, quality, security โ qwen3.5-plus
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Features:
|
|
14
|
-
* - Input analysis and model recommendations
|
|
15
|
-
* - Configurable routing rules
|
|
16
|
-
* - User notifications via ctx.ui.notify
|
|
17
|
-
*
|
|
18
|
-
* Usage:
|
|
19
|
-
* 1. Copy to packages/coding-agent/extensions/phi/smart-router.ts
|
|
20
|
-
* 2. Optionally configure via ~/.phi/agent/routing.json
|
|
12
|
+
* Configuration: ~/.phi/agent/routing.json (same format as config/routing.json)
|
|
13
|
+
* Command: /routing โ show config, enable/disable, test, reload
|
|
21
14
|
*/
|
|
22
15
|
|
|
23
16
|
import type { ExtensionAPI } from "phi-code";
|
|
@@ -25,266 +18,255 @@ import { readFile, mkdir, writeFile, access } from "node:fs/promises";
|
|
|
25
18
|
import { join } from "node:path";
|
|
26
19
|
import { homedir } from "node:os";
|
|
27
20
|
|
|
21
|
+
// โโโ Types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
22
|
+
|
|
23
|
+
interface RouteEntry {
|
|
24
|
+
description: string;
|
|
25
|
+
keywords: string[];
|
|
26
|
+
preferredModel: string;
|
|
27
|
+
fallback: string;
|
|
28
|
+
agent: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
28
31
|
interface RoutingConfig {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
models: {
|
|
36
|
-
coder: string;
|
|
37
|
-
reasoning: string;
|
|
38
|
-
fast: string;
|
|
39
|
-
};
|
|
32
|
+
routes: Record<string, RouteEntry>;
|
|
33
|
+
default: { model: string; agent: string | null };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface FullConfig {
|
|
37
|
+
routing: RoutingConfig;
|
|
40
38
|
enabled: boolean;
|
|
41
39
|
notifyOnRecommendation: boolean;
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
// โโโ Defaults (aligned with config/routing.json and default-models.json) โโ
|
|
43
|
+
|
|
44
|
+
const DEFAULT_ROUTING: RoutingConfig = {
|
|
45
|
+
routes: {
|
|
46
|
+
code: {
|
|
47
|
+
description: "Code generation, implementation, refactoring",
|
|
48
|
+
keywords: ["implement", "create", "build", "refactor", "write", "add", "modify", "update", "generate", "code", "develop", "function", "class"],
|
|
49
|
+
preferredModel: "qwen3-coder-plus",
|
|
50
|
+
fallback: "qwen3.5-plus",
|
|
51
|
+
agent: "code",
|
|
52
|
+
},
|
|
53
|
+
debug: {
|
|
54
|
+
description: "Debugging, fixing, error resolution",
|
|
55
|
+
keywords: ["fix", "bug", "error", "debug", "crash", "broken", "failing", "issue", "troubleshoot", "repair", "solve"],
|
|
56
|
+
preferredModel: "qwen3-max-2026-01-23",
|
|
57
|
+
fallback: "qwen3.5-plus",
|
|
58
|
+
agent: "code",
|
|
59
|
+
},
|
|
60
|
+
explore: {
|
|
61
|
+
description: "Code reading, analysis, understanding",
|
|
62
|
+
keywords: ["read", "analyze", "explain", "understand", "find", "search", "look", "show", "what", "how", "explore", "examine"],
|
|
63
|
+
preferredModel: "kimi-k2.5",
|
|
64
|
+
fallback: "glm-4.7",
|
|
65
|
+
agent: "explore",
|
|
66
|
+
},
|
|
67
|
+
plan: {
|
|
68
|
+
description: "Architecture, design, planning",
|
|
69
|
+
keywords: ["plan", "design", "architect", "spec", "structure", "organize", "strategy", "approach", "roadmap"],
|
|
70
|
+
preferredModel: "qwen3-max-2026-01-23",
|
|
71
|
+
fallback: "qwen3.5-plus",
|
|
72
|
+
agent: "plan",
|
|
73
|
+
},
|
|
74
|
+
test: {
|
|
75
|
+
description: "Testing, validation, verification",
|
|
76
|
+
keywords: ["test", "verify", "validate", "check", "assert", "coverage", "unit", "integration", "e2e"],
|
|
77
|
+
preferredModel: "kimi-k2.5",
|
|
78
|
+
fallback: "glm-4.7",
|
|
79
|
+
agent: "test",
|
|
80
|
+
},
|
|
81
|
+
review: {
|
|
82
|
+
description: "Code review, quality assessment",
|
|
83
|
+
keywords: ["review", "audit", "quality", "security", "improve", "optimize", "refine", "critique"],
|
|
84
|
+
preferredModel: "qwen3.5-plus",
|
|
85
|
+
fallback: "qwen3-max-2026-01-23",
|
|
86
|
+
agent: "review",
|
|
87
|
+
},
|
|
50
88
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
fast: "anthropic/claude-haiku"
|
|
89
|
+
default: {
|
|
90
|
+
model: "qwen3.5-plus",
|
|
91
|
+
agent: null,
|
|
55
92
|
},
|
|
56
|
-
enabled: true,
|
|
57
|
-
notifyOnRecommendation: true
|
|
58
93
|
};
|
|
59
94
|
|
|
95
|
+
// โโโ Extension โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
96
|
+
|
|
60
97
|
export default function smartRouterExtension(pi: ExtensionAPI) {
|
|
61
|
-
let config: RoutingConfig = DEFAULT_CONFIG;
|
|
62
98
|
const configDir = join(homedir(), ".phi", "agent");
|
|
63
99
|
const configPath = join(configDir, "routing.json");
|
|
64
100
|
|
|
101
|
+
let config: FullConfig = {
|
|
102
|
+
routing: DEFAULT_ROUTING,
|
|
103
|
+
enabled: true,
|
|
104
|
+
notifyOnRecommendation: true,
|
|
105
|
+
};
|
|
106
|
+
|
|
65
107
|
/**
|
|
66
|
-
* Load routing
|
|
108
|
+
* Load routing config from ~/.phi/agent/routing.json
|
|
67
109
|
*/
|
|
68
110
|
async function loadConfig() {
|
|
69
111
|
try {
|
|
70
112
|
await access(configPath);
|
|
71
|
-
const
|
|
72
|
-
const userConfig = JSON.parse(
|
|
73
|
-
|
|
74
|
-
// Merge with defaults
|
|
75
|
-
config = {
|
|
76
|
-
...DEFAULT_CONFIG,
|
|
77
|
-
...userConfig,
|
|
78
|
-
patterns: { ...DEFAULT_CONFIG.patterns, ...userConfig.patterns },
|
|
79
|
-
models: { ...DEFAULT_CONFIG.models, ...userConfig.models }
|
|
80
|
-
};
|
|
81
|
-
} catch (error) {
|
|
82
|
-
// Config doesn't exist or is invalid, use defaults
|
|
83
|
-
console.log("Using default routing configuration");
|
|
84
|
-
await saveDefaultConfig();
|
|
85
|
-
}
|
|
86
|
-
}
|
|
113
|
+
const text = await readFile(configPath, "utf-8");
|
|
114
|
+
const userConfig = JSON.parse(text);
|
|
87
115
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
// Support both flat format (routes at top level) and wrapped format
|
|
117
|
+
if (userConfig.routes) {
|
|
118
|
+
config.routing = {
|
|
119
|
+
routes: { ...DEFAULT_ROUTING.routes, ...userConfig.routes },
|
|
120
|
+
default: userConfig.default || DEFAULT_ROUTING.default,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (typeof userConfig.enabled === "boolean") config.enabled = userConfig.enabled;
|
|
125
|
+
if (typeof userConfig.notifyOnRecommendation === "boolean") config.notifyOnRecommendation = userConfig.notifyOnRecommendation;
|
|
126
|
+
} catch {
|
|
127
|
+
// No config file โ use defaults, and save them for reference
|
|
128
|
+
try {
|
|
129
|
+
await mkdir(configDir, { recursive: true });
|
|
130
|
+
await writeFile(configPath, JSON.stringify(DEFAULT_ROUTING, null, 2), "utf-8");
|
|
131
|
+
} catch {
|
|
132
|
+
// Can't write, that's fine
|
|
133
|
+
}
|
|
98
134
|
}
|
|
99
135
|
}
|
|
100
136
|
|
|
101
137
|
/**
|
|
102
|
-
* Analyze input text to
|
|
138
|
+
* Analyze input text to classify task type
|
|
103
139
|
*/
|
|
104
|
-
function
|
|
105
|
-
const
|
|
106
|
-
const results: Array<{
|
|
140
|
+
function classifyTask(text: string): { category: string | null; confidence: number; matches: string[]; route: RouteEntry | null } {
|
|
141
|
+
const lower = text.toLowerCase();
|
|
142
|
+
const results: Array<{ category: string; confidence: number; matches: string[]; route: RouteEntry }> = [];
|
|
107
143
|
|
|
108
|
-
|
|
109
|
-
for (const [category, patterns] of Object.entries(config.patterns)) {
|
|
144
|
+
for (const [category, route] of Object.entries(config.routing.routes)) {
|
|
110
145
|
const matches: string[] = [];
|
|
111
|
-
let matchCount = 0;
|
|
112
146
|
|
|
113
|
-
for (const
|
|
114
|
-
if (
|
|
115
|
-
matches.push(
|
|
116
|
-
matchCount++;
|
|
147
|
+
for (const keyword of route.keywords) {
|
|
148
|
+
if (lower.includes(keyword.toLowerCase())) {
|
|
149
|
+
matches.push(keyword);
|
|
117
150
|
}
|
|
118
151
|
}
|
|
119
152
|
|
|
120
|
-
if (
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
matches
|
|
127
|
-
});
|
|
153
|
+
if (matches.length > 0) {
|
|
154
|
+
// Confidence = weighted match ratio
|
|
155
|
+
// More matches = higher confidence, but cap at 95%
|
|
156
|
+
const ratio = matches.length / route.keywords.length;
|
|
157
|
+
const confidence = Math.min(95, Math.round(ratio * 100 + matches.length * 5));
|
|
158
|
+
results.push({ category, confidence, matches, route });
|
|
128
159
|
}
|
|
129
160
|
}
|
|
130
161
|
|
|
131
|
-
// Return the highest confidence match
|
|
132
162
|
if (results.length === 0) {
|
|
133
|
-
return {
|
|
163
|
+
return { category: null, confidence: 0, matches: [], route: null };
|
|
134
164
|
}
|
|
135
165
|
|
|
166
|
+
// Highest confidence wins
|
|
136
167
|
results.sort((a, b) => b.confidence - a.confidence);
|
|
137
168
|
return results[0];
|
|
138
169
|
}
|
|
139
170
|
|
|
140
|
-
|
|
141
|
-
* Get recommended model for task type
|
|
142
|
-
*/
|
|
143
|
-
function getRecommendedModel(taskType: keyof RoutingConfig['patterns'] | null): string | null {
|
|
144
|
-
if (!taskType) return null;
|
|
145
|
-
|
|
146
|
-
switch (taskType) {
|
|
147
|
-
case 'code':
|
|
148
|
-
return config.models.coder;
|
|
149
|
-
case 'debug':
|
|
150
|
-
case 'planning':
|
|
151
|
-
return config.models.reasoning;
|
|
152
|
-
case 'exploration':
|
|
153
|
-
return config.models.fast;
|
|
154
|
-
default:
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
171
|
+
// โโโ Input Event โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
158
172
|
|
|
159
|
-
/**
|
|
160
|
-
* Get task type description
|
|
161
|
-
*/
|
|
162
|
-
function getTaskDescription(taskType: keyof RoutingConfig['patterns'] | null): string {
|
|
163
|
-
switch (taskType) {
|
|
164
|
-
case 'code':
|
|
165
|
-
return 'Code Implementation';
|
|
166
|
-
case 'debug':
|
|
167
|
-
return 'Debugging & Problem Solving';
|
|
168
|
-
case 'exploration':
|
|
169
|
-
return 'Analysis & Understanding';
|
|
170
|
-
case 'planning':
|
|
171
|
-
return 'Planning & Design';
|
|
172
|
-
default:
|
|
173
|
-
return 'General Task';
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Input interceptor for smart routing
|
|
179
|
-
*/
|
|
180
173
|
pi.on("input", async (event, ctx) => {
|
|
181
|
-
// Skip if routing is disabled or this is an extension-generated message
|
|
182
174
|
if (!config.enabled || event.source === "extension") {
|
|
183
175
|
return { action: "continue" };
|
|
184
176
|
}
|
|
185
177
|
|
|
186
|
-
|
|
187
|
-
const analysis = analyzeTaskType(event.text);
|
|
188
|
-
|
|
189
|
-
// Only recommend if we have good confidence (>= 30%)
|
|
190
|
-
if (analysis.type && analysis.confidence >= 30) {
|
|
191
|
-
const recommendedModel = getRecommendedModel(analysis.type);
|
|
192
|
-
const taskDescription = getTaskDescription(analysis.type);
|
|
193
|
-
|
|
194
|
-
if (recommendedModel && config.notifyOnRecommendation) {
|
|
195
|
-
const message = `๐ก Detected: ${taskDescription} (${analysis.confidence.toFixed(0)}% confidence)
|
|
196
|
-
Recommended model: ${recommendedModel}
|
|
197
|
-
Matched patterns: ${analysis.matches.join(", ")}`;
|
|
178
|
+
const result = classifyTask(event.text);
|
|
198
179
|
|
|
199
|
-
|
|
180
|
+
if (result.category && result.confidence >= 25 && result.route) {
|
|
181
|
+
if (config.notifyOnRecommendation) {
|
|
182
|
+
ctx.ui.notify(
|
|
183
|
+
`๐ ${result.route.description} โ \`${result.route.preferredModel}\` (${result.confidence}% | ${result.matches.join(", ")})`,
|
|
184
|
+
"info"
|
|
185
|
+
);
|
|
200
186
|
}
|
|
201
187
|
}
|
|
202
188
|
|
|
203
189
|
return { action: "continue" };
|
|
204
190
|
});
|
|
205
191
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
*/
|
|
192
|
+
// โโโ /routing Command โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
193
|
+
|
|
209
194
|
pi.registerCommand("routing", {
|
|
210
|
-
description: "Show or configure smart routing
|
|
195
|
+
description: "Show or configure smart routing (enable/disable/test/reload)",
|
|
211
196
|
handler: async (args, ctx) => {
|
|
212
|
-
|
|
213
|
-
// Show current configuration
|
|
214
|
-
const statusMessage = `Smart Router Configuration:
|
|
215
|
-
|
|
216
|
-
**Status:** ${config.enabled ? "Enabled" : "Disabled"}
|
|
217
|
-
**Notifications:** ${config.notifyOnRecommendation ? "Enabled" : "Disabled"}
|
|
197
|
+
const arg = args.trim().toLowerCase();
|
|
218
198
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
199
|
+
if (!arg) {
|
|
200
|
+
// Show current config
|
|
201
|
+
let output = `**๐ Smart Router**\n\n`;
|
|
202
|
+
output += `Status: ${config.enabled ? "โ
Enabled" : "โ Disabled"}\n`;
|
|
203
|
+
output += `Notifications: ${config.notifyOnRecommendation ? "On" : "Off"}\n\n`;
|
|
224
204
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
205
|
+
output += `**Routes:**\n`;
|
|
206
|
+
for (const [cat, route] of Object.entries(config.routing.routes)) {
|
|
207
|
+
output += ` **${cat}** โ \`${route.preferredModel}\` (fallback: \`${route.fallback}\`) [agent: ${route.agent}]\n`;
|
|
208
|
+
output += ` Keywords: ${route.keywords.slice(0, 6).join(", ")}${route.keywords.length > 6 ? "..." : ""}\n`;
|
|
209
|
+
}
|
|
210
|
+
output += `\n **default** โ \`${config.routing.default.model}\`\n`;
|
|
230
211
|
|
|
231
|
-
|
|
212
|
+
output += `\nConfig: \`${configPath}\``;
|
|
213
|
+
output += `\nCommands: \`/routing enable|disable|notify-on|notify-off|reload|test\``;
|
|
232
214
|
|
|
233
|
-
ctx.ui.notify(
|
|
215
|
+
ctx.ui.notify(output, "info");
|
|
234
216
|
return;
|
|
235
217
|
}
|
|
236
218
|
|
|
237
|
-
const arg = args.trim().toLowerCase();
|
|
238
|
-
|
|
239
219
|
switch (arg) {
|
|
240
220
|
case "enable":
|
|
241
221
|
config.enabled = true;
|
|
242
|
-
ctx.ui.notify("Smart routing enabled", "info");
|
|
222
|
+
ctx.ui.notify("โ
Smart routing enabled.", "info");
|
|
243
223
|
break;
|
|
244
224
|
case "disable":
|
|
245
225
|
config.enabled = false;
|
|
246
|
-
ctx.ui.notify("Smart routing disabled", "info");
|
|
226
|
+
ctx.ui.notify("โ Smart routing disabled.", "info");
|
|
247
227
|
break;
|
|
248
228
|
case "notify-on":
|
|
249
229
|
config.notifyOnRecommendation = true;
|
|
250
|
-
ctx.ui.notify("Routing notifications enabled", "info");
|
|
230
|
+
ctx.ui.notify("๐ Routing notifications enabled.", "info");
|
|
251
231
|
break;
|
|
252
232
|
case "notify-off":
|
|
253
233
|
config.notifyOnRecommendation = false;
|
|
254
|
-
ctx.ui.notify("Routing notifications disabled", "info");
|
|
234
|
+
ctx.ui.notify("๐ Routing notifications disabled.", "info");
|
|
255
235
|
break;
|
|
256
236
|
case "reload":
|
|
257
237
|
await loadConfig();
|
|
258
|
-
ctx.ui.notify("Routing
|
|
238
|
+
ctx.ui.notify("๐ Routing config reloaded from disk.", "info");
|
|
259
239
|
break;
|
|
260
|
-
case "test":
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
"
|
|
264
|
-
"
|
|
265
|
-
"
|
|
266
|
-
"
|
|
240
|
+
case "test": {
|
|
241
|
+
const tests = [
|
|
242
|
+
"implement a new user authentication system",
|
|
243
|
+
"fix the crash when uploading files larger than 10MB",
|
|
244
|
+
"explain how the middleware chain works",
|
|
245
|
+
"plan the migration from REST to GraphQL",
|
|
246
|
+
"run all unit tests and check coverage",
|
|
247
|
+
"review the PR for security vulnerabilities",
|
|
248
|
+
"what time is it",
|
|
267
249
|
];
|
|
268
|
-
|
|
269
|
-
let
|
|
270
|
-
for (const input of
|
|
271
|
-
const
|
|
272
|
-
const model =
|
|
273
|
-
|
|
250
|
+
|
|
251
|
+
let output = "**๐งช Routing Test:**\n\n";
|
|
252
|
+
for (const input of tests) {
|
|
253
|
+
const result = classifyTask(input);
|
|
254
|
+
const model = result.route?.preferredModel || config.routing.default.model;
|
|
255
|
+
const tag = result.category || "default";
|
|
256
|
+
output += `"${input}"\n โ **${tag}** (${result.confidence}%) โ \`${model}\`\n\n`;
|
|
274
257
|
}
|
|
275
|
-
|
|
276
|
-
ctx.ui.notify(testResults, "info");
|
|
258
|
+
ctx.ui.notify(output, "info");
|
|
277
259
|
break;
|
|
260
|
+
}
|
|
278
261
|
default:
|
|
279
|
-
ctx.ui.notify("Usage:
|
|
262
|
+
ctx.ui.notify("Usage: `/routing [enable|disable|notify-on|notify-off|reload|test]`", "warning");
|
|
280
263
|
}
|
|
281
264
|
},
|
|
282
265
|
});
|
|
283
266
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
*/
|
|
267
|
+
// โโโ Session Start โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
268
|
+
|
|
287
269
|
pi.on("session_start", async (_event, _ctx) => {
|
|
288
270
|
await loadConfig();
|
|
289
271
|
});
|
|
290
|
-
}
|
|
272
|
+
}
|