fix(coding-agent): resolve models.json auth per request closes #1835

This commit is contained in:
Mario Zechner
2026-03-27 00:19:00 +01:00
parent fb10d9aef9
commit 7a786d88aa
18 changed files with 396 additions and 228 deletions

View File

@@ -31,9 +31,13 @@ export default function (pi: ExtensionAPI) {
return;
}
// Resolve API key for the summarization model
const apiKey = await ctx.modelRegistry.getApiKey(model);
if (!apiKey) {
// 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;
}
@@ -83,7 +87,16 @@ ${conversationText}
try {
// Pass signal to honor abort requests (e.g., user cancels compaction)
const response = await complete(model, { messages: summaryMessages }, { apiKey, maxTokens: 8192, signal });
const response = await complete(
model,
{ messages: summaryMessages },
{
apiKey: auth.apiKey,
headers: auth.headers,
maxTokens: 8192,
signal,
},
);
const summary = response.content
.filter((c): c is { type: "text"; text: string } => c.type === "text")

View File

@@ -80,7 +80,10 @@ export default function (pi: ExtensionAPI) {
loader.onAbort = () => done(null);
const doGenerate = async () => {
const apiKey = await ctx.modelRegistry.getApiKey(ctx.model!);
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",
@@ -96,7 +99,7 @@ export default function (pi: ExtensionAPI) {
const response = await complete(
ctx.model!,
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
{ apiKey, signal: loader.signal },
{ apiKey: auth.apiKey, headers: auth.headers, signal: loader.signal },
);
if (response.stopReason === "aborted") {

View File

@@ -77,7 +77,10 @@ export default function (pi: ExtensionAPI) {
// Do the work
const doExtract = async () => {
const apiKey = await ctx.modelRegistry.getApiKey(ctx.model!);
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! }],
@@ -87,7 +90,7 @@ export default function (pi: ExtensionAPI) {
const response = await complete(
ctx.model!,
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
{ apiKey, signal: loader.signal },
{ apiKey: auth.apiKey, headers: auth.headers, signal: loader.signal },
);
if (response.stopReason === "aborted") {

View File

@@ -165,12 +165,15 @@ export default function (pi: ExtensionAPI) {
ctx.ui.notify("Model openai/gpt-5.2 not found", "warning");
}
const apiKey = model ? await ctx.modelRegistry.getApiKey(model) : undefined;
if (!apiKey && ctx.hasUI) {
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 || !apiKey) {
if (!model || !auth?.ok || !auth.apiKey) {
return;
}
@@ -182,7 +185,15 @@ export default function (pi: ExtensionAPI) {
},
];
const response = await complete(model, { messages: summaryMessages }, { apiKey, reasoningEffort: "high" });
const response = await complete(
model,
{ messages: summaryMessages },
{
apiKey: auth.apiKey,
headers: auth.headers,
reasoningEffort: "high",
},
);
const summary = response.content
.filter((c): c is { type: "text"; text: string } => c.type === "text")