diff --git a/src/agent/runner.ts b/src/agent/runner.ts index bf73268f2..368d04379 100644 --- a/src/agent/runner.ts +++ b/src/agent/runner.ts @@ -7,6 +7,7 @@ import { SessionManager } from "./session/session-manager.js"; import { ProfileManager } from "./profile/index.js"; import { SkillManager } from "./skills/index.js"; import { credentialManager, getCredentialsPath } from "./credentials.js"; +import { resolveProviderConfig } from "./credentials/providers.js"; import { checkContextWindow, DEFAULT_CONTEXT_TOKENS, @@ -16,10 +17,24 @@ import { mergeToolsConfig, type ToolsConfig } from "./tools/policy.js"; /** * Get API Key based on provider. - * Priority: explicit key > provider-specific env var > generic env var format. + * Priority: explicit key > OAuth credentials > credentials.json5 config. + * + * Supports OAuth providers like "claude-code" and "openai-codex" by + * reading credentials from their respective CLI tools. */ function resolveApiKey(provider: string, explicitKey?: string): string | undefined { if (explicitKey) return explicitKey; + + // Try OAuth providers first (claude-code, openai-codex) + const providerConfig = resolveProviderConfig(provider); + if (providerConfig?.apiKey) { + return providerConfig.apiKey; + } + if (providerConfig?.accessToken) { + return providerConfig.accessToken; + } + + // Fall back to credentials.json5 return credentialManager.getLlmProviderConfig(provider)?.apiKey; } diff --git a/src/agent/tools.ts b/src/agent/tools.ts index 6578a238d..8cec06b3f 100644 --- a/src/agent/tools.ts +++ b/src/agent/tools.ts @@ -9,14 +9,52 @@ import { createWebFetchTool, createWebSearchTool } from "./tools/web/index.js"; import { createMemoryTools } from "./tools/memory/index.js"; import { filterTools } from "./tools/policy.js"; +/** + * Provider alias mapping for OAuth providers. + * Maps friendly names to actual pi-ai provider names. + */ +const PROVIDER_ALIAS: Record = { + "claude-code": "anthropic", // Claude Code OAuth uses anthropic API +}; + +/** + * Default models for each provider. + */ +const DEFAULT_MODELS: Record = { + "anthropic": "claude-sonnet-4-20250514", + "claude-code": "claude-sonnet-4-20250514", + "openai": "gpt-4o", + "openai-codex": "gpt-5.1", + "kimi-coding": "kimi-k2-thinking", + "google": "gemini-2.0-flash", + "groq": "llama-3.3-70b-versatile", + "mistral": "mistral-large-latest", +}; + export function resolveModel(options: AgentOptions) { if (options.provider && options.model) { + // Map provider alias (e.g., claude-code -> anthropic) + const actualProvider = PROVIDER_ALIAS[options.provider] ?? options.provider; + // Type assertion needed because provider/model come from dynamic user config return (getModel as (p: string, m: string) => ReturnType)( - options.provider, + actualProvider, options.model, ); } + + // If only provider specified, use default model for that provider + if (options.provider) { + const actualProvider = PROVIDER_ALIAS[options.provider] ?? options.provider; + const defaultModel = DEFAULT_MODELS[options.provider] ?? DEFAULT_MODELS[actualProvider]; + if (defaultModel) { + return (getModel as (p: string, m: string) => ReturnType)( + actualProvider, + defaultModel, + ); + } + } + return getModel("kimi-coding", "kimi-k2-thinking"); }