bermudis-pi-goodies 0.5.4 → 0.6.0
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 +37 -31
- package/index.ts +6 -1
- package/keep-model-on-new.ts +76 -0
- package/model-thinking.ts +1073 -177
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# bermudis-pi-goodies
|
|
2
2
|
|
|
3
3
|
A bundle of small, frequently-used [Pi](https://github.com/earendil-works/pi)
|
|
4
|
-
extensions. One entry point,
|
|
4
|
+
extensions. One entry point, ten independent features.
|
|
5
5
|
|
|
6
6
|
| Feature | Command / hook | What it does |
|
|
7
7
|
| ------------------ | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -10,7 +10,8 @@ extensions. One entry point, nine independent features.
|
|
|
10
10
|
| `name-with-ai` | `/name-with-ai [name]` | Generate a short session name from the first user message (or set one manually). |
|
|
11
11
|
| `zed` | `/z` | Open Zed editor on the current working directory. |
|
|
12
12
|
| `prefer-tools` | hook (no command) | Nudge toward modern CLIs: `rg` over `grep`, `fd` over `find`, `uv` over bare `python`/`pip`/`pytest`/`mypy`. |
|
|
13
|
-
| `model-
|
|
13
|
+
| `keep-model-on-new` | hook (no command) | Keep the active model when `/new` starts a fresh session instead of reverting to pi's saved default model. |
|
|
14
|
+
| `model-thinking` | hook + `/levels` | Per-model thinking levels stored in an extension sidecar (pi's /scoped-models rewrites `enabledModels` bare, wiping `:level` suffixes); `/levels` edits them, hooks apply them whenever a model becomes active. |
|
|
14
15
|
| `kilo` | provider | Access Kilo Gateway models via `/login kilo` or `KILO_API_KEY`. |
|
|
15
16
|
| `provider-balance` | footer (no command) | Show remaining Kilo or OpenRouter credits, z.ai token-plan quota, or OpenAI Codex quota on the right side of the working-directory footer line. |
|
|
16
17
|
| `tps` | hook (no command) | Notify tokens/sec and in/out/cache token usage at the end of each agent turn. |
|
|
@@ -20,7 +21,7 @@ extensions. One entry point, nine independent features.
|
|
|
20
21
|
After publishing the package to npm:
|
|
21
22
|
|
|
22
23
|
```bash
|
|
23
|
-
pi install npm:bermudis-pi-goodies@0.
|
|
24
|
+
pi install npm:bermudis-pi-goodies@0.6.0
|
|
24
25
|
```
|
|
25
26
|
|
|
26
27
|
Remove any old `bermudis-pi-goodies.ts` symlink before reloading Pi. Each
|
|
@@ -29,36 +30,41 @@ Kilo's provider and its balance footer are bundled here.
|
|
|
29
30
|
|
|
30
31
|
## Model selection and thinking
|
|
31
32
|
|
|
32
|
-
Pi's native
|
|
33
|
-
`enabledModels`
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"zai/glm-5.2:high",
|
|
41
|
-
"openai-codex/gpt-5.6-terra:medium"
|
|
42
|
-
]
|
|
43
|
-
}
|
|
33
|
+
Pi's native scoped-models config would put per-model thinking levels in
|
|
34
|
+
`enabledModels` entries like `"zai/glm-5.3:high"`, but the `/scoped-models`
|
|
35
|
+
screen (which maintains that list) rewrites it with bare model ids on every
|
|
36
|
+
save, destroying any `:level` suffix. So this package stores levels in its
|
|
37
|
+
own sidecar file:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
~/.pi/agent/data/bermudis-pi-goodies/thinking-levels.json
|
|
44
41
|
```
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
43
|
+
The split of ownership is clean: `/scoped-models` owns which models are
|
|
44
|
+
enabled and their Ctrl+P cycle order; `/levels` owns the per-model thinking
|
|
45
|
+
level and can never be wiped by the other screen.
|
|
46
|
+
|
|
47
|
+
Use `/levels` to edit: ↑↓ moves between scoped models, ←→ cycles each
|
|
48
|
+
model's level through the ladder it actually supports plus `inherit`
|
|
49
|
+
(which leaves pi's global default in charge), Enter saves atomically and
|
|
50
|
+
applies to the active model immediately, Esc cancels.
|
|
51
|
+
|
|
52
|
+
Hooks apply the stored level whenever a model becomes active: full-picker
|
|
53
|
+
selection, Ctrl+P cycling, startup, and `/new` (where this package carries
|
|
54
|
+
the previous session's active model forward). A native scoped level for the session — via
|
|
55
|
+
`--models "x:high"` or a hand-suffixed enabledModels entry — always wins;
|
|
56
|
+
the sidecar only fills in where pi itself has no level. Explicit
|
|
57
|
+
`--thinking` or `--model ...:<level>` still
|
|
58
|
+
wins for that launched session — a model whose registered id genuinely ends
|
|
59
|
+
in `:<level>` is indistinguishable from that shorthand without the registry,
|
|
60
|
+
so it opts out of its stored level for that startup; switch or cycle to
|
|
61
|
+
re-apply. Resumed and forked sessions keep the level restored by pi.
|
|
62
|
+
|
|
63
|
+
One gap is inherent to Pi: it emits no `model_select` when you pick the
|
|
64
|
+
model that is already active, so re-selecting it in the full picker leaves
|
|
65
|
+
a manual thinking level in place — switch models (or cycle) to snap back.
|
|
66
|
+
Saving the `/scoped-models` screen in pi 0.84.2 writes bare model ids, which
|
|
67
|
+
is now harmless: bare ids are exactly what this design expects.
|
|
62
68
|
|
|
63
69
|
## Provider and balance details
|
|
64
70
|
|
package/index.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* - name-with-ai /name-with-ai generate a session name via the model
|
|
9
9
|
* - zed /z open Zed on cwd
|
|
10
10
|
* - prefer-tools hook block legacy tools (use trash/rg/fd/uv)
|
|
11
|
-
* - model
|
|
11
|
+
* - keep-model hook preserve the active model across /new
|
|
12
|
+
* - model-thinking hook manage per-model thinking levels in an extension-owned sidecar
|
|
12
13
|
* - kilo provider access Kilo Gateway models
|
|
13
14
|
* - provider-balance footer show Kilo credits or Codex quota in the footer
|
|
14
15
|
* - tps hook notify tokens/sec and usage at each agent turn end
|
|
@@ -17,6 +18,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
|
17
18
|
import copyTrajectory from "./copy-trajectory.ts";
|
|
18
19
|
import copyWithModel from "./copy-with-model.ts";
|
|
19
20
|
import kilo from "./kilo.ts";
|
|
21
|
+
import keepModelOnNew from "./keep-model-on-new.ts";
|
|
20
22
|
import modelThinking from "./model-thinking.ts";
|
|
21
23
|
import providerBalance from "./provider-balance.ts";
|
|
22
24
|
import tps from "./tps.ts";
|
|
@@ -30,6 +32,9 @@ export default function bermudisPiGoodies(pi: ExtensionAPI): void {
|
|
|
30
32
|
nameWithAi(pi);
|
|
31
33
|
zed(pi);
|
|
32
34
|
preferTools(pi);
|
|
35
|
+
// Register this before model-thinking so /new restores the model first and
|
|
36
|
+
// model-thinking then sees and configures the final active model.
|
|
37
|
+
keepModelOnNew(pi);
|
|
33
38
|
modelThinking(pi);
|
|
34
39
|
providerBalance(pi);
|
|
35
40
|
kilo(pi);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionAPI,
|
|
3
|
+
ExtensionContext,
|
|
4
|
+
} from "@earendil-works/pi-coding-agent";
|
|
5
|
+
|
|
6
|
+
interface ModelIdentity {
|
|
7
|
+
provider: string;
|
|
8
|
+
id: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extension modules are cached across Pi's session-runtime replacement, while
|
|
13
|
+
* their factories and handlers are recreated. This small handoff therefore
|
|
14
|
+
* survives /new without writing transient state to disk.
|
|
15
|
+
*/
|
|
16
|
+
const pendingModels = new Map<string, ModelIdentity>();
|
|
17
|
+
|
|
18
|
+
function handoffKey(
|
|
19
|
+
sessionFile: string | undefined,
|
|
20
|
+
ctx: Pick<ExtensionContext, "cwd">,
|
|
21
|
+
): string {
|
|
22
|
+
return sessionFile ?? `ephemeral:${ctx.cwd}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface KeepModelOnNewOptions {
|
|
26
|
+
/** Override the process-local handoff store (tests). */
|
|
27
|
+
pendingModels?: Map<string, ModelIdentity>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default function keepModelOnNew(
|
|
31
|
+
pi: ExtensionAPI,
|
|
32
|
+
options: KeepModelOnNewOptions = {},
|
|
33
|
+
): void {
|
|
34
|
+
const handoffs = options.pendingModels ?? pendingModels;
|
|
35
|
+
|
|
36
|
+
pi.on("session_before_switch", (event, ctx) => {
|
|
37
|
+
if (event.reason !== "new" || !ctx.model) return;
|
|
38
|
+
handoffs.set(handoffKey(ctx.sessionManager.getSessionFile(), ctx), {
|
|
39
|
+
provider: ctx.model.provider,
|
|
40
|
+
id: ctx.model.id,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
pi.on("session_start", async (event, ctx) => {
|
|
45
|
+
if (event.reason !== "new") return;
|
|
46
|
+
|
|
47
|
+
const key = handoffKey(event.previousSessionFile, ctx);
|
|
48
|
+
const previous = handoffs.get(key);
|
|
49
|
+
handoffs.delete(key);
|
|
50
|
+
if (!previous) return;
|
|
51
|
+
if (
|
|
52
|
+
ctx.model?.provider === previous.provider &&
|
|
53
|
+
ctx.model.id === previous.id
|
|
54
|
+
) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const model = ctx.modelRegistry.find(previous.provider, previous.id);
|
|
59
|
+
if (!model) {
|
|
60
|
+
const message = `Could not keep model after /new: ${previous.provider}/${previous.id} is unavailable`;
|
|
61
|
+
console.warn(`[keep-model-on-new] ${message}`);
|
|
62
|
+
ctx.ui.notify(message, "warning");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await pi.setModel(model);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
70
|
+
console.warn(
|
|
71
|
+
`[keep-model-on-new] Failed to restore ${previous.provider}/${previous.id}: ${detail}`,
|
|
72
|
+
);
|
|
73
|
+
ctx.ui.notify(`Could not keep model after /new: ${detail}`, "warning");
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|