daemon: enforce auth_mode for OpenAI and Anthropic
This commit is contained in:
+119
-14
@@ -3,7 +3,20 @@ import { AnthropicClient, OpenAIClient, OllamaClient, LlamaCppClient, GeminiClie
|
||||
import type { ModelClient, RetryConfig, ModelTier } from '../models/index.js';
|
||||
import { logger } from '../logger.js';
|
||||
import { getZaiApiKey } from '../auth/zai.js';
|
||||
import { getAnthropicApiKey } from '../auth/anthropic.js';
|
||||
import { getAnthropicApiKey, getAnthropicAuthToken } from '../auth/anthropic.js';
|
||||
import { getOpenAIApiKey, loadStoredOpenAIAuth } from '../auth/openai.js';
|
||||
|
||||
type AuthMode = 'auto' | 'api_key' | 'oauth';
|
||||
|
||||
function getEffectiveAuthMode(cfg: ModelConfig): AuthMode {
|
||||
if (cfg.auth_mode) {
|
||||
return cfg.auth_mode;
|
||||
}
|
||||
if (cfg.use_oauth) {
|
||||
return 'oauth';
|
||||
}
|
||||
return 'auto';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an API key from config or environment variable.
|
||||
@@ -45,23 +58,115 @@ function resolveAuthCredential(cfg: ModelConfig, apiKeyEnvVar: string, authToken
|
||||
export function createClientFromConfig(cfg: ModelConfig): ModelClient {
|
||||
switch (cfg.provider) {
|
||||
case 'anthropic':
|
||||
if (!cfg.api_key && !getAnthropicApiKey()) {
|
||||
{
|
||||
const authMode = getEffectiveAuthMode(cfg);
|
||||
|
||||
if (authMode === 'oauth') {
|
||||
const token = cfg.auth_token ?? getAnthropicAuthToken();
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
'Anthropic auth token not configured (auth_mode: oauth). ' +
|
||||
'Set ANTHROPIC_AUTH_TOKEN, run `flynn anthropic-auth --token`, or provide auth_token in config.',
|
||||
);
|
||||
}
|
||||
return new AnthropicClient({
|
||||
model: cfg.model,
|
||||
authToken: token,
|
||||
});
|
||||
}
|
||||
|
||||
if (authMode === 'api_key') {
|
||||
const apiKey = cfg.api_key ?? getAnthropicApiKey();
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
'Anthropic API key not configured (auth_mode: api_key). ' +
|
||||
'Set ANTHROPIC_API_KEY, run `flynn anthropic-auth`, or provide api_key in config.',
|
||||
);
|
||||
}
|
||||
return new AnthropicClient({
|
||||
model: cfg.model,
|
||||
apiKey,
|
||||
});
|
||||
}
|
||||
|
||||
// auto: prefer API key, then token
|
||||
const apiKey = cfg.api_key ?? getAnthropicApiKey();
|
||||
if (apiKey) {
|
||||
return new AnthropicClient({
|
||||
model: cfg.model,
|
||||
apiKey,
|
||||
});
|
||||
}
|
||||
|
||||
const token = cfg.auth_token ?? getAnthropicAuthToken();
|
||||
if (token) {
|
||||
return new AnthropicClient({
|
||||
model: cfg.model,
|
||||
authToken: token,
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
'Anthropic API key not configured. ' +
|
||||
'Set ANTHROPIC_API_KEY, run `flynn anthropic-auth`, or provide api_key in config.',
|
||||
'Anthropic credentials not configured (auth_mode: auto). ' +
|
||||
'Set ANTHROPIC_API_KEY (or run `flynn anthropic-auth`), ' +
|
||||
'or set ANTHROPIC_AUTH_TOKEN (or run `flynn anthropic-auth --token`).',
|
||||
);
|
||||
}
|
||||
return new AnthropicClient({
|
||||
model: cfg.model,
|
||||
apiKey: cfg.api_key ?? getAnthropicApiKey() ?? undefined,
|
||||
authToken: cfg.auth_token,
|
||||
});
|
||||
case 'openai':
|
||||
return new OpenAIClient({
|
||||
model: cfg.model,
|
||||
apiKey: cfg.api_key,
|
||||
useOAuth: Boolean(cfg.use_oauth),
|
||||
});
|
||||
{
|
||||
const authMode = getEffectiveAuthMode(cfg);
|
||||
|
||||
if (authMode === 'oauth') {
|
||||
const existing = loadStoredOpenAIAuth();
|
||||
if (!existing) {
|
||||
throw new Error(
|
||||
'OpenAI OAuth is not configured (auth_mode: oauth). ' +
|
||||
'Run `flynn openai-auth` to authenticate.',
|
||||
);
|
||||
}
|
||||
return new OpenAIClient({
|
||||
model: cfg.model,
|
||||
useOAuth: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (authMode === 'api_key') {
|
||||
const apiKey = cfg.api_key ?? getOpenAIApiKey();
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
'OpenAI API key not configured (auth_mode: api_key). ' +
|
||||
'Set OPENAI_API_KEY, run `flynn openai-key`, or provide api_key in config.',
|
||||
);
|
||||
}
|
||||
return new OpenAIClient({
|
||||
model: cfg.model,
|
||||
apiKey,
|
||||
});
|
||||
}
|
||||
|
||||
// auto: prefer API key, then OAuth
|
||||
const apiKey = cfg.api_key ?? getOpenAIApiKey();
|
||||
if (apiKey) {
|
||||
return new OpenAIClient({
|
||||
model: cfg.model,
|
||||
apiKey,
|
||||
});
|
||||
}
|
||||
|
||||
const existing = loadStoredOpenAIAuth();
|
||||
if (existing) {
|
||||
return new OpenAIClient({
|
||||
model: cfg.model,
|
||||
useOAuth: true,
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
'OpenAI credentials not configured (auth_mode: auto). ' +
|
||||
'Set OPENAI_API_KEY (or run `flynn openai-key`), ' +
|
||||
'or run `flynn openai-auth` for OAuth.',
|
||||
);
|
||||
}
|
||||
case 'ollama':
|
||||
return new OllamaClient({
|
||||
model: cfg.model,
|
||||
|
||||
Reference in New Issue
Block a user