@xynogen/pix-models 0.1.24 → 0.1.27
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/README.md +1 -1
- package/package.json +1 -1
- package/src/models.ts +36 -22
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Pi extension — enhanced `/models` picker with coding score/rank.
|
|
|
4
4
|
|
|
5
5
|
## What it does
|
|
6
6
|
|
|
7
|
-
Registers a `/models` slash command that replaces Pi's built-in `/model` selector with a richer TUI picker. Each row shows the model id, context window, per-million-token cost, and a coding-focused score/rank (with star bar) when available. The list is sorted by coding score (best first), then alphabetically for unscored models. Fuzzy search filters the list as you type. Selecting a model switches the active model for the session. Model metadata is sourced from `~/.cache/pi/` via `pix-data`; the coding score/rank is computed locally from the modelgrep catalog (best = #1). Requires `@xynogen/pix-data` as a dependency.
|
|
7
|
+
Registers a `/models` slash command that replaces Pi's built-in `/model` selector with a richer TUI picker. Each row shows the model id, context window, per-million-token cost, and a coding-focused score/rank (with star bar) when available. The list is sorted by coding score (best first), then alphabetically for unscored models. Fuzzy search filters the list as you type. Left/right changes the thinking level (`off` → `minimal` → `low` → `medium` → `high` → `xhigh`), with the effective level shown live in the picker header. Selecting a model switches the active model for the session. Model metadata is sourced from `~/.cache/pi/` via `pix-data`; the coding score/rank is computed locally from the modelgrep catalog (best = #1). Requires `@xynogen/pix-data` as a dependency.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
package/package.json
CHANGED
package/src/models.ts
CHANGED
|
@@ -102,8 +102,8 @@ export function normalizeModelText(s: string): string {
|
|
|
102
102
|
// ─── Thinking level control ──────────────────────────────────────────────────
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
|
-
* Canonical thinking levels, ascending.
|
|
106
|
-
*
|
|
105
|
+
* Canonical thinking levels, ascending. ←/→ in the picker steps through this list;
|
|
106
|
+
* pi.setThinkingLevel() clamps to what the active model actually supports,
|
|
107
107
|
* so visiting an unsupported rung is harmless (it lands on the nearest allowed).
|
|
108
108
|
*/
|
|
109
109
|
export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const;
|
|
@@ -277,7 +277,7 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
277
277
|
// items built inside the custom() factory so we have theme access for colors
|
|
278
278
|
|
|
279
279
|
const result = await ctx.ui.custom<string | null>(
|
|
280
|
-
(tui, theme,
|
|
280
|
+
(tui, theme, _kb, done) => {
|
|
281
281
|
const accent = "accent";
|
|
282
282
|
|
|
283
283
|
// Find max rank width across all benchmarked rows for # padding
|
|
@@ -286,9 +286,20 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
286
286
|
1,
|
|
287
287
|
);
|
|
288
288
|
|
|
289
|
+
// Widest cost string so the cost column pads to a common width and the
|
|
290
|
+
// following ⚡score/stars stay column-aligned (e.g. "10.00/50.00" is 11
|
|
291
|
+
// chars — a fixed pad of 10 shifted those rows right by one).
|
|
292
|
+
const maxCostWidth = Math.max(
|
|
293
|
+
...dedupedRows.map((r) => fmtCost(r.dev).length),
|
|
294
|
+
"free".length,
|
|
295
|
+
);
|
|
296
|
+
|
|
289
297
|
// Mute low-info parts (separators, padding, #, ☆) so the actual values pop.
|
|
290
298
|
const mute = (s: string) => theme.fg("muted", s);
|
|
291
299
|
const sep = mute(" · ");
|
|
300
|
+
const guide = (key: string, action: string) =>
|
|
301
|
+
theme.fg("text", key) + theme.fg("dim", ` ${action}`);
|
|
302
|
+
const guideSep = theme.fg("dim", " · ");
|
|
292
303
|
|
|
293
304
|
// Track rank per item value so fuzzy results can prioritize ranked models.
|
|
294
305
|
const rankByValue = new Map<string, number>();
|
|
@@ -340,11 +351,11 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
340
351
|
const rawCost = fmtCost(dev);
|
|
341
352
|
let costSeg: string;
|
|
342
353
|
if (rawCost === "—") {
|
|
343
|
-
costSeg = theme.fg("dim", "—".padEnd(
|
|
354
|
+
costSeg = theme.fg("dim", "—".padEnd(maxCostWidth));
|
|
344
355
|
} else if (rawCost === "free") {
|
|
345
|
-
costSeg = mute("free".padEnd(
|
|
356
|
+
costSeg = mute("free".padEnd(maxCostWidth));
|
|
346
357
|
} else {
|
|
347
|
-
costSeg = theme.fg("success", rawCost.padEnd(
|
|
358
|
+
costSeg = theme.fg("success", rawCost.padEnd(maxCostWidth));
|
|
348
359
|
}
|
|
349
360
|
let benchSeg = "";
|
|
350
361
|
if (bench) {
|
|
@@ -417,7 +428,7 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
417
428
|
internal.invalidate();
|
|
418
429
|
};
|
|
419
430
|
|
|
420
|
-
// Live thinking-level readout.
|
|
431
|
+
// Live thinking-level readout. ←/→ mutates the session immediately via
|
|
421
432
|
// pi.setThinkingLevel(); we mirror pi.getThinkingLevel() so the header
|
|
422
433
|
// reflects the clamped result (model may not support every rung).
|
|
423
434
|
//
|
|
@@ -435,7 +446,11 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
435
446
|
? theme.getThinkingBorderColor(resolved)(label)
|
|
436
447
|
: theme.fg("dim", label);
|
|
437
448
|
return (
|
|
438
|
-
theme.fg("muted", "Thinking: ") +
|
|
449
|
+
theme.fg("muted", "Thinking: ") +
|
|
450
|
+
coloredLabel +
|
|
451
|
+
theme.fg("dim", " (") +
|
|
452
|
+
guide("←/→", "adjust") +
|
|
453
|
+
theme.fg("dim", ")")
|
|
439
454
|
);
|
|
440
455
|
};
|
|
441
456
|
|
|
@@ -451,8 +466,8 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
451
466
|
theme.fg(accent, theme.bold(`${icon("picker.model")} Select model`)),
|
|
452
467
|
theme.fg("dim", "context · pricing · coding rank & score from modelgrep.com"),
|
|
453
468
|
thinkLine(),
|
|
454
|
-
theme.fg("muted", "Search:"),
|
|
455
469
|
...search.render(inner),
|
|
470
|
+
"",
|
|
456
471
|
],
|
|
457
472
|
body: list.render(inner),
|
|
458
473
|
selectedBodyRange: (() => {
|
|
@@ -463,10 +478,14 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
463
478
|
});
|
|
464
479
|
})(),
|
|
465
480
|
footer: [
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
481
|
+
"",
|
|
482
|
+
guide("↑↓", "navigate") +
|
|
483
|
+
guideSep +
|
|
484
|
+
guide("←/→", "thinking") +
|
|
485
|
+
guideSep +
|
|
486
|
+
guide("enter", "select") +
|
|
487
|
+
guideSep +
|
|
488
|
+
guide("esc", "cancel"),
|
|
470
489
|
],
|
|
471
490
|
bodyOffset: pager.bodyOffset,
|
|
472
491
|
color: (s) => theme.fg(accent, s),
|
|
@@ -481,20 +500,15 @@ async function showEnhancedPicker(pi: ExtensionAPI, ctx: ExtensionContext): Prom
|
|
|
481
500
|
search.invalidate();
|
|
482
501
|
},
|
|
483
502
|
handleInput(data: string) {
|
|
484
|
-
if (pager.handleInput(data, kb, true)) {
|
|
485
|
-
tui.requestRender();
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
503
|
// Detect keys via pi-tui's own parser — the same recognition
|
|
489
504
|
// SelectList uses. Arrows arrive as named keys ("up"/"down"),
|
|
490
505
|
// not raw escape sequences, so string-equality checks fail.
|
|
491
506
|
const isNav = matchesKey(data, "up") || matchesKey(data, "down");
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
// to model capability, so unsupported rungs land on the nearest allowed.
|
|
507
|
+
// ←/→ tunes the ACTIVE session model's thinking level. setThinkingLevel
|
|
508
|
+
// clamps to model capability, so unsupported rungs land on the nearest allowed.
|
|
495
509
|
let dir: -1 | 1 | 0 = 0;
|
|
496
|
-
if (matchesKey(data, Key.
|
|
497
|
-
else if (matchesKey(data, Key.
|
|
510
|
+
if (matchesKey(data, Key.left)) dir = -1;
|
|
511
|
+
else if (matchesKey(data, Key.right)) dir = 1;
|
|
498
512
|
if (dir !== 0) {
|
|
499
513
|
const cur = pi.getThinkingLevel?.() || localLevel || "medium";
|
|
500
514
|
localLevel = stepEffectiveThinkingLevel(cur, dir, (candidate) => {
|