fix(coding-agent): resolve models.json auth per request closes #1835
This commit is contained in:
@@ -317,6 +317,32 @@ export class AgentSession {
|
||||
return this._modelRegistry;
|
||||
}
|
||||
|
||||
private async _getRequiredRequestAuth(model: Model<any>): Promise<{
|
||||
apiKey: string;
|
||||
headers?: Record<string, string>;
|
||||
}> {
|
||||
const result = await this._modelRegistry.getApiKeyAndHeaders(model);
|
||||
if (!result.ok) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
if (result.apiKey) {
|
||||
return { apiKey: result.apiKey, headers: result.headers };
|
||||
}
|
||||
|
||||
const isOAuth = this._modelRegistry.isUsingOAuth(model);
|
||||
if (isOAuth) {
|
||||
throw new Error(
|
||||
`Authentication failed for "${model.provider}". ` +
|
||||
`Credentials may have expired or network is unavailable. ` +
|
||||
`Run '/login ${model.provider}' to re-authenticate.`,
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
`No API key found for ${model.provider}.\n\n` +
|
||||
`Use /login or set an API key environment variable. See ${join(getDocsPath(), "providers.md")}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install tool hooks once on the Agent instance.
|
||||
*
|
||||
@@ -946,9 +972,7 @@ export class AgentSession {
|
||||
);
|
||||
}
|
||||
|
||||
// Validate API key
|
||||
const apiKey = await this._modelRegistry.getApiKey(this.model);
|
||||
if (!apiKey) {
|
||||
if (!this._modelRegistry.hasConfiguredAuth(this.model)) {
|
||||
const isOAuth = this._modelRegistry.isUsingOAuth(this.model);
|
||||
if (isOAuth) {
|
||||
throw new Error(
|
||||
@@ -1384,12 +1408,11 @@ export class AgentSession {
|
||||
|
||||
/**
|
||||
* Set model directly.
|
||||
* Validates API key, saves to session and settings.
|
||||
* @throws Error if no API key available for the model
|
||||
* Validates that auth is configured, saves to session and settings.
|
||||
* @throws Error if no auth is configured for the model
|
||||
*/
|
||||
async setModel(model: Model<any>): Promise<void> {
|
||||
const apiKey = await this._modelRegistry.getApiKey(model);
|
||||
if (!apiKey) {
|
||||
if (!this._modelRegistry.hasConfiguredAuth(model)) {
|
||||
throw new Error(`No API key for ${model.provider}/${model.id}`);
|
||||
}
|
||||
|
||||
@@ -1418,30 +1441,12 @@ export class AgentSession {
|
||||
return this._cycleAvailableModel(direction);
|
||||
}
|
||||
|
||||
private async _getScopedModelsWithApiKey(): Promise<Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }>> {
|
||||
const apiKeysByProvider = new Map<string, string | undefined>();
|
||||
const result: Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }> = [];
|
||||
|
||||
for (const scoped of this._scopedModels) {
|
||||
const provider = scoped.model.provider;
|
||||
let apiKey: string | undefined;
|
||||
if (apiKeysByProvider.has(provider)) {
|
||||
apiKey = apiKeysByProvider.get(provider);
|
||||
} else {
|
||||
apiKey = await this._modelRegistry.getApiKeyForProvider(provider);
|
||||
apiKeysByProvider.set(provider, apiKey);
|
||||
}
|
||||
|
||||
if (apiKey) {
|
||||
result.push(scoped);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
private _getScopedModelsWithAuth(): Array<{ model: Model<any>; thinkingLevel?: ThinkingLevel }> {
|
||||
return this._scopedModels.filter((scoped) => this._modelRegistry.hasConfiguredAuth(scoped.model));
|
||||
}
|
||||
|
||||
private async _cycleScopedModel(direction: "forward" | "backward"): Promise<ModelCycleResult | undefined> {
|
||||
const scopedModels = await this._getScopedModelsWithApiKey();
|
||||
const scopedModels = this._getScopedModelsWithAuth();
|
||||
if (scopedModels.length <= 1) return undefined;
|
||||
|
||||
const currentModel = this.model;
|
||||
@@ -1481,11 +1486,6 @@ export class AgentSession {
|
||||
const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
|
||||
const nextModel = availableModels[nextIndex];
|
||||
|
||||
const apiKey = await this._modelRegistry.getApiKey(nextModel);
|
||||
if (!apiKey) {
|
||||
throw new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);
|
||||
}
|
||||
|
||||
const thinkingLevel = this._getThinkingLevelForModelSwitch();
|
||||
this.agent.setModel(nextModel);
|
||||
this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
|
||||
@@ -1633,10 +1633,7 @@ export class AgentSession {
|
||||
throw new Error("No model selected");
|
||||
}
|
||||
|
||||
const apiKey = await this._modelRegistry.getApiKey(this.model);
|
||||
if (!apiKey) {
|
||||
throw new Error(`No API key for ${this.model.provider}`);
|
||||
}
|
||||
const { apiKey, headers } = await this._getRequiredRequestAuth(this.model);
|
||||
|
||||
const pathEntries = this.sessionManager.getBranch();
|
||||
const settings = this.settingsManager.getCompactionSettings();
|
||||
@@ -1690,6 +1687,7 @@ export class AgentSession {
|
||||
preparation,
|
||||
this.model,
|
||||
apiKey,
|
||||
headers,
|
||||
customInstructions,
|
||||
this._compactionAbortController.signal,
|
||||
);
|
||||
@@ -1853,11 +1851,12 @@ export class AgentSession {
|
||||
return;
|
||||
}
|
||||
|
||||
const apiKey = await this._modelRegistry.getApiKey(this.model);
|
||||
if (!apiKey) {
|
||||
const authResult = await this._modelRegistry.getApiKeyAndHeaders(this.model);
|
||||
if (!authResult.ok || !authResult.apiKey) {
|
||||
this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
|
||||
return;
|
||||
}
|
||||
const { apiKey, headers } = authResult;
|
||||
|
||||
const pathEntries = this.sessionManager.getBranch();
|
||||
|
||||
@@ -1907,6 +1906,7 @@ export class AgentSession {
|
||||
preparation,
|
||||
this.model,
|
||||
apiKey,
|
||||
headers,
|
||||
undefined,
|
||||
this._autoCompactionAbortController.signal,
|
||||
);
|
||||
@@ -2155,8 +2155,7 @@ export class AgentSession {
|
||||
refreshTools: () => this._refreshToolRegistry(),
|
||||
getCommands,
|
||||
setModel: async (model) => {
|
||||
const key = await this.modelRegistry.getApiKey(model);
|
||||
if (!key) return false;
|
||||
if (!this.modelRegistry.hasConfiguredAuth(model)) return false;
|
||||
await this.setModel(model);
|
||||
return true;
|
||||
},
|
||||
@@ -2856,14 +2855,12 @@ export class AgentSession {
|
||||
let summaryDetails: unknown;
|
||||
if (options.summarize && entriesToSummarize.length > 0 && !extensionSummary) {
|
||||
const model = this.model!;
|
||||
const apiKey = await this._modelRegistry.getApiKey(model);
|
||||
if (!apiKey) {
|
||||
throw new Error(`No API key for ${model.provider}`);
|
||||
}
|
||||
const { apiKey, headers } = await this._getRequiredRequestAuth(model);
|
||||
const branchSummarySettings = this.settingsManager.getBranchSummarySettings();
|
||||
const result = await generateBranchSummary(entriesToSummarize, {
|
||||
model,
|
||||
apiKey,
|
||||
headers,
|
||||
signal: this._branchSummaryAbortController.signal,
|
||||
customInstructions,
|
||||
replaceInstructions,
|
||||
|
||||
Reference in New Issue
Block a user