feat(runner): support OAuth providers (claude-code, openai-codex)

- Add provider alias mapping (claude-code -> anthropic)
- Resolve API key from OAuth credentials for claude-code and codex
- Add default models for each provider

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jiang Bohan
2026-02-02 16:43:00 +08:00
parent 05138029de
commit b9ce4da28f
2 changed files with 55 additions and 2 deletions

View File

@@ -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;
}

View File

@@ -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<string, string> = {
"claude-code": "anthropic", // Claude Code OAuth uses anthropic API
};
/**
* Default models for each provider.
*/
const DEFAULT_MODELS: Record<string, string> = {
"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<typeof getModel>)(
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<typeof getModel>)(
actualProvider,
defaultModel,
);
}
}
return getModel("kimi-coding", "kimi-k2-thinking");
}