@narumitw/pi-btw 0.51.0 → 0.52.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 +24 -17
- package/package.json +5 -5
- package/src/btw.ts +4 -2
- package/src/menu.ts +33 -13
- package/src/settings.ts +22 -2
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Use it when you want to ask a temporary question, inspect context, or get a shor
|
|
|
18
18
|
- Optionally brings the latest answer, a question-to-end suffix, an exact line range, or the entire side thread into the main editor.
|
|
19
19
|
- Uses the current session branch as context.
|
|
20
20
|
- Uses Pi's current model or an independent model selected in `pi-btw.json`.
|
|
21
|
-
- Uses a pi-btw thinking level that can
|
|
21
|
+
- Uses a pi-btw thinking level that can either start from the main thread or use a fixed remembered value.
|
|
22
22
|
- Does not append the side question or answer to the main conversation.
|
|
23
23
|
- Works as an independently installable npm Pi extension package.
|
|
24
24
|
|
|
@@ -61,7 +61,7 @@ Examples:
|
|
|
61
61
|
Running `/btw` alone opens a menu with **Start side thread** selected first.
|
|
62
62
|
When the current Pi session has non-empty side threads in memory, **Resume side thread** opens a bounded searchable choice list.
|
|
63
63
|
Search matches the displayed first question and question count while returning the thread's raw in-memory ID.
|
|
64
|
-
**Settings** changes the starting thinking level and whether shortcut changes are remembered.
|
|
64
|
+
**Settings** changes the starting thinking level and whether shortcut changes for fixed levels are remembered.
|
|
65
65
|
Each Resume row keeps the first question as its fixed title, shows its question count, and the list is ordered by the newest recorded answer or visible error.
|
|
66
66
|
Opening and closing a thread without a new result does not reorder it.
|
|
67
67
|
`/btw <question>` bypasses this menu and always starts a fresh side thread.
|
|
@@ -79,9 +79,11 @@ Previous side questions and answers remain available to the model and visible fo
|
|
|
79
79
|
invocation. The side-thread header shows its current thinking level. Press Pi's configured
|
|
80
80
|
`app.thinking.cycle` shortcut (`Shift+Tab` by default) in the composer to cycle the levels
|
|
81
81
|
supported by the side-thread model; every later question uses the displayed level until it is
|
|
82
|
-
changed again.
|
|
83
|
-
invocation. Turn **Remember thinking level changes** off in
|
|
84
|
-
current side thread.
|
|
82
|
+
changed again. When a fixed thinking level is selected, each shortcut change is also written to
|
|
83
|
+
`pi-btw.json` for the next invocation by default. Turn **Remember thinking level changes** off in
|
|
84
|
+
Settings to keep fixed-level changes local to the current side thread. When **Same as main thread** is
|
|
85
|
+
selected, shortcut changes are always local to the current side thread. Neither path changes the main
|
|
86
|
+
session's thinking level.
|
|
85
87
|
While a response is running, the transcript and composer remain visible above an `Answering…`
|
|
86
88
|
status.
|
|
87
89
|
Type another question and press `Enter` to queue it as `Steering`; queued questions are shown in
|
|
@@ -148,18 +150,23 @@ cannot be found or authenticated, pi-btw warns and falls back to the current ses
|
|
|
148
150
|
If neither model is available, `/btw` reports an error and stops. This selection affects only
|
|
149
151
|
`/btw`; it does not change the main session model.
|
|
150
152
|
|
|
151
|
-
Pi calls its reasoning setting the **thinking level**.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
`
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
A
|
|
153
|
+
Pi calls its reasoning setting the **thinking level**. In Settings, choose **Same as main thread**
|
|
154
|
+
to start each new side thread from the main thread's current thinking level. This is stored by
|
|
155
|
+
omitting `thinkingLevel` from `pi-btw.json`.
|
|
156
|
+
|
|
157
|
+
Set `thinkingLevel` only when you want a fixed pi-btw starting level. Accepted fixed values are
|
|
158
|
+
`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. The initial value and shortcut cycle
|
|
159
|
+
are clamped to the selected side model's capabilities using Pi's model rules. Resumed side threads
|
|
160
|
+
keep their own local thinking level instead of re-syncing with the main thread. Pi-btw does not read,
|
|
161
|
+
write, or change the main session's `defaultThinkingLevel`.
|
|
162
|
+
|
|
163
|
+
`rememberThinkingLevelChanges` controls only persistence for fixed thinking levels and defaults to
|
|
164
|
+
`true` when omitted. A side-thread shortcut always changes that side thread immediately. When a fixed
|
|
165
|
+
thinking level is selected and remembering is on, the concrete level is written for the next
|
|
166
|
+
invocation; when off, `pi-btw.json` stays unchanged. When **Same as main thread** is selected,
|
|
167
|
+
shortcut changes stay local even when remembering is on. If a shortcut write fails, the local change
|
|
168
|
+
remains active and pi-btw warns that it was not remembered. A failed Settings-screen save instead
|
|
169
|
+
restores the previous displayed value.
|
|
163
170
|
|
|
164
171
|
A missing settings file is a side-effect-free read: pi-btw creates it only after a Settings change
|
|
165
172
|
or a remembered shortcut change. Saves are ordered within the Pi process and published atomically
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-btw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"description": "Pi extension that adds a /btw side-question command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"typecheck": "tsc --noEmit"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@biomejs/biome": "2.5.
|
|
35
|
-
"@earendil-works/pi-ai": "0.84.
|
|
36
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
37
|
-
"@earendil-works/pi-tui": "0.84.
|
|
34
|
+
"@biomejs/biome": "2.5.8",
|
|
35
|
+
"@earendil-works/pi-ai": "0.84.2",
|
|
36
|
+
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
37
|
+
"@earendil-works/pi-tui": "0.84.2",
|
|
38
38
|
"typescript": "7.0.2"
|
|
39
39
|
},
|
|
40
40
|
"repository": {
|
package/src/btw.ts
CHANGED
|
@@ -194,7 +194,7 @@ export async function loadBtwThinkingLevel(
|
|
|
194
194
|
|
|
195
195
|
options.warn?.(
|
|
196
196
|
sanitizeSingleLine(
|
|
197
|
-
`pi-btw settings ignored: ${settings.reason}; expected optional model "provider/model-id", thinkingLevel "${BTW_THINKING_LEVELS.join('" | "')}", and boolean rememberThinkingLevelChanges. Using current Pi thinking level.`,
|
|
197
|
+
`pi-btw settings ignored: ${settings.reason}; expected optional model "provider/model-id", omitted thinkingLevel for Same as main thread or thinkingLevel "${BTW_THINKING_LEVELS.join('" | "')}", and boolean rememberThinkingLevelChanges. Using current Pi thinking level.`,
|
|
198
198
|
),
|
|
199
199
|
);
|
|
200
200
|
return currentThinkingLevel;
|
|
@@ -265,6 +265,7 @@ export default function btw(pi: ExtensionAPI, dependencies: BtwExtensionDependen
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
const settings = await loadSettings(ctx);
|
|
268
|
+
const sameAsMainThinkingLevel = settings.thinkingLevel === undefined;
|
|
268
269
|
const resolution = await resolveModel(settings, ctx);
|
|
269
270
|
if (resolution.kind === "cancelled") {
|
|
270
271
|
notifySafely(ctx, "Cancelled", "info");
|
|
@@ -302,7 +303,8 @@ export default function btw(pi: ExtensionAPI, dependencies: BtwExtensionDependen
|
|
|
302
303
|
initialQuestion: question || undefined,
|
|
303
304
|
selected: resolution.selected,
|
|
304
305
|
thinkingLevel: state.thinkingLevel,
|
|
305
|
-
rememberThinkingLevelChanges:
|
|
306
|
+
rememberThinkingLevelChanges:
|
|
307
|
+
!sameAsMainThinkingLevel && effectiveRememberThinkingLevelChanges(settings),
|
|
306
308
|
state,
|
|
307
309
|
ctx: fullscreenCtx,
|
|
308
310
|
});
|
package/src/menu.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { Component, TUI } from "@earendil-works/pi-tui";
|
|
|
7
7
|
import type { MenuContext, RunMenuResult } from "@narumitw/pi-tui-kit";
|
|
8
8
|
import {
|
|
9
9
|
type BtwSettings,
|
|
10
|
+
type BtwSettingsPatch,
|
|
10
11
|
btwSettingsPath,
|
|
11
12
|
effectiveRememberThinkingLevelChanges,
|
|
12
13
|
readBtwSettings,
|
|
@@ -35,7 +36,7 @@ export interface ShowBtwCommandMenuOptions {
|
|
|
35
36
|
settingsPath?: string;
|
|
36
37
|
readSettings?: typeof readBtwSettings;
|
|
37
38
|
updateSettings?: (
|
|
38
|
-
patch:
|
|
39
|
+
patch: BtwSettingsPatch,
|
|
39
40
|
options: UpdateBtwSettingsOptions,
|
|
40
41
|
) => Promise<BtwSettings>;
|
|
41
42
|
}
|
|
@@ -44,6 +45,7 @@ export type BtwCommandMenuResult = "start" | "closed" | { kind: "resume"; thread
|
|
|
44
45
|
|
|
45
46
|
type BtwMenuScreen = "main" | "resume" | "settings" | "invalid";
|
|
46
47
|
type BtwMenuAction = "start" | "resume" | "set-thinking" | "set-remember";
|
|
48
|
+
const SAME_AS_MAIN_THREAD = "Same as main thread";
|
|
47
49
|
type BtwCustomOptions = Parameters<ExtensionCommandContext["ui"]["custom"]>[1];
|
|
48
50
|
|
|
49
51
|
type BtwCustomFactory<T> = (
|
|
@@ -79,8 +81,22 @@ export async function showBtwCommandMenu(
|
|
|
79
81
|
}
|
|
80
82
|
return { kind: "valid", settings: loaded.kind === "loaded" ? loaded.settings : {} };
|
|
81
83
|
};
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
+
const currentMainThinkingLevel = clampToAvailableThinkingLevel(
|
|
85
|
+
options.currentThinkingLevel,
|
|
86
|
+
levels,
|
|
87
|
+
);
|
|
88
|
+
const displayThinkingLevel = (settings: BtwSettings): string =>
|
|
89
|
+
settings.thinkingLevel === undefined
|
|
90
|
+
? SAME_AS_MAIN_THREAD
|
|
91
|
+
: clampToAvailableThinkingLevel(settings.thinkingLevel, levels);
|
|
92
|
+
const displayThinkingSummary = (settings: BtwSettings): string =>
|
|
93
|
+
settings.thinkingLevel === undefined
|
|
94
|
+
? `${SAME_AS_MAIN_THREAD} (currently ${currentMainThinkingLevel})`
|
|
95
|
+
: displayThinkingLevel(settings);
|
|
96
|
+
const displayRememberSummary = (settings: BtwSettings): string => {
|
|
97
|
+
const value = effectiveRememberThinkingLevelChanges(settings) ? "On" : "Off";
|
|
98
|
+
return settings.thinkingLevel === undefined ? `${value} (fixed levels only)` : value;
|
|
99
|
+
};
|
|
84
100
|
|
|
85
101
|
const menu = defineMenu<BtwMenuState, BtwMenuScreen, BtwMenuAction, MenuContext>({
|
|
86
102
|
start: "main",
|
|
@@ -89,7 +105,7 @@ export async function showBtwCommandMenu(
|
|
|
89
105
|
kind: "actions",
|
|
90
106
|
title: "Pi BTW",
|
|
91
107
|
lines: [
|
|
92
|
-
`Thinking: ${
|
|
108
|
+
`Thinking: ${displayThinkingSummary(state.settings)} · Remember changes: ${displayRememberSummary(state.settings)}`,
|
|
93
109
|
],
|
|
94
110
|
items: [
|
|
95
111
|
{
|
|
@@ -111,7 +127,7 @@ export async function showBtwCommandMenu(
|
|
|
111
127
|
{
|
|
112
128
|
id: "settings",
|
|
113
129
|
label: "Settings",
|
|
114
|
-
description: "Choose pi-btw thinking and
|
|
130
|
+
description: "Choose pi-btw thinking level and fixed-level shortcut memory",
|
|
115
131
|
to: state.kind === "invalid" ? "invalid" : "settings",
|
|
116
132
|
},
|
|
117
133
|
],
|
|
@@ -138,15 +154,15 @@ export async function showBtwCommandMenu(
|
|
|
138
154
|
{
|
|
139
155
|
id: "thinkingLevel",
|
|
140
156
|
label: "Thinking level",
|
|
141
|
-
description:
|
|
157
|
+
description: `Set the starting level for future pi-btw side threads. Currently ${currentMainThinkingLevel}.`,
|
|
142
158
|
currentValue: displayThinkingLevel(state.settings),
|
|
143
|
-
values: levels,
|
|
159
|
+
values: [SAME_AS_MAIN_THREAD, ...levels],
|
|
144
160
|
action: "set-thinking",
|
|
145
161
|
},
|
|
146
162
|
{
|
|
147
163
|
id: "rememberThinkingLevelChanges",
|
|
148
164
|
label: "Remember thinking level changes",
|
|
149
|
-
description: "Save
|
|
165
|
+
description: "Save shortcut changes for fixed thinking levels to pi-btw.json.",
|
|
150
166
|
currentValue: effectiveRememberThinkingLevelChanges(state.settings) ? "On" : "Off",
|
|
151
167
|
values: ["On", "Off"],
|
|
152
168
|
action: "set-remember",
|
|
@@ -176,12 +192,16 @@ export async function showBtwCommandMenu(
|
|
|
176
192
|
return { kind: "close" } as const;
|
|
177
193
|
},
|
|
178
194
|
"set-thinking": async ({ value, signal }) => {
|
|
179
|
-
if (!value
|
|
195
|
+
if (!value) return { kind: "rejected" };
|
|
196
|
+
const patch =
|
|
197
|
+
value === SAME_AS_MAIN_THREAD
|
|
198
|
+
? ({ thinkingLevel: undefined } satisfies BtwSettingsPatch)
|
|
199
|
+
: levels.includes(value as BtwThinkingLevel)
|
|
200
|
+
? ({ thinkingLevel: value as BtwThinkingLevel } satisfies BtwSettingsPatch)
|
|
201
|
+
: undefined;
|
|
202
|
+
if (!patch) return { kind: "rejected" };
|
|
180
203
|
try {
|
|
181
|
-
await updateSettings(
|
|
182
|
-
{ thinkingLevel: value as BtwThinkingLevel },
|
|
183
|
-
{ settingsPath, signal },
|
|
184
|
-
);
|
|
204
|
+
await updateSettings(patch, { settingsPath, signal });
|
|
185
205
|
if (signal.aborted) return { kind: "rejected" };
|
|
186
206
|
notifySafely(ctx, `Pi BTW thinking level: ${value}.`, "info");
|
|
187
207
|
return { kind: "stay" };
|
package/src/settings.ts
CHANGED
|
@@ -20,6 +20,11 @@ export type BtwSettingsLoadResult =
|
|
|
20
20
|
| { kind: "invalid"; reason: string }
|
|
21
21
|
| { kind: "loaded"; settings: BtwSettings };
|
|
22
22
|
|
|
23
|
+
export interface BtwSettingsPatch {
|
|
24
|
+
thinkingLevel?: BtwThinkingLevel;
|
|
25
|
+
rememberThinkingLevelChanges?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
export interface UpdateBtwSettingsOptions {
|
|
24
29
|
settingsPath?: string;
|
|
25
30
|
signal?: AbortSignal;
|
|
@@ -77,14 +82,14 @@ export async function readBtwSettings(
|
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
export function updateBtwSettings(
|
|
80
|
-
patch:
|
|
85
|
+
patch: BtwSettingsPatch,
|
|
81
86
|
options: UpdateBtwSettingsOptions = {},
|
|
82
87
|
): Promise<BtwSettings> {
|
|
83
88
|
const settingsPath = options.settingsPath ?? btwSettingsPath();
|
|
84
89
|
return enqueueMutation(settingsPath, async () => {
|
|
85
90
|
options.signal?.throwIfAborted();
|
|
86
91
|
const current = await readSettingsDocumentForUpdate(settingsPath);
|
|
87
|
-
const updated
|
|
92
|
+
const updated = applyBtwSettingsPatch(current, patch);
|
|
88
93
|
const settings = normalizeBtwSettings(updated);
|
|
89
94
|
if (!settings) throw invalidSettingsError(settingsPath, "invalid settings shape");
|
|
90
95
|
await publishSettings(settingsPath, updated, options.signal, options.beforeRename);
|
|
@@ -216,6 +221,21 @@ async function publishSettings(
|
|
|
216
221
|
}
|
|
217
222
|
}
|
|
218
223
|
|
|
224
|
+
function applyBtwSettingsPatch(
|
|
225
|
+
current: SettingsDocument,
|
|
226
|
+
patch: BtwSettingsPatch,
|
|
227
|
+
): SettingsDocument {
|
|
228
|
+
const updated: SettingsDocument = { ...current };
|
|
229
|
+
if (Object.hasOwn(patch, "thinkingLevel")) {
|
|
230
|
+
if (patch.thinkingLevel === undefined) delete updated.thinkingLevel;
|
|
231
|
+
else updated.thinkingLevel = patch.thinkingLevel;
|
|
232
|
+
}
|
|
233
|
+
if (Object.hasOwn(patch, "rememberThinkingLevelChanges")) {
|
|
234
|
+
updated.rememberThinkingLevelChanges = patch.rememberThinkingLevelChanges;
|
|
235
|
+
}
|
|
236
|
+
return updated;
|
|
237
|
+
}
|
|
238
|
+
|
|
219
239
|
function isSettingsDocument(value: unknown): value is SettingsDocument {
|
|
220
240
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
221
241
|
}
|