@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.
@@ -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
- `**${role.label}** โ€” ${role.desc}\nDefault: ${role.defaultModel}\n\nAvailable models:\n${modelList}\n\nEnter model name or number (Enter for default):`
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 model for ${role.label}? (Enter for ${fallbackDefault}):`
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
- `Default model for general tasks?\nAvailable:\n${modelList}\n\nEnter model name or number (Enter for ${availableModels[0]}):`
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
- "Choose setup mode:\n\n" +
396
- " 1. auto โ€” Use optimal defaults from public rankings (instant)\n" +
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 mode = modeInput.trim().startsWith("2") || modeInput.trim().toLowerCase().startsWith("b") ? "benchmark"
403
- : modeInput.trim().startsWith("3") || modeInput.trim().toLowerCase().startsWith("m") ? "manual"
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 to suggest the most appropriate model for the task:
5
- * - Code tasks (implement, create, refactor, build) โ†’ coder model
6
- * - Debug tasks (fix, bug, error, debug) โ†’ reasoning model
7
- * - Exploration tasks (read, analyze, explain, understand) โ†’ fast model
8
- * - Planning tasks (plan, design, architect, spec) โ†’ reasoning model
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
- * Reads configuration from ~/.phi/agent/routing.json if available.
11
- * Currently only notifies user of recommendations - automatic switching to be added later.
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
- patterns: {
30
- code: string[];
31
- debug: string[];
32
- exploration: string[];
33
- planning: string[];
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
- const DEFAULT_CONFIG: RoutingConfig = {
45
- patterns: {
46
- code: ["implement", "create", "build", "refactor", "code", "write", "develop", "generate"],
47
- debug: ["fix", "bug", "error", "debug", "troubleshoot", "repair", "solve", "issue"],
48
- exploration: ["read", "analyze", "explain", "understand", "explore", "examine", "review", "what is"],
49
- planning: ["plan", "design", "architect", "spec", "strategy", "approach", "organize", "structure"]
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
- models: {
52
- coder: "anthropic/claude-sonnet-3.5",
53
- reasoning: "anthropic/claude-opus",
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 configuration
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 configText = await readFile(configPath, 'utf-8');
72
- const userConfig = JSON.parse(configText) as Partial<RoutingConfig>;
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
- * Save default configuration file
90
- */
91
- async function saveDefaultConfig() {
92
- try {
93
- await mkdir(configDir, { recursive: true });
94
- await writeFile(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2), 'utf-8');
95
- console.log(`Created default routing config at ${configPath}`);
96
- } catch (error) {
97
- console.warn("Failed to save default routing config:", error);
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 determine task type
138
+ * Analyze input text to classify task type
103
139
  */
104
- function analyzeTaskType(text: string): { type: keyof RoutingConfig['patterns'] | null; confidence: number; matches: string[] } {
105
- const normalizedText = text.toLowerCase();
106
- const results: Array<{ type: keyof RoutingConfig['patterns']; confidence: number; matches: string[] }> = [];
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
- // Check each pattern category
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 pattern of patterns) {
114
- if (normalizedText.includes(pattern.toLowerCase())) {
115
- matches.push(pattern);
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 (matchCount > 0) {
121
- // Calculate confidence based on match count and pattern length
122
- const confidence = (matchCount / patterns.length) * 100;
123
- results.push({
124
- type: category as keyof RoutingConfig['patterns'],
125
- confidence,
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 { type: null, confidence: 0, matches: [] };
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
- // Analyze the input
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
- ctx.ui.notify(message, "info");
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
- * Register routing configuration command
208
- */
192
+ // โ”€โ”€โ”€ /routing Command โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
193
+
209
194
  pi.registerCommand("routing", {
210
- description: "Show or configure smart routing settings",
195
+ description: "Show or configure smart routing (enable/disable/test/reload)",
211
196
  handler: async (args, ctx) => {
212
- if (!args.trim()) {
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
- **Model Assignments:**
220
- - Code tasks: ${config.models.coder}
221
- - Debug tasks: ${config.models.reasoning}
222
- - Exploration: ${config.models.fast}
223
- - Planning: ${config.models.reasoning}
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
- **Pattern Matching:**
226
- - Code: ${config.patterns.code.join(", ")}
227
- - Debug: ${config.patterns.debug.join(", ")}
228
- - Exploration: ${config.patterns.exploration.join(", ")}
229
- - Planning: ${config.patterns.planning.join(", ")}
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
- Config file: ${configPath}`;
212
+ output += `\nConfig: \`${configPath}\``;
213
+ output += `\nCommands: \`/routing enable|disable|notify-on|notify-off|reload|test\``;
232
214
 
233
- ctx.ui.notify(statusMessage, "info");
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 configuration reloaded", "info");
238
+ ctx.ui.notify("๐Ÿ”„ Routing config reloaded from disk.", "info");
259
239
  break;
260
- case "test":
261
- // Test mode - show what would be recommended for different inputs
262
- const testInputs = [
263
- "implement a new feature",
264
- "fix this bug",
265
- "explain how this works",
266
- "plan the system architecture"
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 testResults = "**Routing Test Results:**\n\n";
270
- for (const input of testInputs) {
271
- const analysis = analyzeTaskType(input);
272
- const model = getRecommendedModel(analysis.type);
273
- testResults += `"${input}" โ†’ ${analysis.type || 'none'} (${analysis.confidence.toFixed(0)}%) โ†’ ${model || 'default'}\n`;
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: /routing [enable|disable|notify-on|notify-off|reload|test]", "warning");
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
- * Load configuration on session start
286
- */
267
+ // โ”€โ”€โ”€ Session Start โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
268
+
287
269
  pi.on("session_start", async (_event, _ctx) => {
288
270
  await loadConfig();
289
271
  });
290
- }
272
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phi-code-admin/phi-code",
3
- "version": "0.57.1",
3
+ "version": "0.57.3",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {