fix(runtime): honor stored Anthropic API key state
This commit is contained in:
parent
e01e099c6c
commit
70dd17c784
3 changed files with 64 additions and 1 deletions
|
|
@ -1016,6 +1016,7 @@ async function initializeServices(): Promise<void> {
|
||||||
);
|
);
|
||||||
const mcpInstallService = new McpInstallService(mcpAggregator, extensionsRuntimeAdapter);
|
const mcpInstallService = new McpInstallService(mcpAggregator, extensionsRuntimeAdapter);
|
||||||
const apiKeyService = new ApiKeyService();
|
const apiKeyService = new ApiKeyService();
|
||||||
|
providerConnectionService.setApiKeyService(apiKeyService);
|
||||||
await apiKeyService.syncProcessEnv(RUNTIME_MANAGED_API_KEY_ENV_VARS);
|
await apiKeyService.syncProcessEnv(RUNTIME_MANAGED_API_KEY_ENV_VARS);
|
||||||
// warmup() and ensureInstalled() are deferred to after window creation
|
// warmup() and ensureInstalled() are deferred to after window creation
|
||||||
// (did-finish-load handler) to avoid thread pool contention at startup.
|
// (did-finish-load handler) to avoid thread pool contention at startup.
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ export class ProviderConnectionService {
|
||||||
null;
|
null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly apiKeyService = new ApiKeyService(),
|
private apiKeyService = new ApiKeyService(),
|
||||||
private readonly configManager = ConfigManager.getInstance()
|
private readonly configManager = ConfigManager.getInstance()
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
@ -107,6 +107,10 @@ export class ProviderConnectionService {
|
||||||
this.codexModelCatalogFeature = feature;
|
this.codexModelCatalogFeature = feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setApiKeyService(apiKeyService: ApiKeyService): void {
|
||||||
|
this.apiKeyService = apiKeyService;
|
||||||
|
}
|
||||||
|
|
||||||
getConfiguredAuthMode(providerId: CliProviderId): CliProviderAuthMode | null {
|
getConfiguredAuthMode(providerId: CliProviderId): CliProviderAuthMode | null {
|
||||||
if (providerId === 'anthropic') {
|
if (providerId === 'anthropic') {
|
||||||
return this.configManager.getConfig().providerConnections.anthropic.authMode;
|
return this.configManager.getConfig().providerConnections.anthropic.authMode;
|
||||||
|
|
@ -263,6 +267,11 @@ export class ProviderConnectionService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const storedKey = await this.apiKeyService.lookupPreferred('ANTHROPIC_API_KEY');
|
||||||
|
if (storedKey?.value.trim()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
'Anthropic API key mode is enabled, but no ANTHROPIC_API_KEY is configured. ' +
|
'Anthropic API key mode is enabled, but no ANTHROPIC_API_KEY is configured. ' +
|
||||||
'Add a stored/environment API key or switch Anthropic auth mode back to Auto or OAuth.'
|
'Add a stored/environment API key or switch Anthropic auth mode back to Auto or OAuth.'
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,59 @@ describe('ProviderConnectionService', () => {
|
||||||
expect(issue).toContain('ANTHROPIC_API_KEY');
|
expect(issue).toContain('ANTHROPIC_API_KEY');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('treats a stored Anthropic API key as configured even when env is empty', async () => {
|
||||||
|
const lookupPreferred = vi.fn().mockResolvedValue({
|
||||||
|
envVarName: 'ANTHROPIC_API_KEY',
|
||||||
|
value: 'stored-key',
|
||||||
|
});
|
||||||
|
const { ProviderConnectionService } =
|
||||||
|
await import('@main/services/runtime/ProviderConnectionService');
|
||||||
|
|
||||||
|
const service = new ProviderConnectionService(
|
||||||
|
{
|
||||||
|
lookupPreferred,
|
||||||
|
} as never,
|
||||||
|
{
|
||||||
|
getConfig: () => createConfig('api_key'),
|
||||||
|
} as never
|
||||||
|
);
|
||||||
|
|
||||||
|
const issue = await service.getConfiguredConnectionIssue({}, 'anthropic');
|
||||||
|
|
||||||
|
expect(lookupPreferred).toHaveBeenCalledWith('ANTHROPIC_API_KEY');
|
||||||
|
expect(issue).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can swap to the shared API key service after construction', async () => {
|
||||||
|
const staleApiKeyService = {
|
||||||
|
lookupPreferred: vi.fn().mockResolvedValue(null),
|
||||||
|
};
|
||||||
|
const sharedApiKeyService = {
|
||||||
|
lookupPreferred: vi.fn().mockResolvedValue({
|
||||||
|
envVarName: 'ANTHROPIC_API_KEY',
|
||||||
|
value: 'shared-key',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const { ProviderConnectionService } =
|
||||||
|
await import('@main/services/runtime/ProviderConnectionService');
|
||||||
|
|
||||||
|
const service = new ProviderConnectionService(
|
||||||
|
staleApiKeyService as never,
|
||||||
|
{
|
||||||
|
getConfig: () => createConfig('api_key'),
|
||||||
|
} as never
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await service.getConfiguredConnectionIssue({}, 'anthropic')).toContain(
|
||||||
|
'Anthropic API key mode is enabled'
|
||||||
|
);
|
||||||
|
|
||||||
|
service.setApiKeyService(sharedApiKeyService as never);
|
||||||
|
|
||||||
|
expect(await service.getConfiguredConnectionIssue({}, 'anthropic')).toBeNull();
|
||||||
|
expect(sharedApiKeyService.lookupPreferred).toHaveBeenCalledWith('ANTHROPIC_API_KEY');
|
||||||
|
});
|
||||||
|
|
||||||
it('prefers stored API key status over environment detection for Anthropic', async () => {
|
it('prefers stored API key status over environment detection for Anthropic', async () => {
|
||||||
getCachedShellEnvMock.mockReturnValue({
|
getCachedShellEnvMock.mockReturnValue({
|
||||||
ANTHROPIC_API_KEY: 'shell-key',
|
ANTHROPIC_API_KEY: 'shell-key',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue