@phi-code-admin/phi-code 0.75.5 → 0.75.7
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/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +10 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +10 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/extensions/phi/init.ts +34 -16
- package/extensions/phi/setup.ts +18 -8
- package/extensions/phi/smart-router.ts +63 -19
- package/package.json +1 -1
package/extensions/phi/init.ts
CHANGED
|
@@ -369,14 +369,25 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
369
369
|
await writeModelsConfig(config);
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
-
// ─── Manual model assignment (one model per
|
|
372
|
+
// ─── Manual model assignment (one model per orchestration role) ─────
|
|
373
|
+
//
|
|
374
|
+
// As of 0.75.6, `/phi-init` ONLY configures orchestration role models
|
|
375
|
+
// (used by `/plan` and the orchestrator). The chat default model is
|
|
376
|
+
// owned exclusively by `/model` and persisted via the settings manager.
|
|
377
|
+
// We intentionally do NOT ask "Default model" here — that would override
|
|
378
|
+
// the user's `/model` choice on every routing decision.
|
|
373
379
|
|
|
374
380
|
async function manualMode(
|
|
375
381
|
availableModels: string[],
|
|
376
382
|
ctx: any,
|
|
377
383
|
): Promise<Record<string, { preferred: string; fallback: string }>> {
|
|
378
|
-
ctx.ui.notify(
|
|
379
|
-
|
|
384
|
+
ctx.ui.notify(
|
|
385
|
+
"Assign a model to each orchestration role.\n" +
|
|
386
|
+
"These models are used by `/plan` and the orchestrator — NOT by normal chat.\n" +
|
|
387
|
+
"The chat default model is controlled via `/model` (and stays sticky across prompts).\n",
|
|
388
|
+
"info",
|
|
389
|
+
);
|
|
390
|
+
const modelOptions = ["default (use current chat model)", ...availableModels];
|
|
380
391
|
const assignments: Record<string, { preferred: string; fallback: string }> = {};
|
|
381
392
|
|
|
382
393
|
for (const role of TASK_ROLES) {
|
|
@@ -391,9 +402,12 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
391
402
|
ctx.ui.notify(` ${role.label}: ${preferredModel} (fallback: ${fallback})`, "info");
|
|
392
403
|
}
|
|
393
404
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
assignments["default"] = {
|
|
405
|
+
// Orchestrator fallback (used only when a specific route has no model).
|
|
406
|
+
// This is NOT the chat default — `/model` controls that.
|
|
407
|
+
assignments["default"] = {
|
|
408
|
+
preferred: "default",
|
|
409
|
+
fallback: availableModels[0] || "default",
|
|
410
|
+
};
|
|
397
411
|
return assignments;
|
|
398
412
|
}
|
|
399
413
|
|
|
@@ -505,14 +519,14 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
505
519
|
handler: async (_args, ctx) => {
|
|
506
520
|
try {
|
|
507
521
|
ctx.ui.notify(
|
|
508
|
-
"
|
|
509
|
-
"
|
|
510
|
-
"
|
|
511
|
-
"This
|
|
522
|
+
"`/phi-init` configures **orchestration** roles only (Code / Debug / Plan / Explore / " +
|
|
523
|
+
"Test / Review — used by `/plan` and the orchestrator).\n\n" +
|
|
524
|
+
"The **chat default model** is owned exclusively by `/model` and stays sticky across " +
|
|
525
|
+
"prompts. This wizard will NOT change it.",
|
|
512
526
|
"info",
|
|
513
527
|
);
|
|
514
528
|
|
|
515
|
-
ctx.ui.notify(" Phi Code Setup Wizard", "info");
|
|
529
|
+
ctx.ui.notify(" Phi Code Setup Wizard (orchestration roles)", "info");
|
|
516
530
|
|
|
517
531
|
// 1. Detect providers (env vars + local servers + previously saved keys)
|
|
518
532
|
ctx.ui.notify("Detecting providers...\n", "info");
|
|
@@ -619,17 +633,21 @@ _Edit this file to customize Phi Code's behavior for your project._
|
|
|
619
633
|
ctx.ui.notify(` Config: ${agentDir}`, "info");
|
|
620
634
|
ctx.ui.notify(` Memory: ${memoryDir}`, "info");
|
|
621
635
|
ctx.ui.notify(` Agents: ${agentsDir}`, "info");
|
|
622
|
-
ctx.ui.notify("\
|
|
636
|
+
ctx.ui.notify("\nOrchestration role assignments (used by `/plan`):", "info");
|
|
623
637
|
for (const role of TASK_ROLES) {
|
|
624
638
|
const a = assignments[role.key];
|
|
625
639
|
ctx.ui.notify(` ${role.label}: \`${a.preferred}\` (fallback: \`${a.fallback}\`)`, "info");
|
|
626
640
|
}
|
|
627
|
-
ctx.ui.notify(
|
|
641
|
+
ctx.ui.notify(
|
|
642
|
+
"\nChat default model: use `/model` (this wizard does NOT change the chat default).",
|
|
643
|
+
"info",
|
|
644
|
+
);
|
|
628
645
|
ctx.ui.notify("\nNext steps:", "info");
|
|
646
|
+
ctx.ui.notify(" - `/model` to pick the chat default model (sticky across prompts)", "info");
|
|
647
|
+
ctx.ui.notify(" - `/plan <description>` to run the orchestrator with the roles above", "info");
|
|
648
|
+
ctx.ui.notify(" - `/routing` to inspect the route table (auto-switch is OFF by default)", "info");
|
|
649
|
+
ctx.ui.notify(" - `/models refresh` to re-fetch the live model catalog", "info");
|
|
629
650
|
ctx.ui.notify(" - Edit `~/.phi/memory/AGENTS.md` with your project instructions", "info");
|
|
630
|
-
ctx.ui.notify(" - Run `/agents` to see available sub-agents", "info");
|
|
631
|
-
ctx.ui.notify(" - Run `/skills` to see available skills", "info");
|
|
632
|
-
ctx.ui.notify(" - Run `/models refresh` to re-fetch the model catalog", "info");
|
|
633
651
|
ctx.ui.notify(" - Start coding!\n", "info");
|
|
634
652
|
} catch (error) {
|
|
635
653
|
const message = error instanceof Error ? error.message : String(error);
|
package/extensions/phi/setup.ts
CHANGED
|
@@ -199,8 +199,7 @@ function buildStatusWidget(
|
|
|
199
199
|
lines.push(` ${icon} ${p.displayName}${note}`);
|
|
200
200
|
}
|
|
201
201
|
lines.push("");
|
|
202
|
-
lines.push("
|
|
203
|
-
lines.push(` Default chat : ${assignments.default ?? "(not set)"}`);
|
|
202
|
+
lines.push("Orchestration roles (used by /plan — NOT chat):");
|
|
204
203
|
for (const role of ORCHESTRATION_ROLES) {
|
|
205
204
|
const a = assignments.orchestration[role.key];
|
|
206
205
|
const preferred = a?.preferred ?? "(not set)";
|
|
@@ -208,6 +207,7 @@ function buildStatusWidget(
|
|
|
208
207
|
lines.push(` ${role.label.padEnd(8)} : ${preferred} / ${fallback}`);
|
|
209
208
|
}
|
|
210
209
|
lines.push("");
|
|
210
|
+
lines.push("Chat default model : controlled via `/model` (this wizard never overrides it)");
|
|
211
211
|
lines.push(`Keys file : ${store.configPath} (chmod 0600 on Unix)`);
|
|
212
212
|
return lines;
|
|
213
213
|
}
|
|
@@ -537,15 +537,22 @@ async function configureAssignments(
|
|
|
537
537
|
return { defaultModel: "default", orchestration: {} };
|
|
538
538
|
}
|
|
539
539
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
540
|
+
ui.notify(
|
|
541
|
+
"Assigning orchestration role models. The chat default is controlled via `/model` — " +
|
|
542
|
+
"this wizard does NOT change it.",
|
|
543
|
+
"info",
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
// Sentinel: the orchestrator falls back to the current chat model when a
|
|
547
|
+
// route doesn't pin a specific one. We never ask the user for a "default"
|
|
548
|
+
// chat model here — `/model` owns that.
|
|
549
|
+
const defaultModel = "default";
|
|
543
550
|
|
|
544
551
|
const orchestration: Record<string, RouteAssignment> = {};
|
|
545
552
|
for (const role of ORCHESTRATION_ROLES) {
|
|
546
553
|
const preferred =
|
|
547
554
|
(await pickModelFromCatalog(ui, `${role.label} - preferred model (${role.desc})`, allModelIds)) ??
|
|
548
|
-
|
|
555
|
+
allModelIds[0];
|
|
549
556
|
const fallbackOptions = allModelIds.filter((m) => m !== preferred);
|
|
550
557
|
const fallback = fallbackOptions.length > 0
|
|
551
558
|
? (await pickModelFromCatalog(ui, `${role.label} - fallback model`, fallbackOptions)) ?? preferred
|
|
@@ -590,8 +597,11 @@ export default function setupExtension(pi: ExtensionAPI) {
|
|
|
590
597
|
try {
|
|
591
598
|
ui.notify(
|
|
592
599
|
"**φ Phi Code Setup Wizard**\n\n" +
|
|
593
|
-
"This wizard configures providers and assigns models to
|
|
594
|
-
"
|
|
600
|
+
"This wizard configures providers and assigns models to **orchestration roles** " +
|
|
601
|
+
"(used by `/plan`).\n" +
|
|
602
|
+
"The **chat default model is controlled via `/model`** and stays sticky across " +
|
|
603
|
+
"prompts — this wizard will never change it.\n\n" +
|
|
604
|
+
"Keys are stored in `~/.phi/agent/models.json` (chmod 0600 on Unix). " +
|
|
595
605
|
"Edit that file directly later to hot-reload (no restart needed).",
|
|
596
606
|
"info",
|
|
597
607
|
);
|
|
@@ -19,6 +19,17 @@ import { homedir } from "node:os";
|
|
|
19
19
|
|
|
20
20
|
interface ExtensionConfig {
|
|
21
21
|
enabled: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* When false (default), the smart router never changes the chat model — it
|
|
24
|
+
* only emits an informational notification per prompt. Use `/model` to
|
|
25
|
+
* choose the chat model; that choice is now the single source of truth
|
|
26
|
+
* and is persisted across sessions via the settings manager.
|
|
27
|
+
*
|
|
28
|
+
* When true (opt-in via `/routing autoswitch on`), the router switches
|
|
29
|
+
* the chat model to the preferred route per prompt, matching the
|
|
30
|
+
* pre-0.75.6 behavior.
|
|
31
|
+
*/
|
|
32
|
+
autoSwitch: boolean;
|
|
22
33
|
notifyOnRecommendation: boolean;
|
|
23
34
|
}
|
|
24
35
|
|
|
@@ -31,7 +42,8 @@ export default function smartRouterExtension(pi: ExtensionAPI) {
|
|
|
31
42
|
let router = new SmartRouter(SmartRouter.defaultConfig());
|
|
32
43
|
let extConfig: ExtensionConfig = {
|
|
33
44
|
enabled: true,
|
|
34
|
-
|
|
45
|
+
autoSwitch: false,
|
|
46
|
+
notifyOnRecommendation: false,
|
|
35
47
|
};
|
|
36
48
|
|
|
37
49
|
/**
|
|
@@ -95,20 +107,30 @@ export default function smartRouterExtension(pi: ExtensionAPI) {
|
|
|
95
107
|
|
|
96
108
|
const modelToUse = targetModel || fallbackModel;
|
|
97
109
|
|
|
98
|
-
if (modelToUse
|
|
99
|
-
|
|
110
|
+
if (!modelToUse) {
|
|
111
|
+
if (extConfig.notifyOnRecommendation) {
|
|
112
|
+
ctx.ui.notify(
|
|
113
|
+
`Routing suggestion: ${recommendation.category} → \`${recommendation.model}\` (not in registry).`,
|
|
114
|
+
"info",
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
} else if (modelToUse.id === ctx.model?.id) {
|
|
118
|
+
// Already on the recommended model — nothing to do.
|
|
119
|
+
} else if (extConfig.autoSwitch) {
|
|
120
|
+
// Legacy opt-in behavior: actually swap the chat model.
|
|
100
121
|
const switched = await pi.setModel(modelToUse);
|
|
101
122
|
if (switched && extConfig.notifyOnRecommendation) {
|
|
102
123
|
ctx.ui.notify(
|
|
103
|
-
|
|
104
|
-
"info"
|
|
124
|
+
`Auto-switched (${recommendation.category}) → \`${modelToUse.id}\`${modelToUse.id !== recommendation.model ? " (fallback)" : ""}`,
|
|
125
|
+
"info",
|
|
105
126
|
);
|
|
106
127
|
}
|
|
107
|
-
} else if (extConfig.notifyOnRecommendation
|
|
108
|
-
//
|
|
128
|
+
} else if (extConfig.notifyOnRecommendation) {
|
|
129
|
+
// Default behavior: never override the user's `/model` choice. Just
|
|
130
|
+
// advertise the suggestion — the chat model stays sticky.
|
|
109
131
|
ctx.ui.notify(
|
|
110
|
-
|
|
111
|
-
"info"
|
|
132
|
+
`Routing suggestion: ${recommendation.category} → \`${modelToUse.id}\`. Stay on \`${ctx.model?.id}\` (use \`/routing autoswitch on\` to auto-apply, or \`/model\` to change manually).`,
|
|
133
|
+
"info",
|
|
112
134
|
);
|
|
113
135
|
}
|
|
114
136
|
}
|
|
@@ -125,44 +147,66 @@ export default function smartRouterExtension(pi: ExtensionAPI) {
|
|
|
125
147
|
|
|
126
148
|
if (!arg) {
|
|
127
149
|
const routingConfig = (router as any).config as RoutingConfig;
|
|
128
|
-
let output =
|
|
129
|
-
output += `Status:
|
|
130
|
-
output += `
|
|
150
|
+
let output = `**Smart Router** (powered by sigma-agents)\n\n`;
|
|
151
|
+
output += `Status: ${extConfig.enabled ? "enabled" : "disabled"}\n`;
|
|
152
|
+
output += `Auto-switch: ${extConfig.autoSwitch ? "on (overrides /model per prompt)" : "off (suggestions only — /model is sticky)"}\n`;
|
|
153
|
+
output += `Notifications: ${extConfig.notifyOnRecommendation ? "on" : "off"}\n\n`;
|
|
131
154
|
|
|
132
155
|
output += `**Routes:**\n`;
|
|
133
156
|
for (const [cat, route] of Object.entries(routingConfig.routes)) {
|
|
134
157
|
output += ` **${cat}** → \`${route.preferredModel}\` (fallback: \`${route.fallback}\`) [agent: ${route.agent || "none"}]\n`;
|
|
135
158
|
output += ` Keywords: ${route.keywords.slice(0, 6).join(", ")}${route.keywords.length > 6 ? "..." : ""}\n`;
|
|
136
159
|
}
|
|
137
|
-
output += `\n **default** → \`${routingConfig.default.model}
|
|
160
|
+
output += `\n **default** → \`${routingConfig.default.model}\` (orchestrator fallback only; chat default comes from \`/model\`)\n`;
|
|
138
161
|
|
|
139
162
|
output += `\nConfig: \`${configPath}\``;
|
|
140
|
-
output += `\nCommands: \`/routing enable|disable|notify-on|notify-off|reload|test\``;
|
|
163
|
+
output += `\nCommands: \`/routing [enable|disable|autoswitch on|autoswitch off|notify-on|notify-off|reload|test]\``;
|
|
141
164
|
|
|
142
165
|
ctx.ui.notify(output, "info");
|
|
143
166
|
return;
|
|
144
167
|
}
|
|
145
168
|
|
|
169
|
+
const tokens = arg.split(/\s+/);
|
|
170
|
+
const head = tokens[0];
|
|
171
|
+
|
|
172
|
+
if (head === "autoswitch") {
|
|
173
|
+
const flag = tokens[1];
|
|
174
|
+
if (flag === "on") {
|
|
175
|
+
extConfig.autoSwitch = true;
|
|
176
|
+
ctx.ui.notify(
|
|
177
|
+
"Auto-switch enabled: the smart router will override the chat model per prompt. " +
|
|
178
|
+
"Disable with `/routing autoswitch off` if it gets in your way.",
|
|
179
|
+
"info",
|
|
180
|
+
);
|
|
181
|
+
} else if (flag === "off") {
|
|
182
|
+
extConfig.autoSwitch = false;
|
|
183
|
+
ctx.ui.notify("Auto-switch disabled. The model selected via `/model` is now sticky.", "info");
|
|
184
|
+
} else {
|
|
185
|
+
ctx.ui.notify("Usage: `/routing autoswitch on|off`", "warning");
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
146
190
|
switch (arg) {
|
|
147
191
|
case "enable":
|
|
148
192
|
extConfig.enabled = true;
|
|
149
|
-
ctx.ui.notify("
|
|
193
|
+
ctx.ui.notify("Smart routing enabled.", "info");
|
|
150
194
|
break;
|
|
151
195
|
case "disable":
|
|
152
196
|
extConfig.enabled = false;
|
|
153
|
-
ctx.ui.notify("
|
|
197
|
+
ctx.ui.notify("Smart routing disabled.", "info");
|
|
154
198
|
break;
|
|
155
199
|
case "notify-on":
|
|
156
200
|
extConfig.notifyOnRecommendation = true;
|
|
157
|
-
ctx.ui.notify("
|
|
201
|
+
ctx.ui.notify("Routing notifications enabled.", "info");
|
|
158
202
|
break;
|
|
159
203
|
case "notify-off":
|
|
160
204
|
extConfig.notifyOnRecommendation = false;
|
|
161
|
-
ctx.ui.notify("
|
|
205
|
+
ctx.ui.notify("Routing notifications disabled.", "info");
|
|
162
206
|
break;
|
|
163
207
|
case "reload":
|
|
164
208
|
await loadConfig();
|
|
165
|
-
ctx.ui.notify("
|
|
209
|
+
ctx.ui.notify("Routing config reloaded from disk.", "info");
|
|
166
210
|
break;
|
|
167
211
|
case "test": {
|
|
168
212
|
const tests = [
|