mirror of
https://github.com/earendil-works/pi.git
synced 2026-10-02 00:35:27 +08:00
@@ -109,6 +109,7 @@
|
||||
- Fixed concurrent in-memory credential mutations losing unrelated provider updates by serializing their read-modify-write sections.
|
||||
- Updated `undici` to 8.9.0 and the packaged `brace-expansion` to 5.0.9 to address GHSA-8xcm-r25x-g524, GHSA-4cwx-7wf7-3272, GHSA-m8rv-5g2x-5cg5, GHSA-jr45-8vmc-qm54, GHSA-v3r7-h72x-cjcm, and GHSA-rgw5-rvv9-x895.
|
||||
- Fixed GitHub Copilot compaction and branch summaries using the Individual endpoint instead of the credential-resolved Business or Enterprise endpoint ([#6768](https://github.com/earendil-works/pi/issues/6768)).
|
||||
- Fixed extension model calls dropping credential-resolved endpoints when forwarding request authentication, including custom compaction with GitHub Copilot Business and Enterprise accounts ([#7579](https://github.com/earendil-works/pi/issues/7579)).
|
||||
|
||||
## [0.83.0] - 2026-07-29
|
||||
|
||||
|
||||
@@ -31,17 +31,6 @@ export default function (pi: ExtensionAPI) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve request auth for the summarization model
|
||||
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
||||
if (!auth.ok) {
|
||||
ctx.ui.notify(`Compaction auth failed: ${auth.error}`, "warning");
|
||||
return;
|
||||
}
|
||||
if (!auth.apiKey) {
|
||||
ctx.ui.notify(`No API key for ${model.provider}, using default compaction`, "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
// Combine all messages for full summary
|
||||
const allMessages = [...messagesToSummarize, ...turnPrefixMessages];
|
||||
|
||||
@@ -91,9 +80,6 @@ ${conversationText}
|
||||
model,
|
||||
{ messages: summaryMessages },
|
||||
{
|
||||
apiKey: auth.apiKey,
|
||||
headers: auth.headers,
|
||||
env: auth.env,
|
||||
maxTokens: 8192,
|
||||
signal,
|
||||
cacheRetention: "none",
|
||||
|
||||
@@ -117,11 +117,6 @@ export default function (pi: ExtensionAPI) {
|
||||
loader.onAbort = () => done(null);
|
||||
|
||||
const doGenerate = async () => {
|
||||
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(ctx.model!);
|
||||
if (!auth.ok || !auth.apiKey) {
|
||||
throw new Error(auth.ok ? `No API key for ${ctx.model!.provider}` : auth.error);
|
||||
}
|
||||
|
||||
const userMessage: Message = {
|
||||
role: "user",
|
||||
content: [
|
||||
@@ -137,9 +132,6 @@ export default function (pi: ExtensionAPI) {
|
||||
ctx.model!,
|
||||
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
|
||||
{
|
||||
apiKey: auth.apiKey,
|
||||
headers: auth.headers,
|
||||
env: auth.env,
|
||||
signal: loader.signal,
|
||||
cacheRetention: "none",
|
||||
sessionId: uuidv7(),
|
||||
|
||||
@@ -77,10 +77,6 @@ export default function (pi: ExtensionAPI) {
|
||||
|
||||
// Do the work
|
||||
const doExtract = async () => {
|
||||
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(ctx.model!);
|
||||
if (!auth.ok || !auth.apiKey) {
|
||||
throw new Error(auth.ok ? `No API key for ${ctx.model!.provider}` : auth.error);
|
||||
}
|
||||
const userMessage: UserMessage = {
|
||||
role: "user",
|
||||
content: [{ type: "text", text: lastAssistantText! }],
|
||||
@@ -90,7 +86,7 @@ export default function (pi: ExtensionAPI) {
|
||||
const response = await ctx.modelRegistry.complete(
|
||||
ctx.model!,
|
||||
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
|
||||
{ apiKey: auth.apiKey, headers: auth.headers, env: auth.env, signal: loader.signal },
|
||||
{ signal: loader.signal },
|
||||
);
|
||||
|
||||
if (response.stopReason === "aborted") {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { uuidv7 } from "@earendil-works/pi-ai";
|
||||
import { complete, getModel } from "@earendil-works/pi-ai/compat";
|
||||
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
||||
import { DynamicBorder, getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
||||
import { Container, Markdown, matchesKey, Text } from "@earendil-works/pi-tui";
|
||||
@@ -161,20 +160,13 @@ export default function (pi: ExtensionAPI) {
|
||||
ctx.ui.notify("Preparing summary...", "info");
|
||||
}
|
||||
|
||||
const model = getModel("openai", "gpt-5.2");
|
||||
if (!model && ctx.hasUI) {
|
||||
ctx.ui.notify("Model openai/gpt-5.2 not found", "warning");
|
||||
const model = ctx.modelRegistry.find("openai", "gpt-5.2");
|
||||
if (!model) {
|
||||
if (ctx.hasUI) ctx.ui.notify("Model openai/gpt-5.2 not found", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
const auth = model ? await ctx.modelRegistry.getApiKeyAndHeaders(model) : undefined;
|
||||
if (auth && !auth.ok && ctx.hasUI) {
|
||||
ctx.ui.notify(auth.error, "warning");
|
||||
}
|
||||
if (auth?.ok && !auth.apiKey && ctx.hasUI) {
|
||||
ctx.ui.notify("No API key for openai/gpt-5.2", "warning");
|
||||
}
|
||||
|
||||
if (!model || !auth?.ok || !auth.apiKey) {
|
||||
if (!ctx.modelRegistry.hasConfiguredAuth(model)) {
|
||||
if (ctx.hasUI) ctx.ui.notify("No authentication configured for openai/gpt-5.2", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -186,13 +178,10 @@ export default function (pi: ExtensionAPI) {
|
||||
},
|
||||
];
|
||||
|
||||
const response = await complete(
|
||||
const response = await ctx.modelRegistry.complete(
|
||||
model,
|
||||
{ messages: summaryMessages },
|
||||
{
|
||||
apiKey: auth.apiKey,
|
||||
headers: auth.headers,
|
||||
env: auth.env,
|
||||
reasoningEffort: "high",
|
||||
cacheRetention: "none",
|
||||
sessionId: uuidv7(),
|
||||
|
||||
@@ -19,6 +19,7 @@ export type ResolvedRequestAuth =
|
||||
ok: true;
|
||||
apiKey?: string;
|
||||
headers?: ProviderHeaders;
|
||||
baseUrl?: string;
|
||||
env?: Record<string, string>;
|
||||
}
|
||||
| { ok: false; error: string };
|
||||
@@ -74,6 +75,7 @@ export class ModelRegistry {
|
||||
ok: true,
|
||||
apiKey: resolution.auth.apiKey,
|
||||
headers: resolution.auth.headers,
|
||||
...(resolution.auth.baseUrl ? { baseUrl: resolution.auth.baseUrl } : {}),
|
||||
env: resolution.env,
|
||||
};
|
||||
} catch (error) {
|
||||
|
||||
@@ -109,7 +109,6 @@ describe("Documentation example", () => {
|
||||
ui: { notify: vi.fn() },
|
||||
modelRegistry: {
|
||||
find: vi.fn(() => model),
|
||||
getApiKeyAndHeaders: vi.fn(async () => ({ ok: true, apiKey: "fake-key" })),
|
||||
complete,
|
||||
},
|
||||
},
|
||||
@@ -118,7 +117,12 @@ describe("Documentation example", () => {
|
||||
expect(complete).toHaveBeenCalledWith(
|
||||
model,
|
||||
expect.objectContaining({ messages: expect.any(Array) }),
|
||||
expect.objectContaining({ apiKey: "fake-key", maxTokens: 8192 }),
|
||||
expect.objectContaining({ maxTokens: 8192 }),
|
||||
);
|
||||
expect(complete).not.toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
expect.objectContaining({ apiKey: expect.anything() }),
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
compaction: {
|
||||
|
||||
Reference in New Issue
Block a user