- Rename ClaudeApiProfile to ClaudeCompatibleProvider with models[] array - Each ProviderModel has mapsToClaudeModel field for Claude tier mapping - Add providerType field for provider-specific icons (glm, minimax, openrouter) - Add thinking level support for provider models in phase selectors - Show all mapped Claude models per provider model (e.g., "Maps to Haiku, Sonnet, Opus") - Add Bulk Replace feature to switch all phases to a provider at once - Hide Bulk Replace button when no providers are enabled - Fix project-level phaseModelOverrides not persisting after refresh - Fix deleting last provider not persisting (remove empty array guard) - Add getProviderByModelId() helper for all SDK routes - Update all routes to pass provider config for provider models - Update terminology from "profiles" to "providers" throughout UI - Update documentation to reflect new provider system
10 KiB
Claude Compatible Providers System
This document describes the implementation of Claude Compatible Providers, allowing users to configure alternative API endpoints that expose Claude-compatible models to the application.
Overview
Claude Compatible Providers allow Automaker to work with third-party API endpoints that implement Claude's API protocol. This enables:
- Cost savings: Use providers like z.AI GLM or MiniMax at lower costs
- Alternative models: Access models like GLM-4.7 or MiniMax M2.1 through familiar interfaces
- Flexibility: Configure per-phase model selection to optimize for speed vs quality
- Project overrides: Use different providers for different projects
Architecture
Type Definitions
ClaudeCompatibleProvider
export interface ClaudeCompatibleProvider {
id: string; // Unique identifier (UUID)
name: string; // Display name (e.g., "z.AI GLM")
baseUrl: string; // API endpoint URL
providerType?: string; // Provider type for icon/grouping (e.g., 'glm', 'minimax', 'openrouter')
apiKeySource?: ApiKeySource; // 'inline' | 'env' | 'credentials'
apiKey?: string; // API key (when apiKeySource = 'inline')
useAuthToken?: boolean; // Use ANTHROPIC_AUTH_TOKEN header
timeoutMs?: number; // Request timeout in milliseconds
disableNonessentialTraffic?: boolean; // Minimize non-essential API calls
enabled?: boolean; // Whether provider is active (default: true)
models?: ProviderModel[]; // Models exposed by this provider
}
ProviderModel
export interface ProviderModel {
id: string; // Model ID sent to API (e.g., "GLM-4.7")
displayName: string; // Display name in UI (e.g., "GLM 4.7")
mapsToClaudeModel?: ClaudeModelAlias; // Which Claude tier this replaces ('haiku' | 'sonnet' | 'opus')
capabilities?: {
supportsVision?: boolean; // Whether model supports image inputs
supportsThinking?: boolean; // Whether model supports extended thinking
maxThinkingLevel?: ThinkingLevel; // Maximum thinking level if supported
};
}
PhaseModelEntry
Phase model configuration now supports provider models:
export interface PhaseModelEntry {
providerId?: string; // Provider ID (undefined = native Claude)
model: string; // Model ID or alias
thinkingLevel?: ThinkingLevel; // 'none' | 'low' | 'medium' | 'high'
}
Provider Templates
Available provider templates in CLAUDE_PROVIDER_TEMPLATES:
| Template | Provider Type | Base URL | Description |
|---|---|---|---|
| Direct Anthropic | anthropic | https://api.anthropic.com |
Standard Anthropic API |
| OpenRouter | openrouter | https://openrouter.ai/api |
Access Claude and 300+ models |
| z.AI GLM | glm | https://api.z.ai/api/anthropic |
GLM models at lower cost |
| MiniMax | minimax | https://api.minimax.io/anthropic |
MiniMax M2.1 model |
| MiniMax (China) | minimax | https://api.minimaxi.com/anthropic |
MiniMax for China region |
Model Mappings
Each provider model specifies which Claude model tier it maps to via mapsToClaudeModel:
z.AI GLM:
GLM-4.5-Air→ haikuGLM-4.7→ sonnet, opus
MiniMax:
MiniMax-M2.1→ haiku, sonnet, opus
OpenRouter:
anthropic/claude-3.5-haiku→ haikuanthropic/claude-3.5-sonnet→ sonnetanthropic/claude-3-opus→ opus
Server-Side Implementation
API Key Resolution
The buildEnv() function in claude-provider.ts resolves API keys based on apiKeySource:
function buildEnv(
providerConfig?: ClaudeCompatibleProvider,
credentials?: Credentials
): Record<string, string | undefined> {
if (providerConfig) {
let apiKey: string | undefined;
const source = providerConfig.apiKeySource ?? 'inline';
switch (source) {
case 'inline':
apiKey = providerConfig.apiKey;
break;
case 'env':
apiKey = process.env.ANTHROPIC_API_KEY;
break;
case 'credentials':
apiKey = credentials?.apiKeys?.anthropic;
break;
}
// ... build environment with resolved key
}
}
Provider Lookup
The getProviderByModelId() helper resolves provider configuration from model IDs:
export async function getProviderByModelId(
modelId: string,
settingsService: SettingsService,
logPrefix?: string
): Promise<{
provider?: ClaudeCompatibleProvider;
resolvedModel?: string;
credentials?: Credentials;
}>;
This is used by all routes that call the Claude SDK to:
- Check if the model ID belongs to a provider
- Get the provider configuration (baseUrl, auth, etc.)
- Resolve the
mapsToClaudeModelfor the SDK
Phase Model Resolution
The getPhaseModelWithOverrides() helper gets effective phase model config:
export async function getPhaseModelWithOverrides(
phaseKey: PhaseModelKey,
settingsService: SettingsService,
projectPath?: string,
logPrefix?: string
): Promise<{
model: string;
thinkingLevel?: ThinkingLevel;
providerId?: string;
providerConfig?: ClaudeCompatibleProvider;
credentials?: Credentials;
}>;
This handles:
- Project-level overrides (if projectPath provided)
- Global phase model settings
- Default fallback models
UI Implementation
Model Selection Dropdowns
Phase model selectors (PhaseModelSelector) display:
- Claude Models - Native Claude models (Haiku, Sonnet, Opus)
- Provider Sections - Each enabled provider as a separate group:
- Section header:
{provider.name} (via Claude) - Models with their mapped Claude tiers: "Maps to Haiku, Sonnet, Opus"
- Thinking level submenu for models that support it
- Section header:
Provider Icons
Icons are determined by providerType:
glm→ Z logominimax→ MiniMax logoopenrouter→ OpenRouter logo- Generic → OpenRouter as fallback
Bulk Replace
The "Bulk Replace" feature allows switching all phase models to a provider at once:
- Select a provider from the dropdown
- Preview shows which models will be assigned:
- haiku phases → provider's haiku-mapped model
- sonnet phases → provider's sonnet-mapped model
- opus phases → provider's opus-mapped model
- Apply replaces all phase model configurations
The Bulk Replace button only appears when at least one provider is enabled.
Project-Level Overrides
Projects can override global phase model settings via phaseModelOverrides:
interface Project {
// ...
phaseModelOverrides?: PhaseModelConfig; // Per-phase overrides
}
Storage
Project overrides are stored in .automaker/settings.json:
{
"phaseModelOverrides": {
"enhancementModel": {
"providerId": "provider-uuid",
"model": "GLM-4.5-Air",
"thinkingLevel": "none"
}
}
}
Resolution Priority
- Project override for specific phase (if set)
- Global phase model setting
- Default model for phase
Migration
v5 → v6 Migration
The system migrated from claudeApiProfiles to claudeCompatibleProviders:
// Old: modelMappings object
{
modelMappings: {
haiku: 'GLM-4.5-Air',
sonnet: 'GLM-4.7',
opus: 'GLM-4.7'
}
}
// New: models array with mapsToClaudeModel
{
models: [
{ id: 'GLM-4.5-Air', displayName: 'GLM 4.5 Air', mapsToClaudeModel: 'haiku' },
{ id: 'GLM-4.7', displayName: 'GLM 4.7', mapsToClaudeModel: 'sonnet' },
{ id: 'GLM-4.7', displayName: 'GLM 4.7', mapsToClaudeModel: 'opus' },
]
}
The migration is automatic and preserves existing provider configurations.
Files Changed
Types
| File | Changes |
|---|---|
libs/types/src/settings.ts |
ClaudeCompatibleProvider, ProviderModel, PhaseModelEntry types |
libs/types/src/provider.ts |
ExecuteOptions.claudeCompatibleProvider field |
libs/types/src/index.ts |
Exports for new types |
Server
| File | Changes |
|---|---|
apps/server/src/providers/claude-provider.ts |
Provider config handling, buildEnv updates |
apps/server/src/lib/settings-helpers.ts |
getProviderByModelId(), getPhaseModelWithOverrides() |
apps/server/src/services/settings-service.ts |
v5→v6 migration |
apps/server/src/routes/**/*.ts |
Provider lookup for all SDK calls |
UI
| File | Changes |
|---|---|
apps/ui/src/.../phase-model-selector.tsx |
Provider model rendering, thinking levels |
apps/ui/src/.../bulk-replace-dialog.tsx |
Bulk replace feature |
apps/ui/src/.../api-profiles-section.tsx |
Provider management UI |
apps/ui/src/components/ui/provider-icon.tsx |
Provider-specific icons |
apps/ui/src/hooks/use-project-settings-loader.ts |
Load phaseModelOverrides |
Testing
# Build and run
npm run build:packages
npm run dev:web
# Run server tests
npm run test:server
Test Cases
- Provider setup: Add z.AI GLM provider with inline API key
- Model selection: Select GLM-4.7 for a phase, verify it appears in dropdown
- Thinking levels: Select thinking level for provider model
- Bulk replace: Switch all phases to a provider at once
- Project override: Set per-project model override, verify it persists
- Provider deletion: Delete all providers, verify empty state persists
Future Enhancements
Potential improvements:
- Provider validation: Test API connection before saving
- Usage tracking: Show which phases use which provider
- Cost estimation: Display estimated costs per provider
- Model capabilities: Auto-detect supported features from provider