pi-sessions 0.8.0 → 0.10.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 +74 -37
- package/dist/session-messaging/broker/process.js +234 -0
- package/dist/shared/session-broker/framing.js +58 -0
- package/dist/shared/session-broker/protocol.js +163 -0
- package/dist/shared/session-broker/socket-path.js +19 -0
- package/dist/shared/typebox.js +36 -0
- package/extensions/pi-sessions.ts +125 -0
- package/extensions/session-ask/agent.ts +34 -14
- package/extensions/{session-ask.ts → session-ask/install.ts} +73 -90
- package/extensions/session-ask/navigate.ts +3 -1
- package/extensions/session-ask/presenter.ts +23 -0
- package/extensions/session-ask/renderer.ts +63 -0
- package/extensions/session-ask/tool-contract.ts +27 -0
- package/extensions/session-ask/view-model.ts +18 -0
- package/extensions/session-auto-title/generate.ts +18 -18
- package/extensions/{session-auto-title.ts → session-auto-title/install.ts} +60 -53
- package/extensions/session-auto-title/model.ts +25 -17
- package/extensions/session-auto-title/retitle.ts +17 -18
- package/extensions/session-auto-title/wizard.ts +12 -11
- package/extensions/session-handoff/board-view-model.ts +179 -0
- package/extensions/session-handoff/board.ts +663 -0
- package/extensions/session-handoff/bootstrap.ts +172 -0
- package/extensions/session-handoff/extract.ts +129 -132
- package/extensions/session-handoff/install.ts +225 -0
- package/extensions/session-handoff/kickoff.ts +92 -0
- package/extensions/session-handoff/launch/backend.ts +16 -0
- package/extensions/session-handoff/launch/deferred.ts +20 -0
- package/extensions/session-handoff/launch/ghostty.ts +99 -0
- package/extensions/session-handoff/launch/resolution.ts +57 -0
- package/extensions/session-handoff/launch/shell.ts +7 -0
- package/extensions/session-handoff/launch/tmux.ts +31 -0
- package/extensions/session-handoff/launch-options.ts +61 -0
- package/extensions/session-handoff/launch-target.ts +91 -0
- package/extensions/session-handoff/metadata.ts +194 -56
- package/extensions/session-handoff/model.ts +58 -0
- package/extensions/session-handoff/query.ts +0 -1
- package/extensions/session-handoff/receipt.ts +96 -0
- package/extensions/session-handoff/review.ts +2 -28
- package/extensions/session-handoff/spawn.ts +76 -181
- package/extensions/session-handoff/strong-modal.ts +13 -0
- package/extensions/session-handoff/tool-contract.ts +12 -0
- package/extensions/session-handoff/tool-presenter.ts +35 -0
- package/extensions/session-handoff/tool-renderer.ts +66 -0
- package/extensions/session-handoff/tool-schema.ts +54 -0
- package/extensions/session-handoff/tool-view-model.ts +49 -0
- package/extensions/session-handoff/tool.ts +206 -0
- package/extensions/session-handoff/ui.ts +66 -0
- package/extensions/session-hooks/install.ts +75 -0
- package/extensions/{session-index.ts → session-index/install.ts} +9 -7
- package/extensions/session-messaging/broker/process.ts +21 -28
- package/extensions/session-messaging/broker/spawn.ts +12 -7
- package/extensions/session-messaging/install.ts +78 -0
- package/extensions/session-messaging/pi/cancel-session-presenter.ts +64 -0
- package/extensions/session-messaging/pi/incoming-message-presenter.ts +32 -0
- package/extensions/session-messaging/pi/incoming-message-view-model.ts +20 -0
- package/extensions/session-messaging/pi/incoming-runtime.ts +27 -23
- package/extensions/session-messaging/pi/message-contracts.ts +32 -0
- package/extensions/session-messaging/pi/renderer.ts +19 -12
- package/extensions/session-messaging/pi/send-message-presenter.ts +39 -0
- package/extensions/session-messaging/pi/send-message-view-model.ts +54 -0
- package/extensions/session-messaging/pi/service.ts +262 -81
- package/extensions/session-messaging/pi/tools.ts +184 -40
- package/extensions/session-search/extract.ts +60 -14
- package/extensions/session-search/hooks.ts +10 -13
- package/extensions/session-search/install.ts +373 -0
- package/extensions/session-search/renderer.ts +195 -0
- package/extensions/session-search/tool-contract.ts +51 -0
- package/extensions/shared/composition.ts +20 -0
- package/extensions/shared/errors.ts +3 -0
- package/extensions/shared/model-resolution.ts +73 -0
- package/extensions/shared/model-runtime.ts +33 -0
- package/extensions/shared/model.ts +7 -10
- package/extensions/shared/rendering/collapsible-text.ts +89 -0
- package/extensions/shared/rendering/expandable-content-layout.ts +84 -0
- package/extensions/shared/rendering/theme.ts +5 -0
- package/extensions/shared/session-broker/client.ts +30 -29
- package/extensions/shared/session-broker/protocol.ts +128 -10
- package/extensions/shared/session-index/common.ts +5 -5
- package/extensions/shared/session-index/lineage.ts +0 -3
- package/extensions/shared/session-index/schema.ts +0 -1
- package/extensions/shared/session-index/scoring.ts +1 -2
- package/extensions/shared/session-index/search.ts +11 -4
- package/extensions/shared/session-index/store.ts +4 -9
- package/extensions/shared/settings.ts +83 -40
- package/extensions/shared/text.ts +5 -0
- package/extensions/shared/thinking-levels.ts +22 -0
- package/extensions/shared/tmux.ts +205 -0
- package/extensions/subagents/cancel.ts +111 -0
- package/extensions/subagents/classify.ts +58 -0
- package/extensions/subagents/install.ts +229 -0
- package/extensions/subagents/launch-target.ts +75 -0
- package/extensions/subagents/ledger.ts +217 -0
- package/extensions/subagents/reconcile.ts +386 -0
- package/extensions/subagents/report-message-presenter.ts +36 -0
- package/extensions/subagents/report-message-renderer.ts +21 -0
- package/extensions/subagents/report-message-view-model.ts +29 -0
- package/extensions/subagents/report.ts +159 -0
- package/extensions/subagents/roster.ts +262 -0
- package/extensions/subagents/settle.ts +182 -0
- package/extensions/subagents/wake.ts +173 -0
- package/images/handoff-board-subagents.png +0 -0
- package/images/handoff-board-user-sessions.png +0 -0
- package/images/handoff-subagent-report.png +0 -0
- package/images/session-handoff-tool.png +0 -0
- package/package.json +16 -18
- package/extensions/session-handoff.ts +0 -741
- package/extensions/session-hooks.ts +0 -75
- package/extensions/session-messaging/pi/message-view.ts +0 -131
- package/extensions/session-messaging.ts +0 -30
- package/extensions/session-search.ts +0 -419
- package/extensions/shared/session-broker/active.ts +0 -26
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
4
5
|
import type { Api, Model, TextContent, UserMessage } from "@earendil-works/pi-ai";
|
|
5
|
-
import {
|
|
6
|
-
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import type { ModelRuntime } from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import type { AutoTitleContext } from "./context.ts";
|
|
8
8
|
import type { AutoTitleTrigger } from "./state.ts";
|
|
9
9
|
|
|
@@ -17,6 +17,12 @@ export interface AutoTitleFailure {
|
|
|
17
17
|
message: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
export interface AutoTitleGeneration {
|
|
21
|
+
systemPrompt: string;
|
|
22
|
+
timeoutMs: number;
|
|
23
|
+
thinkingLevel: ThinkingLevel | undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
export type AutoTitleGenerationResult =
|
|
21
27
|
| {
|
|
22
28
|
ok: true;
|
|
@@ -28,12 +34,11 @@ export type AutoTitleGenerationResult =
|
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
export async function generateAutoTitle(
|
|
31
|
-
|
|
37
|
+
modelRuntime: ModelRuntime,
|
|
32
38
|
model: Model<Api>,
|
|
33
39
|
context: AutoTitleContext,
|
|
34
40
|
trigger: AutoTitleTrigger,
|
|
35
|
-
|
|
36
|
-
timeoutMs: number,
|
|
41
|
+
generation: AutoTitleGeneration,
|
|
37
42
|
): Promise<AutoTitleGenerationResult> {
|
|
38
43
|
if (!context.conversationText) {
|
|
39
44
|
return {
|
|
@@ -46,16 +51,11 @@ export async function generateAutoTitle(
|
|
|
46
51
|
};
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
50
|
-
if (!auth.ok) {
|
|
51
|
-
return {
|
|
52
|
-
ok: false,
|
|
53
|
-
failure: createAutoTitleFailure(trigger, model, "Failed to authenticate auto-title model."),
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
54
|
const shouldPreserveTitle = trigger === "periodic" && Boolean(context.currentTitle?.trim());
|
|
58
|
-
const resolvedSystemPrompt = buildAutoTitleSystemPrompt(
|
|
55
|
+
const resolvedSystemPrompt = buildAutoTitleSystemPrompt(
|
|
56
|
+
generation.systemPrompt,
|
|
57
|
+
shouldPreserveTitle,
|
|
58
|
+
);
|
|
59
59
|
const userPrompt = buildAutoTitlePrompt(context, resolvedSystemPrompt, shouldPreserveTitle);
|
|
60
60
|
const message: UserMessage = {
|
|
61
61
|
role: "user",
|
|
@@ -64,7 +64,8 @@ export async function generateAutoTitle(
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
const abortController = new AbortController();
|
|
67
|
-
const timeoutId = setTimeout(() => abortController.abort(), timeoutMs);
|
|
67
|
+
const timeoutId = setTimeout(() => abortController.abort(), generation.timeoutMs);
|
|
68
|
+
const thinkingLevel = generation.thinkingLevel;
|
|
68
69
|
|
|
69
70
|
try {
|
|
70
71
|
const requestContext = {
|
|
@@ -72,10 +73,9 @@ export async function generateAutoTitle(
|
|
|
72
73
|
messages: [message],
|
|
73
74
|
};
|
|
74
75
|
writeAutoTitleDebugRequest(model, trigger, requestContext);
|
|
75
|
-
const response = await completeSimple(model, requestContext, {
|
|
76
|
-
...(auth.apiKey && { apiKey: auth.apiKey }),
|
|
77
|
-
...(auth.headers && { headers: auth.headers }),
|
|
76
|
+
const response = await modelRuntime.completeSimple(model, requestContext, {
|
|
78
77
|
maxTokens: AUTO_TITLE_MAX_TOKENS,
|
|
78
|
+
...(thinkingLevel && thinkingLevel !== "off" ? { reasoning: thinkingLevel } : {}),
|
|
79
79
|
signal: abortController.signal,
|
|
80
80
|
});
|
|
81
81
|
writeAutoTitleDebugResponse(model, trigger, response);
|
|
@@ -3,37 +3,30 @@ import type {
|
|
|
3
3
|
ExtensionAPI,
|
|
4
4
|
ExtensionCommandContext,
|
|
5
5
|
ExtensionContext,
|
|
6
|
-
|
|
6
|
+
ModelRuntime,
|
|
7
7
|
TurnEndEvent,
|
|
8
8
|
} from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import type { SessionLifecycle } from "../shared/composition.ts";
|
|
10
|
+
import type { ModelRuntimeProvider } from "../shared/model-runtime.ts";
|
|
11
|
+
import { isTuiMode } from "../shared/pi-mode.ts";
|
|
12
|
+
import type { SessionSettings } from "../shared/settings.ts";
|
|
9
13
|
import {
|
|
10
14
|
createSessionAutoTitleCommandHandler,
|
|
11
15
|
getRetitleArgumentCompletions,
|
|
12
16
|
type RetitleCommandInvocation,
|
|
13
17
|
type RetitleCommandOutcome,
|
|
14
|
-
} from "./
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "./session-auto-title/controller.ts";
|
|
19
|
-
import { resolveAutoTitleModel } from "./session-auto-title/model.ts";
|
|
18
|
+
} from "./command.ts";
|
|
19
|
+
import { createSessionAutoTitleController, type SessionAutoTitleController } from "./controller.ts";
|
|
20
|
+
import type { AutoTitleGeneration } from "./generate.ts";
|
|
21
|
+
import { type AutoTitleModelResolution, resolveAutoTitleModel } from "./model.ts";
|
|
20
22
|
import {
|
|
21
23
|
buildRetitleScopeScan,
|
|
22
24
|
notifyBulkRetitleResult,
|
|
23
25
|
persistAutoTitleState,
|
|
24
26
|
runBulkRetitle,
|
|
25
27
|
runRetitlePlan,
|
|
26
|
-
} from "./
|
|
27
|
-
import { showRetitleWizard } from "./
|
|
28
|
-
import { isTuiMode } from "./shared/pi-mode.ts";
|
|
29
|
-
import { loadSettings } from "./shared/settings.ts";
|
|
30
|
-
|
|
31
|
-
export {
|
|
32
|
-
createSessionAutoTitleCommandHandler,
|
|
33
|
-
getRetitleArgumentCompletions,
|
|
34
|
-
parseRetitleCommand,
|
|
35
|
-
TITLE_USAGE,
|
|
36
|
-
} from "./session-auto-title/command.ts";
|
|
28
|
+
} from "./retitle.ts";
|
|
29
|
+
import { showRetitleWizard } from "./wizard.ts";
|
|
37
30
|
|
|
38
31
|
interface TitleRunState {
|
|
39
32
|
controller: SessionAutoTitleController;
|
|
@@ -42,12 +35,26 @@ interface TitleRunState {
|
|
|
42
35
|
clearInFlight: () => void;
|
|
43
36
|
}
|
|
44
37
|
|
|
45
|
-
export
|
|
46
|
-
|
|
38
|
+
export function installAutoTitle(
|
|
39
|
+
pi: ExtensionAPI,
|
|
40
|
+
deps: {
|
|
41
|
+
settings: SessionSettings;
|
|
42
|
+
getModelRuntime: ModelRuntimeProvider;
|
|
43
|
+
getSessionEpoch: () => number;
|
|
44
|
+
},
|
|
45
|
+
): SessionLifecycle {
|
|
46
|
+
const { settings, getModelRuntime, getSessionEpoch } = deps;
|
|
47
47
|
const controller = createSessionAutoTitleController(settings.autoTitle);
|
|
48
|
-
let sessionEpoch = 0;
|
|
49
48
|
let titleWorkInFlight: Promise<void> | undefined;
|
|
50
|
-
|
|
49
|
+
|
|
50
|
+
// An explicit thinkingLevel setting overrides a thinking suffix on the configured model.
|
|
51
|
+
const buildGeneration = (
|
|
52
|
+
resolution: AutoTitleModelResolution | undefined,
|
|
53
|
+
): AutoTitleGeneration => ({
|
|
54
|
+
systemPrompt: settings.autoTitle.prompt,
|
|
55
|
+
timeoutMs: settings.autoTitle.timeoutMs,
|
|
56
|
+
thinkingLevel: settings.autoTitle.thinkingLevel ?? resolution?.thinkingLevel,
|
|
57
|
+
});
|
|
51
58
|
|
|
52
59
|
pi.registerCommand("title", {
|
|
53
60
|
description: "Generate titles for this session, this folder, or all of Pi",
|
|
@@ -58,12 +65,13 @@ export default function sessionAutoTitleExtension(pi: ExtensionAPI): void {
|
|
|
58
65
|
await titleWorkInFlight;
|
|
59
66
|
}
|
|
60
67
|
|
|
61
|
-
const
|
|
68
|
+
const modelRuntime = await getModelRuntime(ctx.modelRegistry);
|
|
69
|
+
const resolution = resolveAutoTitleModel(modelRuntime, ctx.model, settings.autoTitle.model);
|
|
62
70
|
return handleTitleInvocation(
|
|
63
71
|
pi,
|
|
64
72
|
{
|
|
65
73
|
controller,
|
|
66
|
-
getSessionEpoch
|
|
74
|
+
getSessionEpoch,
|
|
67
75
|
setInFlight: (work) => {
|
|
68
76
|
titleWorkInFlight = work;
|
|
69
77
|
},
|
|
@@ -72,21 +80,15 @@ export default function sessionAutoTitleExtension(pi: ExtensionAPI): void {
|
|
|
72
80
|
},
|
|
73
81
|
},
|
|
74
82
|
ctx,
|
|
75
|
-
|
|
83
|
+
modelRuntime,
|
|
84
|
+
resolution?.model,
|
|
76
85
|
invocation,
|
|
77
|
-
|
|
78
|
-
settings.autoTitle.timeoutMs,
|
|
86
|
+
buildGeneration(resolution),
|
|
79
87
|
);
|
|
80
88
|
},
|
|
81
89
|
),
|
|
82
90
|
});
|
|
83
91
|
|
|
84
|
-
pi.on("session_start", async (_event: SessionStartEvent, ctx: ExtensionContext) => {
|
|
85
|
-
sessionEpoch += 1;
|
|
86
|
-
resolvedModel = resolveAutoTitleModel(ctx, settings.autoTitle.model)?.model;
|
|
87
|
-
persistAutoTitleState(pi, controller.handleSessionStart(ctx));
|
|
88
|
-
});
|
|
89
|
-
|
|
90
92
|
pi.on("turn_end", async (_event: TurnEndEvent, ctx: ExtensionContext) => {
|
|
91
93
|
const result = controller.handleTurnEnd(ctx);
|
|
92
94
|
persistAutoTitleState(pi, result.persistedState);
|
|
@@ -95,17 +97,19 @@ export default function sessionAutoTitleExtension(pi: ExtensionAPI): void {
|
|
|
95
97
|
return;
|
|
96
98
|
}
|
|
97
99
|
|
|
100
|
+
const modelRuntime = await getModelRuntime(ctx.modelRegistry);
|
|
101
|
+
const resolution = resolveAutoTitleModel(modelRuntime, ctx.model, settings.autoTitle.model);
|
|
98
102
|
titleWorkInFlight = runRetitlePlan({
|
|
99
103
|
pi,
|
|
100
104
|
controller,
|
|
101
105
|
ctx,
|
|
102
|
-
|
|
106
|
+
modelRuntime,
|
|
107
|
+
model: resolution?.model,
|
|
103
108
|
isManual: false,
|
|
104
109
|
existingPlan: result.plan,
|
|
105
|
-
getSessionEpoch
|
|
110
|
+
getSessionEpoch,
|
|
106
111
|
notifyOnSuccess: false,
|
|
107
|
-
|
|
108
|
-
timeoutMs: settings.autoTitle.timeoutMs,
|
|
112
|
+
generation: buildGeneration(resolution),
|
|
109
113
|
})
|
|
110
114
|
.then((outcome) => {
|
|
111
115
|
if (outcome.ok) {
|
|
@@ -126,31 +130,34 @@ export default function sessionAutoTitleExtension(pi: ExtensionAPI): void {
|
|
|
126
130
|
});
|
|
127
131
|
});
|
|
128
132
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
return {
|
|
134
|
+
onSessionStart(_event, ctx) {
|
|
135
|
+
persistAutoTitleState(pi, controller.handleSessionStart(ctx));
|
|
136
|
+
},
|
|
137
|
+
onSessionShutdown() {
|
|
138
|
+
controller.handleSessionShutdown();
|
|
139
|
+
titleWorkInFlight = undefined;
|
|
140
|
+
},
|
|
141
|
+
};
|
|
135
142
|
}
|
|
136
143
|
|
|
137
144
|
async function handleTitleInvocation(
|
|
138
145
|
pi: ExtensionAPI,
|
|
139
146
|
state: TitleRunState,
|
|
140
147
|
ctx: ExtensionCommandContext,
|
|
148
|
+
modelRuntime: ModelRuntime,
|
|
141
149
|
model: Model<Api> | undefined,
|
|
142
150
|
invocation: RetitleCommandInvocation,
|
|
143
|
-
|
|
144
|
-
timeoutMs: number,
|
|
151
|
+
generation: AutoTitleGeneration,
|
|
145
152
|
): Promise<RetitleCommandOutcome> {
|
|
146
153
|
const retitleOpts = {
|
|
147
154
|
pi,
|
|
148
155
|
controller: state.controller,
|
|
149
156
|
ctx,
|
|
157
|
+
modelRuntime,
|
|
150
158
|
model,
|
|
151
159
|
isManual: true,
|
|
152
|
-
|
|
153
|
-
timeoutMs,
|
|
160
|
+
generation,
|
|
154
161
|
getSessionEpoch: state.getSessionEpoch,
|
|
155
162
|
};
|
|
156
163
|
|
|
@@ -173,10 +180,10 @@ async function handleTitleInvocation(
|
|
|
173
180
|
pi,
|
|
174
181
|
state.controller,
|
|
175
182
|
ctx,
|
|
183
|
+
modelRuntime,
|
|
176
184
|
model,
|
|
177
185
|
state.getSessionEpoch,
|
|
178
|
-
|
|
179
|
-
timeoutMs,
|
|
186
|
+
generation,
|
|
180
187
|
);
|
|
181
188
|
}
|
|
182
189
|
|
|
@@ -189,10 +196,10 @@ async function handleTitleInvocation(
|
|
|
189
196
|
pi,
|
|
190
197
|
state.controller,
|
|
191
198
|
ctx,
|
|
199
|
+
modelRuntime,
|
|
192
200
|
model,
|
|
193
201
|
state.getSessionEpoch,
|
|
194
|
-
|
|
195
|
-
timeoutMs,
|
|
202
|
+
generation,
|
|
196
203
|
{
|
|
197
204
|
initialInvocation: {
|
|
198
205
|
scope: invocation.scope,
|
|
@@ -209,12 +216,12 @@ async function handleTitleInvocation(
|
|
|
209
216
|
pi,
|
|
210
217
|
state.controller,
|
|
211
218
|
ctx,
|
|
219
|
+
modelRuntime,
|
|
212
220
|
model,
|
|
213
221
|
scan,
|
|
214
222
|
mode,
|
|
215
223
|
state.getSessionEpoch,
|
|
216
|
-
|
|
217
|
-
timeoutMs,
|
|
224
|
+
generation,
|
|
218
225
|
);
|
|
219
226
|
notifyBulkRetitleResult(ctx, scan, mode, result);
|
|
220
227
|
return "success";
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
1
2
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
2
|
-
import type {
|
|
3
|
-
import { findModelByReference } from "../shared/model.ts";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
import type { ModelRuntime } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { type ExactModelReference, findModelByReference } from "../shared/model.ts";
|
|
5
|
+
import { resolveAuthenticatedModel } from "../shared/model-resolution.ts";
|
|
6
|
+
import { freshenModel } from "../shared/model-runtime.ts";
|
|
7
|
+
|
|
8
|
+
const DEFAULT_AUTO_TITLE_FALLBACK_MODELS: readonly ExactModelReference[] = [
|
|
9
|
+
{ provider: "openai-codex", modelId: "gpt-5.6-luna" },
|
|
10
|
+
{ provider: "openai", modelId: "gpt-5.6-luna" },
|
|
11
|
+
{ provider: "anthropic", modelId: "claude-haiku-4-5" },
|
|
12
|
+
{ provider: "google", modelId: "gemini-flash-lite-latest" },
|
|
10
13
|
] as const;
|
|
11
14
|
|
|
12
15
|
export type AutoTitleModelSource = "configured" | "fallback" | "current";
|
|
@@ -14,24 +17,29 @@ export type AutoTitleModelSource = "configured" | "fallback" | "current";
|
|
|
14
17
|
export interface AutoTitleModelResolution {
|
|
15
18
|
model: Model<Api>;
|
|
16
19
|
source: AutoTitleModelSource;
|
|
20
|
+
thinkingLevel?: ThinkingLevel | undefined;
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
export function resolveAutoTitleModel(
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
modelRuntime: ModelRuntime,
|
|
25
|
+
currentModel: Model<Api> | undefined,
|
|
26
|
+
configuredModel: string | undefined,
|
|
22
27
|
): AutoTitleModelResolution | undefined {
|
|
23
|
-
const availableModels = ctx.modelRegistry.getAvailable();
|
|
24
|
-
|
|
25
28
|
if (configuredModel) {
|
|
26
|
-
const
|
|
27
|
-
|
|
29
|
+
const configured = resolveAuthenticatedModel({
|
|
30
|
+
modelRuntime,
|
|
31
|
+
modelPattern: configuredModel,
|
|
32
|
+
});
|
|
33
|
+
if (configured.ok) {
|
|
28
34
|
return {
|
|
29
|
-
model:
|
|
35
|
+
model: configured.model,
|
|
30
36
|
source: "configured",
|
|
37
|
+
thinkingLevel: configured.thinkingLevel,
|
|
31
38
|
};
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
|
|
42
|
+
const availableModels = modelRuntime.getAvailableSnapshot();
|
|
35
43
|
for (const fallbackReference of DEFAULT_AUTO_TITLE_FALLBACK_MODELS) {
|
|
36
44
|
const fallbackMatch = findModelByReference(availableModels, fallbackReference);
|
|
37
45
|
if (fallbackMatch) {
|
|
@@ -42,12 +50,12 @@ export function resolveAutoTitleModel(
|
|
|
42
50
|
}
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
if (!
|
|
53
|
+
if (!currentModel) {
|
|
46
54
|
return undefined;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
return {
|
|
50
|
-
model:
|
|
58
|
+
model: freshenModel(modelRuntime, currentModel),
|
|
51
59
|
source: "current",
|
|
52
60
|
};
|
|
53
61
|
}
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
ExtensionAPI,
|
|
4
4
|
ExtensionCommandContext,
|
|
5
5
|
ExtensionContext,
|
|
6
|
+
ModelRuntime,
|
|
6
7
|
SessionInfo,
|
|
7
8
|
} from "@earendil-works/pi-coding-agent";
|
|
8
9
|
import { SessionManager } from "@earendil-works/pi-coding-agent";
|
|
@@ -10,6 +11,7 @@ import type { RetitleMode, RetitleScope } from "./command.ts";
|
|
|
10
11
|
import { buildAutoTitleContext } from "./context.ts";
|
|
11
12
|
import type { AutoTitleTriggerPlan, SessionAutoTitleController } from "./controller.ts";
|
|
12
13
|
import {
|
|
14
|
+
type AutoTitleGeneration,
|
|
13
15
|
type AutoTitleGenerationResult,
|
|
14
16
|
createAutoTitleFailure,
|
|
15
17
|
generateAutoTitle,
|
|
@@ -53,12 +55,12 @@ export async function runBulkRetitle(
|
|
|
53
55
|
pi: ExtensionAPI,
|
|
54
56
|
controller: SessionAutoTitleController,
|
|
55
57
|
ctx: ExtensionCommandContext,
|
|
58
|
+
modelRuntime: ModelRuntime,
|
|
56
59
|
model: Model<Api> | undefined,
|
|
57
60
|
scan: RetitleScopeScan,
|
|
58
61
|
mode: RetitleMode,
|
|
59
62
|
getSessionEpoch: () => number,
|
|
60
|
-
|
|
61
|
-
timeoutMs: number,
|
|
63
|
+
generation: AutoTitleGeneration,
|
|
62
64
|
): Promise<BulkRetitleResult> {
|
|
63
65
|
const result: BulkRetitleResult = {
|
|
64
66
|
attempted: 0,
|
|
@@ -83,10 +85,10 @@ export async function runBulkRetitle(
|
|
|
83
85
|
pi,
|
|
84
86
|
controller,
|
|
85
87
|
ctx,
|
|
88
|
+
modelRuntime,
|
|
86
89
|
model,
|
|
87
90
|
isManual: true,
|
|
88
|
-
|
|
89
|
-
timeoutMs,
|
|
91
|
+
generation,
|
|
90
92
|
getSessionEpoch,
|
|
91
93
|
notifyOnSuccess: false,
|
|
92
94
|
});
|
|
@@ -94,7 +96,7 @@ export async function runBulkRetitle(
|
|
|
94
96
|
continue;
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
const outcome = await retitleStoredSession(
|
|
99
|
+
const outcome = await retitleStoredSession(modelRuntime, model, session.path, generation);
|
|
98
100
|
result[outcome] += 1;
|
|
99
101
|
}
|
|
100
102
|
|
|
@@ -164,10 +166,10 @@ export interface RetitlePlanOptions {
|
|
|
164
166
|
pi: ExtensionAPI;
|
|
165
167
|
controller: SessionAutoTitleController;
|
|
166
168
|
ctx: ExtensionContext;
|
|
169
|
+
modelRuntime: ModelRuntime;
|
|
167
170
|
model: Model<Api> | undefined;
|
|
168
171
|
isManual: boolean;
|
|
169
|
-
|
|
170
|
-
timeoutMs: number;
|
|
172
|
+
generation: AutoTitleGeneration;
|
|
171
173
|
existingPlan?: AutoTitleTriggerPlan;
|
|
172
174
|
getSessionEpoch?: () => number;
|
|
173
175
|
notifyOnSuccess?: boolean;
|
|
@@ -180,10 +182,10 @@ export async function runRetitlePlan(
|
|
|
180
182
|
pi,
|
|
181
183
|
controller,
|
|
182
184
|
ctx,
|
|
185
|
+
modelRuntime,
|
|
183
186
|
model,
|
|
184
187
|
isManual,
|
|
185
|
-
|
|
186
|
-
timeoutMs,
|
|
188
|
+
generation,
|
|
187
189
|
existingPlan,
|
|
188
190
|
getSessionEpoch,
|
|
189
191
|
} = options;
|
|
@@ -218,12 +220,11 @@ export async function runRetitlePlan(
|
|
|
218
220
|
},
|
|
219
221
|
);
|
|
220
222
|
const generatedTitle = await generateAutoTitle(
|
|
221
|
-
|
|
223
|
+
modelRuntime,
|
|
222
224
|
model,
|
|
223
225
|
titleContext,
|
|
224
226
|
plan.reason,
|
|
225
|
-
|
|
226
|
-
timeoutMs,
|
|
227
|
+
generation,
|
|
227
228
|
);
|
|
228
229
|
if (!generatedTitle.ok) {
|
|
229
230
|
return generatedTitle;
|
|
@@ -266,11 +267,10 @@ export function persistAutoTitleState(
|
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
async function retitleStoredSession(
|
|
269
|
-
|
|
270
|
+
modelRuntime: ModelRuntime,
|
|
270
271
|
model: Model<Api>,
|
|
271
272
|
sessionPath: string,
|
|
272
|
-
|
|
273
|
-
timeoutMs: number,
|
|
273
|
+
generation: AutoTitleGeneration,
|
|
274
274
|
): Promise<"retitled" | "unchanged" | "failed"> {
|
|
275
275
|
const sessionManager = SessionManager.open(sessionPath);
|
|
276
276
|
const currentTitle = sessionManager.getSessionName();
|
|
@@ -288,12 +288,11 @@ async function retitleStoredSession(
|
|
|
288
288
|
currentTitle,
|
|
289
289
|
};
|
|
290
290
|
const generatedTitle = await generateAutoTitle(
|
|
291
|
-
|
|
291
|
+
modelRuntime,
|
|
292
292
|
model,
|
|
293
293
|
titleContext,
|
|
294
294
|
plan.reason,
|
|
295
|
-
|
|
296
|
-
timeoutMs,
|
|
295
|
+
generation,
|
|
297
296
|
);
|
|
298
297
|
if (!generatedTitle.ok) {
|
|
299
298
|
return "failed";
|
|
@@ -3,13 +3,14 @@ import {
|
|
|
3
3
|
copyToClipboard,
|
|
4
4
|
type ExtensionAPI,
|
|
5
5
|
type ExtensionCommandContext,
|
|
6
|
+
type ModelRuntime,
|
|
6
7
|
type Theme,
|
|
7
8
|
} from "@earendil-works/pi-coding-agent";
|
|
8
9
|
import type { Focusable, TUI } from "@earendil-works/pi-tui";
|
|
9
10
|
import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
10
11
|
import type { RetitleCommandOutcome, RetitleMode, RetitleScope } from "./command.ts";
|
|
11
12
|
import type { AutoRetitleStatus, SessionAutoTitleController } from "./controller.ts";
|
|
12
|
-
import type { AutoTitleFailure } from "./generate.ts";
|
|
13
|
+
import type { AutoTitleFailure, AutoTitleGeneration } from "./generate.ts";
|
|
13
14
|
import {
|
|
14
15
|
buildBulkRetitleMessage,
|
|
15
16
|
buildRetitleScopeScan,
|
|
@@ -54,10 +55,10 @@ export async function showRetitleWizard(
|
|
|
54
55
|
pi: ExtensionAPI,
|
|
55
56
|
controller: SessionAutoTitleController,
|
|
56
57
|
ctx: ExtensionCommandContext,
|
|
58
|
+
modelRuntime: ModelRuntime,
|
|
57
59
|
model: Model<Api> | undefined,
|
|
58
60
|
getSessionEpoch: () => number,
|
|
59
|
-
|
|
60
|
-
timeoutMs: number,
|
|
61
|
+
generation: AutoTitleGeneration,
|
|
61
62
|
options?: RetitleWizardOptions,
|
|
62
63
|
): Promise<RetitleCommandOutcome> {
|
|
63
64
|
return ctx.ui.custom<RetitleCommandOutcome>(
|
|
@@ -68,10 +69,10 @@ export async function showRetitleWizard(
|
|
|
68
69
|
pi,
|
|
69
70
|
controller,
|
|
70
71
|
ctx,
|
|
72
|
+
modelRuntime,
|
|
71
73
|
model,
|
|
72
74
|
getSessionEpoch,
|
|
73
|
-
|
|
74
|
-
timeoutMs,
|
|
75
|
+
generation,
|
|
75
76
|
done,
|
|
76
77
|
options,
|
|
77
78
|
),
|
|
@@ -98,10 +99,10 @@ class RetitleWizardPanel implements Focusable {
|
|
|
98
99
|
private readonly pi: ExtensionAPI,
|
|
99
100
|
private readonly controller: SessionAutoTitleController,
|
|
100
101
|
private readonly ctx: ExtensionCommandContext,
|
|
102
|
+
private readonly modelRuntime: ModelRuntime,
|
|
101
103
|
private readonly model: Model<Api> | undefined,
|
|
102
104
|
private readonly getSessionEpoch: () => number,
|
|
103
|
-
private readonly
|
|
104
|
-
private readonly timeoutMs: number,
|
|
105
|
+
private readonly generation: AutoTitleGeneration,
|
|
105
106
|
private readonly done: (result: RetitleCommandOutcome) => void,
|
|
106
107
|
options?: RetitleWizardOptions,
|
|
107
108
|
) {
|
|
@@ -250,10 +251,10 @@ class RetitleWizardPanel implements Focusable {
|
|
|
250
251
|
pi: this.pi,
|
|
251
252
|
controller: this.controller,
|
|
252
253
|
ctx: this.ctx,
|
|
254
|
+
modelRuntime: this.modelRuntime,
|
|
253
255
|
model: this.model,
|
|
254
256
|
isManual: true,
|
|
255
|
-
|
|
256
|
-
timeoutMs: this.timeoutMs,
|
|
257
|
+
generation: this.generation,
|
|
257
258
|
getSessionEpoch: this.getSessionEpoch,
|
|
258
259
|
});
|
|
259
260
|
if (result.ok) {
|
|
@@ -309,12 +310,12 @@ class RetitleWizardPanel implements Focusable {
|
|
|
309
310
|
this.pi,
|
|
310
311
|
this.controller,
|
|
311
312
|
this.ctx,
|
|
313
|
+
this.modelRuntime,
|
|
312
314
|
this.model,
|
|
313
315
|
scan,
|
|
314
316
|
mode,
|
|
315
317
|
this.getSessionEpoch,
|
|
316
|
-
this.
|
|
317
|
-
this.timeoutMs,
|
|
318
|
+
this.generation,
|
|
318
319
|
);
|
|
319
320
|
notifyBulkRetitleResult(this.ctx, scan, mode, result);
|
|
320
321
|
this.done(
|