ultimate-pi 0.2.7 → 0.3.1
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/.agents/skills/harness-eval/SKILL.md +1 -1
- package/.agents/skills/harness-governor/SKILL.md +2 -2
- package/.agents/skills/harness-spec/SKILL.md +1 -1
- package/.pi/PACKAGING.md +3 -2
- package/.pi/extensions/custom-header.ts +0 -17
- package/.pi/extensions/pi-model-router-harness.ts +42 -0
- package/.pi/extensions/policy-gate.ts +18 -0
- package/.pi/extensions/provider-payload-sanitize.ts +66 -0
- package/.pi/extensions/sentrux-rules-sync.ts +0 -18
- package/.pi/harness/README.md +3 -2
- package/.pi/harness/docs/adrs/0004-defer-ci-agent-smoke.md +1 -1
- package/.pi/harness/docs/adrs/0006-sentrux-dual-layer.md +1 -1
- package/.pi/harness/docs/adrs/0009-sentrux-rules-lifecycle.md +2 -2
- package/.pi/harness/evals/smoke/README.md +1 -1
- package/.pi/harness/evolution/README.md +1 -1
- package/.pi/harness/evolution/chaos-drill.md +1 -1
- package/.pi/prompts/harness-setup.md +42 -35
- package/.pi/scripts/README.md +25 -9
- package/.pi/scripts/harness-cli-verify.sh +4 -2
- package/.pi/scripts/harness-seed-project-contracts.mjs +49 -0
- package/.pi/scripts/harness-sync-model-router.mjs +84 -0
- package/.pi/scripts/harness-verify.mjs +5 -3
- package/.pi/scripts/sentrux-rules-sync.mjs +2 -2
- package/.pi/scripts/vendor-sync-pi-model-router.sh +47 -0
- package/.pi/settings.example.json +0 -1
- package/.sentrux/rules.toml +1 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +62 -0
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/biome.json +2 -1
- package/package.json +9 -10
- package/vendor/pi-model-router/.prettierignore +4 -0
- package/vendor/pi-model-router/.prettierrc +5 -0
- package/vendor/pi-model-router/AGENTS.md +39 -0
- package/vendor/pi-model-router/LICENSE +21 -0
- package/vendor/pi-model-router/README.md +99 -0
- package/vendor/pi-model-router/UPSTREAM_PIN.md +8 -0
- package/vendor/pi-model-router/docs/ARCHITECTURE.md +54 -0
- package/vendor/pi-model-router/extensions/commands.ts +720 -0
- package/vendor/pi-model-router/extensions/config.ts +348 -0
- package/vendor/pi-model-router/extensions/constants.ts +1 -0
- package/vendor/pi-model-router/extensions/index.ts +457 -0
- package/vendor/pi-model-router/extensions/provider.ts +529 -0
- package/vendor/pi-model-router/extensions/routing.ts +416 -0
- package/vendor/pi-model-router/extensions/state.ts +49 -0
- package/vendor/pi-model-router/extensions/types.ts +86 -0
- package/vendor/pi-model-router/extensions/ui.ts +130 -0
- package/vendor/pi-model-router/model-router.example.json +48 -0
- package/vendor/pi-model-router/package.json +48 -0
- package/vendor/pi-model-router/tsconfig.json +16 -0
- package/.pi/extensions/model-router-bootstrap.ts +0 -174
- package/.sentrux/.harness-rules-meta.json +0 -5
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionContext,
|
|
4
|
+
} from '@mariozechner/pi-coding-agent';
|
|
5
|
+
import {
|
|
6
|
+
type RouterConfig,
|
|
7
|
+
type RouterPersistedState,
|
|
8
|
+
type RoutingDecision,
|
|
9
|
+
type RouterPinByProfile,
|
|
10
|
+
type RouterThinkingByProfile,
|
|
11
|
+
type RouterTier,
|
|
12
|
+
type CustomSessionEntry,
|
|
13
|
+
} from './types.js';
|
|
14
|
+
import {
|
|
15
|
+
FALLBACK_CONFIG,
|
|
16
|
+
loadRouterConfig,
|
|
17
|
+
profileNames,
|
|
18
|
+
resolveProfileName,
|
|
19
|
+
parseCanonicalModelRef,
|
|
20
|
+
} from './config.js';
|
|
21
|
+
import { MAX_DEBUG_HISTORY } from './constants.js';
|
|
22
|
+
import { isRouterPersistedState, buildPersistedState } from './state.js';
|
|
23
|
+
import { updateStatus, formatModelRef } from './ui.js';
|
|
24
|
+
import { registerCommands } from './commands.js';
|
|
25
|
+
import { registerRouterProvider } from './provider.js';
|
|
26
|
+
|
|
27
|
+
const routerExtension = (pi: ExtensionAPI) => {
|
|
28
|
+
let currentConfig: RouterConfig = FALLBACK_CONFIG;
|
|
29
|
+
let currentModelRegistry: ExtensionContext['modelRegistry'] | undefined;
|
|
30
|
+
let currentCwd = process.cwd();
|
|
31
|
+
let lastDecision: RoutingDecision | undefined;
|
|
32
|
+
let debugEnabled = false;
|
|
33
|
+
let routerEnabled = false;
|
|
34
|
+
let selectedProfile = resolveProfileName(
|
|
35
|
+
FALLBACK_CONFIG,
|
|
36
|
+
FALLBACK_CONFIG.defaultProfile,
|
|
37
|
+
);
|
|
38
|
+
let widgetEnabled = false;
|
|
39
|
+
let lastRegisteredModels = '';
|
|
40
|
+
let pinnedTierByProfile: RouterPinByProfile = {};
|
|
41
|
+
let thinkingByProfile: RouterThinkingByProfile = {};
|
|
42
|
+
let debugHistory: RoutingDecision[] = [];
|
|
43
|
+
let lastNonRouterModel: string | undefined;
|
|
44
|
+
let accumulatedCost = 0;
|
|
45
|
+
let lastExtensionContext: ExtensionContext | undefined;
|
|
46
|
+
let lastConfigWarnings: string[] = [];
|
|
47
|
+
let lastPersistedSnapshot: string | undefined;
|
|
48
|
+
let isInitialized = false;
|
|
49
|
+
let isInternalModelSwitch = false;
|
|
50
|
+
|
|
51
|
+
const setModelInternally = async (
|
|
52
|
+
model: NonNullable<ExtensionContext['model']>,
|
|
53
|
+
) => {
|
|
54
|
+
isInternalModelSwitch = true;
|
|
55
|
+
try {
|
|
56
|
+
return await pi.setModel(model);
|
|
57
|
+
} finally {
|
|
58
|
+
isInternalModelSwitch = false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const getPinnedTierForProfile = (
|
|
63
|
+
profileName: string,
|
|
64
|
+
): RouterTier | undefined => pinnedTierByProfile[profileName];
|
|
65
|
+
|
|
66
|
+
const setPinnedTierForProfile = (
|
|
67
|
+
profileName: string,
|
|
68
|
+
tier: RouterTier | undefined,
|
|
69
|
+
) => {
|
|
70
|
+
if (tier) {
|
|
71
|
+
pinnedTierByProfile[profileName] = tier;
|
|
72
|
+
} else {
|
|
73
|
+
delete pinnedTierByProfile[profileName];
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const recordDebugDecision = (decision: RoutingDecision) => {
|
|
78
|
+
debugHistory = [...debugHistory, decision].slice(-MAX_DEBUG_HISTORY);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const getThinkingOverride = (profileName: string, tier: RouterTier) => {
|
|
82
|
+
return thinkingByProfile[profileName]?.[tier];
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const persistState = () => {
|
|
86
|
+
const state = buildPersistedState(
|
|
87
|
+
routerEnabled,
|
|
88
|
+
selectedProfile,
|
|
89
|
+
pinnedTierByProfile,
|
|
90
|
+
thinkingByProfile,
|
|
91
|
+
debugEnabled,
|
|
92
|
+
widgetEnabled,
|
|
93
|
+
debugHistory,
|
|
94
|
+
lastDecision,
|
|
95
|
+
lastNonRouterModel,
|
|
96
|
+
accumulatedCost,
|
|
97
|
+
);
|
|
98
|
+
const snapshot = JSON.stringify({
|
|
99
|
+
...state,
|
|
100
|
+
timestamp: 0,
|
|
101
|
+
lastDecision: state.lastDecision
|
|
102
|
+
? { ...state.lastDecision, timestamp: 0 }
|
|
103
|
+
: undefined,
|
|
104
|
+
debugHistory: state.debugHistory?.map((decision) => ({
|
|
105
|
+
...decision,
|
|
106
|
+
timestamp: 0,
|
|
107
|
+
})),
|
|
108
|
+
});
|
|
109
|
+
if (snapshot === lastPersistedSnapshot) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
pi.appendEntry('router-state', state);
|
|
113
|
+
lastPersistedSnapshot = snapshot;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const actions = {
|
|
117
|
+
persistState,
|
|
118
|
+
updateStatus: (ctx: ExtensionContext) =>
|
|
119
|
+
updateStatus(
|
|
120
|
+
ctx,
|
|
121
|
+
routerEnabled,
|
|
122
|
+
selectedProfile,
|
|
123
|
+
pinnedTierByProfile,
|
|
124
|
+
thinkingByProfile,
|
|
125
|
+
lastDecision,
|
|
126
|
+
lastNonRouterModel,
|
|
127
|
+
accumulatedCost,
|
|
128
|
+
widgetEnabled,
|
|
129
|
+
currentConfig,
|
|
130
|
+
),
|
|
131
|
+
reloadConfig: (
|
|
132
|
+
ctx?: ExtensionContext,
|
|
133
|
+
options?: { preserveDebug?: boolean },
|
|
134
|
+
) => {
|
|
135
|
+
const loaded = loadRouterConfig(currentCwd);
|
|
136
|
+
currentConfig = loaded.config;
|
|
137
|
+
lastConfigWarnings = loaded.warnings;
|
|
138
|
+
if (!options?.preserveDebug) {
|
|
139
|
+
debugEnabled = currentConfig.debug ?? false;
|
|
140
|
+
}
|
|
141
|
+
selectedProfile = resolveProfileName(currentConfig, selectedProfile);
|
|
142
|
+
actions.registerRouterProvider();
|
|
143
|
+
if (ctx) {
|
|
144
|
+
actions.updateStatus(ctx);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
ensureValidActiveRouterProfile: async (ctx: ExtensionContext) => {
|
|
148
|
+
if (ctx.model?.provider !== 'router') {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (currentConfig.profiles[ctx.model.id]) {
|
|
152
|
+
selectedProfile = ctx.model.id;
|
|
153
|
+
routerEnabled = true;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const fallbackProfile = resolveProfileName(
|
|
158
|
+
currentConfig,
|
|
159
|
+
selectedProfile,
|
|
160
|
+
);
|
|
161
|
+
const routerModel = ctx.modelRegistry.find('router', fallbackProfile);
|
|
162
|
+
selectedProfile = fallbackProfile;
|
|
163
|
+
if (!routerModel) {
|
|
164
|
+
ctx.ui.notify(
|
|
165
|
+
`Router profile "${ctx.model.id}" is no longer configured.`,
|
|
166
|
+
'warning',
|
|
167
|
+
);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await setModelInternally(routerModel);
|
|
172
|
+
ctx.ui.notify(
|
|
173
|
+
`Router profile "${ctx.model.id}" is no longer configured. Switched to router/${fallbackProfile}.`,
|
|
174
|
+
'warning',
|
|
175
|
+
);
|
|
176
|
+
},
|
|
177
|
+
switchToRouterProfile: async (
|
|
178
|
+
profileName: string,
|
|
179
|
+
ctx: ExtensionContext,
|
|
180
|
+
strict = true,
|
|
181
|
+
) => {
|
|
182
|
+
if (strict && !currentConfig.profiles[profileName]) {
|
|
183
|
+
ctx.ui.notify(`Unknown router profile: ${profileName}`, 'error');
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
const resolvedProfile = resolveProfileName(currentConfig, profileName);
|
|
187
|
+
|
|
188
|
+
// Ensure the provider is registered with current capacities for this profile
|
|
189
|
+
actions.registerRouterProvider();
|
|
190
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
191
|
+
|
|
192
|
+
const routerModel = ctx.modelRegistry.find('router', resolvedProfile);
|
|
193
|
+
if (!routerModel) {
|
|
194
|
+
ctx.ui.notify(`Unknown router profile: ${profileName}`, 'error');
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
if (ctx.model && ctx.model.provider !== 'router') {
|
|
198
|
+
lastNonRouterModel = `${ctx.model.provider}/${ctx.model.id}`;
|
|
199
|
+
}
|
|
200
|
+
const success = await setModelInternally(routerModel);
|
|
201
|
+
if (!success) {
|
|
202
|
+
ctx.ui.notify(`Failed to switch to router/${resolvedProfile}`, 'error');
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
selectedProfile = resolvedProfile;
|
|
206
|
+
routerEnabled = true;
|
|
207
|
+
persistState();
|
|
208
|
+
actions.updateStatus(ctx);
|
|
209
|
+
return true;
|
|
210
|
+
},
|
|
211
|
+
registerRouterProvider: () => {
|
|
212
|
+
registerRouterProvider(
|
|
213
|
+
pi,
|
|
214
|
+
{
|
|
215
|
+
get lastRegisteredModels() {
|
|
216
|
+
return lastRegisteredModels;
|
|
217
|
+
},
|
|
218
|
+
set lastRegisteredModels(v) {
|
|
219
|
+
lastRegisteredModels = v;
|
|
220
|
+
},
|
|
221
|
+
get currentConfig() {
|
|
222
|
+
return currentConfig;
|
|
223
|
+
},
|
|
224
|
+
get currentModelRegistry() {
|
|
225
|
+
return currentModelRegistry;
|
|
226
|
+
},
|
|
227
|
+
get lastExtensionContext() {
|
|
228
|
+
return lastExtensionContext;
|
|
229
|
+
},
|
|
230
|
+
get selectedProfile() {
|
|
231
|
+
return selectedProfile;
|
|
232
|
+
},
|
|
233
|
+
set selectedProfile(v) {
|
|
234
|
+
selectedProfile = v;
|
|
235
|
+
},
|
|
236
|
+
get routerEnabled() {
|
|
237
|
+
return routerEnabled;
|
|
238
|
+
},
|
|
239
|
+
set routerEnabled(v) {
|
|
240
|
+
routerEnabled = v;
|
|
241
|
+
},
|
|
242
|
+
get lastDecision() {
|
|
243
|
+
return lastDecision;
|
|
244
|
+
},
|
|
245
|
+
set lastDecision(v) {
|
|
246
|
+
lastDecision = v;
|
|
247
|
+
},
|
|
248
|
+
thinkingByProfile,
|
|
249
|
+
pinnedTierByProfile,
|
|
250
|
+
get accumulatedCost() {
|
|
251
|
+
return accumulatedCost;
|
|
252
|
+
},
|
|
253
|
+
set accumulatedCost(v) {
|
|
254
|
+
accumulatedCost = v;
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
persistState,
|
|
259
|
+
recordDebugDecision,
|
|
260
|
+
getThinkingOverride,
|
|
261
|
+
updateStatus: actions.updateStatus,
|
|
262
|
+
},
|
|
263
|
+
);
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
actions.reloadConfig();
|
|
268
|
+
|
|
269
|
+
const restoreStateFromSession = async (ctx: ExtensionContext) => {
|
|
270
|
+
lastExtensionContext = ctx;
|
|
271
|
+
currentModelRegistry = ctx.modelRegistry;
|
|
272
|
+
currentCwd = ctx.cwd;
|
|
273
|
+
actions.reloadConfig();
|
|
274
|
+
|
|
275
|
+
// Give the registry a moment to synchronize after re-registration
|
|
276
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
277
|
+
|
|
278
|
+
routerEnabled = ctx.model?.provider === 'router';
|
|
279
|
+
selectedProfile = resolveProfileName(
|
|
280
|
+
currentConfig,
|
|
281
|
+
ctx.model?.provider === 'router' ? ctx.model.id : selectedProfile,
|
|
282
|
+
);
|
|
283
|
+
pinnedTierByProfile = {};
|
|
284
|
+
thinkingByProfile = {};
|
|
285
|
+
widgetEnabled = false;
|
|
286
|
+
debugHistory = [];
|
|
287
|
+
accumulatedCost = 0;
|
|
288
|
+
lastNonRouterModel =
|
|
289
|
+
ctx.model && ctx.model.provider !== 'router'
|
|
290
|
+
? `${ctx.model.provider}/${ctx.model.id}`
|
|
291
|
+
: lastNonRouterModel;
|
|
292
|
+
lastDecision = undefined;
|
|
293
|
+
|
|
294
|
+
const entries = ctx.sessionManager.getBranch() as CustomSessionEntry[];
|
|
295
|
+
const savedState = entries
|
|
296
|
+
.filter(
|
|
297
|
+
(entry) =>
|
|
298
|
+
entry.type === 'custom' && entry.customType === 'router-state',
|
|
299
|
+
)
|
|
300
|
+
.map((entry) => entry.data)
|
|
301
|
+
.findLast((data) => isRouterPersistedState(data));
|
|
302
|
+
|
|
303
|
+
if (isRouterPersistedState(savedState)) {
|
|
304
|
+
selectedProfile = resolveProfileName(
|
|
305
|
+
currentConfig,
|
|
306
|
+
savedState.selectedProfile,
|
|
307
|
+
);
|
|
308
|
+
routerEnabled = savedState.enabled;
|
|
309
|
+
pinnedTierByProfile = savedState.pinByProfile
|
|
310
|
+
? { ...savedState.pinByProfile }
|
|
311
|
+
: {};
|
|
312
|
+
thinkingByProfile = savedState.thinkingByProfile
|
|
313
|
+
? { ...savedState.thinkingByProfile }
|
|
314
|
+
: {};
|
|
315
|
+
if (savedState.pinTier) {
|
|
316
|
+
pinnedTierByProfile[selectedProfile] = savedState.pinTier;
|
|
317
|
+
}
|
|
318
|
+
debugEnabled = savedState.debugEnabled ?? debugEnabled;
|
|
319
|
+
widgetEnabled = savedState.widgetEnabled ?? widgetEnabled;
|
|
320
|
+
debugHistory = savedState.debugHistory
|
|
321
|
+
? [...savedState.debugHistory].slice(-MAX_DEBUG_HISTORY)
|
|
322
|
+
: [];
|
|
323
|
+
lastNonRouterModel = savedState.lastNonRouterModel ?? lastNonRouterModel;
|
|
324
|
+
accumulatedCost = savedState.accumulatedCost ?? 0;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
await actions.ensureValidActiveRouterProfile(ctx);
|
|
328
|
+
|
|
329
|
+
if (routerEnabled) {
|
|
330
|
+
const routerModel = ctx.modelRegistry.find('router', selectedProfile);
|
|
331
|
+
if (routerModel) {
|
|
332
|
+
const success = await setModelInternally(routerModel);
|
|
333
|
+
if (!success) {
|
|
334
|
+
ctx.ui.notify(
|
|
335
|
+
`Failed to restore router/${selectedProfile} after relaunch.`,
|
|
336
|
+
'warning',
|
|
337
|
+
);
|
|
338
|
+
routerEnabled = false;
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
ctx.ui.notify(
|
|
342
|
+
`Unable to restore router/${selectedProfile}; model is unavailable.`,
|
|
343
|
+
'warning',
|
|
344
|
+
);
|
|
345
|
+
routerEnabled = false;
|
|
346
|
+
ctx.ui.setHiddenThinkingLabel?.();
|
|
347
|
+
}
|
|
348
|
+
} else {
|
|
349
|
+
ctx.ui.setHiddenThinkingLabel?.();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
persistState();
|
|
353
|
+
actions.updateStatus(ctx);
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
registerCommands(
|
|
357
|
+
pi,
|
|
358
|
+
{
|
|
359
|
+
get currentConfig() {
|
|
360
|
+
return currentConfig;
|
|
361
|
+
},
|
|
362
|
+
get routerEnabled() {
|
|
363
|
+
return routerEnabled;
|
|
364
|
+
},
|
|
365
|
+
set routerEnabled(v) {
|
|
366
|
+
routerEnabled = v;
|
|
367
|
+
},
|
|
368
|
+
get selectedProfile() {
|
|
369
|
+
return selectedProfile;
|
|
370
|
+
},
|
|
371
|
+
set selectedProfile(v) {
|
|
372
|
+
selectedProfile = v;
|
|
373
|
+
},
|
|
374
|
+
pinnedTierByProfile,
|
|
375
|
+
thinkingByProfile,
|
|
376
|
+
get lastDecision() {
|
|
377
|
+
return lastDecision;
|
|
378
|
+
},
|
|
379
|
+
get lastNonRouterModel() {
|
|
380
|
+
return lastNonRouterModel;
|
|
381
|
+
},
|
|
382
|
+
set lastNonRouterModel(v) {
|
|
383
|
+
lastNonRouterModel = v;
|
|
384
|
+
},
|
|
385
|
+
get accumulatedCost() {
|
|
386
|
+
return accumulatedCost;
|
|
387
|
+
},
|
|
388
|
+
get debugEnabled() {
|
|
389
|
+
return debugEnabled;
|
|
390
|
+
},
|
|
391
|
+
set debugEnabled(v) {
|
|
392
|
+
debugEnabled = v;
|
|
393
|
+
},
|
|
394
|
+
get widgetEnabled() {
|
|
395
|
+
return widgetEnabled;
|
|
396
|
+
},
|
|
397
|
+
set widgetEnabled(v) {
|
|
398
|
+
widgetEnabled = v;
|
|
399
|
+
},
|
|
400
|
+
get debugHistory() {
|
|
401
|
+
return debugHistory;
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
actions,
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
pi.on('session_start', async (_event, ctx) => {
|
|
408
|
+
isInitialized = true;
|
|
409
|
+
await restoreStateFromSession(ctx);
|
|
410
|
+
if (debugEnabled) {
|
|
411
|
+
ctx.ui.notify(
|
|
412
|
+
`Router initialized with profiles: ${profileNames(currentConfig).join(', ')}`,
|
|
413
|
+
'info',
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
pi.on('model_select', async (event, ctx) => {
|
|
419
|
+
if (!isInitialized || isInternalModelSwitch) return;
|
|
420
|
+
if (event.model.provider === 'router') {
|
|
421
|
+
const profileName = resolveProfileName(currentConfig, event.model.id);
|
|
422
|
+
|
|
423
|
+
// If the selected model has stale capacities (e.g. from the initial registration),
|
|
424
|
+
// re-apply the model from the registry to force a TUI refresh.
|
|
425
|
+
const registryModel = ctx.modelRegistry.find('router', profileName);
|
|
426
|
+
if (
|
|
427
|
+
registryModel &&
|
|
428
|
+
(registryModel.contextWindow !== event.model.contextWindow ||
|
|
429
|
+
registryModel.maxTokens !== event.model.maxTokens)
|
|
430
|
+
) {
|
|
431
|
+
await setModelInternally(registryModel);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
routerEnabled = true;
|
|
435
|
+
selectedProfile = profileName;
|
|
436
|
+
} else {
|
|
437
|
+
routerEnabled = false;
|
|
438
|
+
lastNonRouterModel = `${event.model.provider}/${event.model.id}`;
|
|
439
|
+
ctx.ui.setHiddenThinkingLabel?.();
|
|
440
|
+
}
|
|
441
|
+
persistState();
|
|
442
|
+
actions.updateStatus(ctx);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
pi.on('turn_end', async (_event, ctx) => {
|
|
446
|
+
if (routerEnabled && ctx.model?.provider !== 'router') {
|
|
447
|
+
const routerModel = ctx.modelRegistry.find('router', selectedProfile);
|
|
448
|
+
if (routerModel) {
|
|
449
|
+
await setModelInternally(routerModel);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
persistState();
|
|
453
|
+
actions.updateStatus(ctx);
|
|
454
|
+
});
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
export default routerExtension;
|