pi-ui-extend 1.0.6 → 1.0.8
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/dist/bundled-extensions/session-title/title-generation-compat.d.ts +2 -13
- package/dist/bundled-extensions/session-title/title-generation-compat.js +1 -10
- package/external/pi-tools-suite/package.json +3 -3
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +8 -2
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +12 -8
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +4 -4
- package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +4 -4
- package/external/pi-tools-suite/src/coding-discipline/index.ts +4 -3
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +2 -2
- package/external/pi-tools-suite/src/dcp/index.ts +4 -0
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +33 -10
- package/external/pi-tools-suite/src/model-completion.ts +12 -18
- package/package.json +4 -4
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { SessionTitleConfig } from "./config.js";
|
|
3
|
-
type TitleModelRegistry =
|
|
4
|
-
find(provider: string, modelId: string): Model<Api> | undefined;
|
|
5
|
-
getApiKeyAndHeaders(model: Model<Api>): Promise<{
|
|
6
|
-
ok: true;
|
|
7
|
-
apiKey?: string;
|
|
8
|
-
headers?: Record<string, string>;
|
|
9
|
-
env?: Record<string, string>;
|
|
10
|
-
} | {
|
|
11
|
-
ok: false;
|
|
12
|
-
error: string;
|
|
13
|
-
}>;
|
|
14
|
-
};
|
|
3
|
+
type TitleModelRegistry = Pick<ModelRegistry, "complete" | "find">;
|
|
15
4
|
/** Extension-side title generation through Pi's public ModelRegistry facade. */
|
|
16
5
|
export declare function generateSessionTitle(input: string, modelRegistry: TitleModelRegistry, config: SessionTitleConfig, modelRef: string, signal: AbortSignal, onWarning?: (message: string) => void): Promise<string | undefined>;
|
|
17
6
|
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { complete } from "@earendil-works/pi-ai/compat";
|
|
2
1
|
import { buildTitlePrompt, parseTitleModelRef, sanitizeSessionTitle, TITLE_SYSTEM_PROMPT, titleResponseText, } from "./title-generation.js";
|
|
3
2
|
/** Extension-side title generation through Pi's public ModelRegistry facade. */
|
|
4
3
|
export async function generateSessionTitle(input, modelRegistry, config, modelRef, signal, onWarning) {
|
|
@@ -12,12 +11,7 @@ export async function generateSessionTitle(input, modelRegistry, config, modelRe
|
|
|
12
11
|
onWarning?.(`Session-title model not found: ${modelRef}`);
|
|
13
12
|
return undefined;
|
|
14
13
|
}
|
|
15
|
-
const
|
|
16
|
-
if (auth.ok === false) {
|
|
17
|
-
onWarning?.(auth.error);
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
const response = await complete(model, {
|
|
14
|
+
const response = await modelRegistry.complete(model, {
|
|
21
15
|
systemPrompt: TITLE_SYSTEM_PROMPT,
|
|
22
16
|
messages: [
|
|
23
17
|
{
|
|
@@ -27,9 +21,6 @@ export async function generateSessionTitle(input, modelRegistry, config, modelRe
|
|
|
27
21
|
},
|
|
28
22
|
],
|
|
29
23
|
}, {
|
|
30
|
-
...(auth.apiKey === undefined ? {} : { apiKey: auth.apiKey }),
|
|
31
|
-
...(auth.headers === undefined ? {} : { headers: auth.headers }),
|
|
32
|
-
...(auth.env === undefined ? {} : { env: auth.env }),
|
|
33
24
|
cacheRetention: "none",
|
|
34
25
|
maxRetries: config.maxRetries,
|
|
35
26
|
maxTokens: config.maxTokens,
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"vscode-languageserver-protocol": "^3.17.5"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"@earendil-works/pi-ai": "0.
|
|
47
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
48
|
-
"@earendil-works/pi-tui": "0.
|
|
46
|
+
"@earendil-works/pi-ai": "0.84.1",
|
|
47
|
+
"@earendil-works/pi-coding-agent": "0.84.1",
|
|
48
|
+
"@earendil-works/pi-tui": "0.84.1",
|
|
49
49
|
"typebox": "*"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
@@ -221,7 +221,11 @@ export async function addAntigravityAccount(
|
|
|
221
221
|
};
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
async function refreshAccountToken(
|
|
224
|
+
async function refreshAccountToken(
|
|
225
|
+
account: OpencodeAntigravityAccount,
|
|
226
|
+
oauthClient?: GoogleOAuthClientCredentials,
|
|
227
|
+
signal?: AbortSignal,
|
|
228
|
+
): Promise<RefreshedAntigravityAccount> {
|
|
225
229
|
const refreshToken = getAccountRefreshToken(account);
|
|
226
230
|
if (!refreshToken) throw new Error(`Missing refresh token for Antigravity account ${account.email ?? "<unknown>"}`);
|
|
227
231
|
const clientCredentials = getGoogleOAuthClientCredentials(account, oauthClient);
|
|
@@ -230,6 +234,7 @@ async function refreshAccountToken(account: OpencodeAntigravityAccount, oauthCli
|
|
|
230
234
|
const start = Date.now();
|
|
231
235
|
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
232
236
|
method: "POST",
|
|
237
|
+
signal,
|
|
233
238
|
headers: {
|
|
234
239
|
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
235
240
|
Accept: "*/*",
|
|
@@ -256,7 +261,7 @@ async function refreshAccountToken(account: OpencodeAntigravityAccount, oauthCli
|
|
|
256
261
|
};
|
|
257
262
|
}
|
|
258
263
|
|
|
259
|
-
export async function refreshAntigravityToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {
|
|
264
|
+
export async function refreshAntigravityToken(credentials: OAuthCredentials, signal: AbortSignal): Promise<OAuthCredentials> {
|
|
260
265
|
const credentialDetails = credentials as OAuthCredentials & PiAuthCredential;
|
|
261
266
|
const oauthClient = getGoogleOAuthClientCredentials(credentialDetails);
|
|
262
267
|
const storedAccounts = getStoredAccounts(credentialDetails);
|
|
@@ -272,6 +277,7 @@ export async function refreshAntigravityToken(credentials: OAuthCredentials): Pr
|
|
|
272
277
|
email: credentialDetails.email,
|
|
273
278
|
},
|
|
274
279
|
oauthClient,
|
|
280
|
+
signal,
|
|
275
281
|
);
|
|
276
282
|
return {
|
|
277
283
|
...refreshed.credentials,
|
|
@@ -68,17 +68,21 @@ async function sendAntigravityRequest(
|
|
|
68
68
|
const headerStyle = getModelHeaderStyle(model);
|
|
69
69
|
const endpoints = headerStyle === "gemini-cli" ? [ENDPOINT_PROD] : STREAM_ENDPOINTS;
|
|
70
70
|
for (const endpoint of endpoints) {
|
|
71
|
+
const headers = new Headers({
|
|
72
|
+
Authorization: `Bearer ${apiKey}`,
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
Accept: "text/event-stream",
|
|
75
|
+
...getAntigravityHeaders(headerStyle),
|
|
76
|
+
...requestHeaders,
|
|
77
|
+
});
|
|
78
|
+
for (const [name, value] of Object.entries(options?.headers ?? {})) {
|
|
79
|
+
if (value === null) headers.delete(name);
|
|
80
|
+
else headers.set(name, value);
|
|
81
|
+
}
|
|
71
82
|
response = await fetch(`${endpoint}/v1internal:streamGenerateContent?alt=sse`, {
|
|
72
83
|
method: "POST",
|
|
73
84
|
signal: options?.signal,
|
|
74
|
-
headers
|
|
75
|
-
Authorization: `Bearer ${apiKey}`,
|
|
76
|
-
"Content-Type": "application/json",
|
|
77
|
-
Accept: "text/event-stream",
|
|
78
|
-
...getAntigravityHeaders(headerStyle),
|
|
79
|
-
...requestHeaders,
|
|
80
|
-
...(options?.headers ?? {}),
|
|
81
|
-
},
|
|
85
|
+
headers,
|
|
82
86
|
body: JSON.stringify(payload),
|
|
83
87
|
});
|
|
84
88
|
await options?.onResponse?.({ status: response.status, headers: Object.fromEntries(response.headers.entries()) }, model);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
1
|
+
import type { Api, Model, ProviderHeaders } from "@earendil-works/pi-ai";
|
|
2
2
|
import { completeWithModelRegistry, type ModelCompletionRegistry } from "../../model-completion.js";
|
|
3
3
|
import type { AgentTask } from "./types.js";
|
|
4
4
|
import {
|
|
@@ -14,7 +14,7 @@ export interface SubagentRoutingContext {
|
|
|
14
14
|
modelRegistry?: ModelCompletionRegistry & {
|
|
15
15
|
find(provider: string, modelId: string): Model<Api> | undefined;
|
|
16
16
|
getApiKeyAndHeaders(model: Model<Api>): Promise<
|
|
17
|
-
| { ok?: true; apiKey?: string; headers?:
|
|
17
|
+
| { ok?: true; apiKey?: string; headers?: ProviderHeaders; baseUrl?: string; env?: Record<string, string> }
|
|
18
18
|
| { ok: false; error: string }
|
|
19
19
|
>;
|
|
20
20
|
};
|
|
@@ -180,7 +180,7 @@ async function resolveRoutingModels(
|
|
|
180
180
|
interface RoutingCandidate {
|
|
181
181
|
model: Model<Api>;
|
|
182
182
|
apiKey?: string;
|
|
183
|
-
headers?:
|
|
183
|
+
headers?: ProviderHeaders;
|
|
184
184
|
env?: Record<string, string>;
|
|
185
185
|
}
|
|
186
186
|
|
|
@@ -189,7 +189,7 @@ type RoutingResponse = Awaited<ReturnType<typeof completeWithModelRegistry>>;
|
|
|
189
189
|
async function resolveModelRef(ctx: SubagentRoutingContext, modelRef: string): Promise<{
|
|
190
190
|
model: Model<Api>;
|
|
191
191
|
apiKey?: string;
|
|
192
|
-
headers?:
|
|
192
|
+
headers?: ProviderHeaders;
|
|
193
193
|
env?: Record<string, string>;
|
|
194
194
|
} | undefined> {
|
|
195
195
|
const parsed = parseModelRef(modelRef);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
1
|
+
import type { Api, Model, ProviderHeaders } from "@earendil-works/pi-ai";
|
|
2
2
|
import { completeWithModelRegistry, type ModelCompletionRegistry } from "../../model-completion.js";
|
|
3
3
|
import { currentModelRef, resolveSubagentRoutingConfig, type SubagentConfig } from "./config.js";
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ export interface UltraworkAutoContext {
|
|
|
9
9
|
modelRegistry?: ModelCompletionRegistry & {
|
|
10
10
|
find(provider: string, modelId: string): Model<Api> | undefined;
|
|
11
11
|
getApiKeyAndHeaders(model: Model<Api>): Promise<
|
|
12
|
-
| { ok?: true; apiKey?: string; headers?:
|
|
12
|
+
| { ok?: true; apiKey?: string; headers?: ProviderHeaders; baseUrl?: string; env?: Record<string, string> }
|
|
13
13
|
| { ok: false; error: string }
|
|
14
14
|
>;
|
|
15
15
|
};
|
|
@@ -131,7 +131,7 @@ function buildClassifierPrompt(userText: string): string {
|
|
|
131
131
|
async function resolveClassifierModel(ctx: UltraworkAutoContext, modelRef: string): Promise<{
|
|
132
132
|
model: Model<Api>;
|
|
133
133
|
apiKey?: string;
|
|
134
|
-
headers?:
|
|
134
|
+
headers?: ProviderHeaders;
|
|
135
135
|
env?: Record<string, string>;
|
|
136
136
|
} | undefined> {
|
|
137
137
|
const configured = await resolveModelRef(ctx, modelRef);
|
|
@@ -143,7 +143,7 @@ async function resolveClassifierModel(ctx: UltraworkAutoContext, modelRef: strin
|
|
|
143
143
|
async function resolveModelRef(ctx: UltraworkAutoContext, modelRef: string): Promise<{
|
|
144
144
|
model: Model<Api>;
|
|
145
145
|
apiKey?: string;
|
|
146
|
-
headers?:
|
|
146
|
+
headers?: ProviderHeaders;
|
|
147
147
|
env?: Record<string, string>;
|
|
148
148
|
} | undefined> {
|
|
149
149
|
const parsed = parseModelRef(modelRef);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { Api, AssistantMessage, ImageContent, Model, TextContent } from "@earendil-works/pi-ai";
|
|
3
|
+
import type { Api, AssistantMessage, ImageContent, Model, ProviderHeaders, TextContent } from "@earendil-works/pi-ai";
|
|
4
4
|
import { Type } from "typebox";
|
|
5
5
|
|
|
6
6
|
import { loadPiToolsSuiteConfig, DEFAULT_CODING_DISCIPLINE_STRICTNESS, type CodingDisciplineStrictness } from "../config.js";
|
|
@@ -28,7 +28,7 @@ type ResolvedLookupModel = {
|
|
|
28
28
|
modelRegistry: ModelCompletionRegistry;
|
|
29
29
|
model: Model<Api>;
|
|
30
30
|
apiKey?: string;
|
|
31
|
-
headers?:
|
|
31
|
+
headers?: ProviderHeaders;
|
|
32
32
|
env?: Record<string, string>;
|
|
33
33
|
};
|
|
34
34
|
|
|
@@ -825,7 +825,8 @@ async function resolveLookupModel(ctx: unknown, modelRef: string): Promise<Resol
|
|
|
825
825
|
const auth = await registry.getApiKeyAndHeaders(model) as {
|
|
826
826
|
ok?: true;
|
|
827
827
|
apiKey?: string;
|
|
828
|
-
headers?:
|
|
828
|
+
headers?: ProviderHeaders;
|
|
829
|
+
baseUrl?: string;
|
|
829
830
|
env?: Record<string, string>;
|
|
830
831
|
} | { ok: false; error: string };
|
|
831
832
|
if (auth.ok === false) return undefined;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// automatic fallback to the programmatic digest on any failure/timeout.
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
|
|
16
|
-
import type { Model, Api } from "@earendil-works/pi-ai"
|
|
16
|
+
import type { Model, Api, ProviderHeaders } from "@earendil-works/pi-ai"
|
|
17
17
|
import { completeWithModelRegistry, type ModelCompletionRegistry } from "../model-completion.js"
|
|
18
18
|
import type { DcpState } from "./state.js"
|
|
19
19
|
import type { DcpConfig } from "./config.js"
|
|
@@ -137,7 +137,7 @@ export interface ModelSummaryResult {
|
|
|
137
137
|
type ModelSummaryRegistry = ModelCompletionRegistry & {
|
|
138
138
|
find(provider: string, modelId: string): Model<Api> | undefined
|
|
139
139
|
getApiKeyAndHeaders(model: Model<Api>): Promise<
|
|
140
|
-
| { ok: true; apiKey?: string; headers?:
|
|
140
|
+
| { ok: true; apiKey?: string; headers?: ProviderHeaders; baseUrl?: string; env?: Record<string, string> }
|
|
141
141
|
| { ok: false; error: string }
|
|
142
142
|
>
|
|
143
143
|
}
|
|
@@ -809,6 +809,7 @@ export default async function dcpModule(pi: ExtensionAPI): Promise<void> {
|
|
|
809
809
|
await saveDcpState(ctx, state)
|
|
810
810
|
}
|
|
811
811
|
|
|
812
|
+
const anchorsBeforeFinalization = state.nudgeAnchors.length
|
|
812
813
|
if (state.manualMode) {
|
|
813
814
|
state.nudgeAnchors = state.nudgeAnchors.filter((anchor) =>
|
|
814
815
|
anchor.type === "context-strong" || anchor.type === "context-soft",
|
|
@@ -817,6 +818,9 @@ export default async function dcpModule(pi: ExtensionAPI): Promise<void> {
|
|
|
817
818
|
applyAnchoredNudges(prunedMessages, state, (anchor) =>
|
|
818
819
|
appendConcreteNudgeGuidance(baseNudgeText(anchor.type), candidate, messageCandidates, state),
|
|
819
820
|
)
|
|
821
|
+
if (state.nudgeAnchors.length !== anchorsBeforeFinalization) {
|
|
822
|
+
await saveDcpState(ctx, state)
|
|
823
|
+
}
|
|
820
824
|
|
|
821
825
|
return finishContext("complete", prunedMessages, {
|
|
822
826
|
candidate,
|
|
@@ -51,7 +51,6 @@ function isRealAnchorCandidate(msg: any): boolean {
|
|
|
51
51
|
const role = msg?.role ?? "";
|
|
52
52
|
if (role !== "user" && role !== "assistant") return false;
|
|
53
53
|
const text = messageText(msg);
|
|
54
|
-
if (text.includes("<dcp-system-reminder>")) return false;
|
|
55
54
|
if (extractBlockId(text) !== undefined) return false;
|
|
56
55
|
return true;
|
|
57
56
|
}
|
|
@@ -94,6 +93,12 @@ function anchorMatchesMessage(anchor: DcpNudgeAnchor, msg: any, index: number):
|
|
|
94
93
|
return msg?.timestamp === anchor.anchorTimestamp;
|
|
95
94
|
}
|
|
96
95
|
|
|
96
|
+
function isNewerAnchor(candidate: DcpNudgeAnchor, current: DcpNudgeAnchor): boolean {
|
|
97
|
+
if (candidate.updatedAt !== current.updatedAt) return candidate.updatedAt > current.updatedAt;
|
|
98
|
+
if (candidate.createdAt !== current.createdAt) return candidate.createdAt > current.createdAt;
|
|
99
|
+
return candidate.id > current.id;
|
|
100
|
+
}
|
|
101
|
+
|
|
97
102
|
function appendTextToMessage(msg: any, text: string): void {
|
|
98
103
|
const suffix = `\n\n${text}`;
|
|
99
104
|
if (typeof msg.content === "string") {
|
|
@@ -205,15 +210,27 @@ export function upsertNudgeAnchor(
|
|
|
205
210
|
options: { contextPercent?: number } = {},
|
|
206
211
|
): { anchor: DcpNudgeAnchor | null; created: boolean; updated: boolean } {
|
|
207
212
|
const target = findAnchorMessage(messages);
|
|
208
|
-
if (!target)
|
|
213
|
+
if (!target) {
|
|
214
|
+
// The caller will append one synthetic tail reminder. Drop persisted
|
|
215
|
+
// anchors first so applyAnchoredNudges cannot render a second reminder.
|
|
216
|
+
state.nudgeAnchors = [];
|
|
217
|
+
state.lastNudge = undefined;
|
|
218
|
+
return { anchor: null, created: false, updated: false };
|
|
219
|
+
}
|
|
209
220
|
|
|
210
221
|
const key = `${target.stableId}|${target.timestamp}`;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
222
|
+
let existing: DcpNudgeAnchor | null = null;
|
|
223
|
+
for (const anchor of state.nudgeAnchors) {
|
|
224
|
+
const anchorKey = `${anchor.anchorStableId ?? ""}|${anchor.anchorTimestamp}`;
|
|
225
|
+
if (anchorKey !== key) continue;
|
|
226
|
+
if (!existing || isNewerAnchor(anchor, existing)) existing = anchor;
|
|
227
|
+
}
|
|
214
228
|
|
|
215
229
|
const now = Date.now();
|
|
216
230
|
if (existing) {
|
|
231
|
+
// Older sidecars may contain several anchors. Keep only the anchor for the
|
|
232
|
+
// current target so every subsequent context pass has singleton state.
|
|
233
|
+
state.nudgeAnchors = [existing];
|
|
217
234
|
const shouldUpgrade = typePriority(type) > typePriority(existing.type);
|
|
218
235
|
if (shouldUpgrade) existing.type = type;
|
|
219
236
|
existing.updatedAt = now;
|
|
@@ -240,7 +257,9 @@ export function upsertNudgeAnchor(
|
|
|
240
257
|
createdAt: now,
|
|
241
258
|
updatedAt: now,
|
|
242
259
|
};
|
|
243
|
-
|
|
260
|
+
// A nudge follows the latest useful message. Replacing the previous anchor
|
|
261
|
+
// prevents one full reminder from accumulating per turn/assistant response.
|
|
262
|
+
state.nudgeAnchors = [anchor];
|
|
244
263
|
state.lastNudge = {
|
|
245
264
|
type,
|
|
246
265
|
anchorId: anchor.id,
|
|
@@ -259,15 +278,19 @@ export function applyAnchoredNudges(
|
|
|
259
278
|
): void {
|
|
260
279
|
if (state.nudgeAnchors.length === 0) return;
|
|
261
280
|
|
|
262
|
-
|
|
281
|
+
let selected: { anchor: DcpNudgeAnchor; index: number } | null = null;
|
|
263
282
|
for (const anchor of state.nudgeAnchors) {
|
|
264
283
|
const index = messages.findIndex((msg, messageIndex) => anchorMatchesMessage(anchor, msg, messageIndex));
|
|
265
284
|
if (index === -1) continue;
|
|
266
|
-
|
|
267
|
-
|
|
285
|
+
if (!selected || isNewerAnchor(anchor, selected.anchor)) {
|
|
286
|
+
selected = { anchor, index };
|
|
287
|
+
}
|
|
268
288
|
}
|
|
269
289
|
|
|
270
|
-
state
|
|
290
|
+
// Defensive migration for persisted pre-singleton state: render only the
|
|
291
|
+
// newest valid anchor and discard every stale predecessor.
|
|
292
|
+
state.nudgeAnchors = selected ? [selected.anchor] : [];
|
|
293
|
+
if (selected) appendTextToMessage(messages[selected.index], render(selected.anchor));
|
|
271
294
|
}
|
|
272
295
|
|
|
273
296
|
export function clearDcpNudgeAnchors(state: DcpState): number {
|
|
@@ -1,37 +1,31 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Api,
|
|
3
3
|
AssistantMessage,
|
|
4
|
-
AssistantMessageEventStream,
|
|
5
4
|
Context,
|
|
6
5
|
Model,
|
|
6
|
+
ModelsApiStreamOptions,
|
|
7
7
|
SimpleStreamOptions,
|
|
8
8
|
} from "@earendil-works/pi-ai";
|
|
9
9
|
import { completeSimple } from "@earendil-works/pi-ai/compat";
|
|
10
|
+
import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
10
11
|
|
|
11
|
-
type
|
|
12
|
-
streamSimple?: (
|
|
13
|
-
model: Model<Api>,
|
|
14
|
-
context: Context,
|
|
15
|
-
options?: SimpleStreamOptions,
|
|
16
|
-
) => AssistantMessageEventStream;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type ModelCompletionRegistry = {
|
|
20
|
-
getRegisteredProviderConfig?(providerId: string): RegisteredProviderConfig | undefined;
|
|
21
|
-
};
|
|
12
|
+
export type ModelCompletionRegistry = Partial<Pick<ModelRegistry, "complete" | "getRegisteredProviderConfig">>;
|
|
22
13
|
|
|
23
14
|
/**
|
|
24
|
-
* Complete through
|
|
25
|
-
*
|
|
26
|
-
*
|
|
15
|
+
* Complete through Pi's model runtime when available so custom providers and
|
|
16
|
+
* resolved auth endpoints are preserved. The older stream/compat branches are
|
|
17
|
+
* retained for narrow test doubles that do not expose ModelRegistry.complete().
|
|
27
18
|
*/
|
|
28
19
|
export async function completeWithModelRegistry(
|
|
29
20
|
modelRegistry: ModelCompletionRegistry | undefined,
|
|
30
21
|
model: Model<Api>,
|
|
31
22
|
context: Context,
|
|
32
|
-
options?:
|
|
23
|
+
options?: ModelsApiStreamOptions<Api>,
|
|
33
24
|
): Promise<AssistantMessage> {
|
|
25
|
+
if (modelRegistry?.complete) return modelRegistry.complete(model, context, options);
|
|
26
|
+
|
|
34
27
|
const providerConfig = modelRegistry?.getRegisteredProviderConfig?.(model.provider);
|
|
35
|
-
|
|
36
|
-
return
|
|
28
|
+
const simpleOptions = options as SimpleStreamOptions | undefined;
|
|
29
|
+
if (providerConfig?.streamSimple) return providerConfig.streamSimple(model, context, simpleOptions).result();
|
|
30
|
+
return completeSimple(model, context, simpleOptions);
|
|
37
31
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ui-extend",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Pix: a workspace-first terminal UI for Pi with tabs, readable tool activity, voice input, and bundled agent tools.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
"prepublishOnly": "npm run check && npm run build:pix && npm run generate-schemas"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@earendil-works/pi-ai": "0.
|
|
79
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
80
|
-
"@earendil-works/pi-tui": "0.
|
|
78
|
+
"@earendil-works/pi-ai": "0.84.1",
|
|
79
|
+
"@earendil-works/pi-coding-agent": "0.84.1",
|
|
80
|
+
"@earendil-works/pi-tui": "0.84.1",
|
|
81
81
|
"@mariozechner/clipboard": "^0.3.9",
|
|
82
82
|
"jsonc-parser": "3.3.1",
|
|
83
83
|
"typebox": "1.1.38",
|