feat: add Claude API provider profiles for alternative endpoints

Add support for managing multiple Claude-compatible API endpoints
(z.AI GLM, AWS Bedrock, etc.) through provider profiles in settings.

Features:
- New ClaudeApiProfile type with base URL, API key, model mappings
- Pre-configured z.AI GLM template with correct model names
- Profile selector in Settings > Claude > API Profiles
- Clean switching between profiles and direct Anthropic API
- Immediate persistence to prevent data loss on restart

Profile support added to all execution paths:
- Agent service (chat)
- Ideation service
- Auto-mode service (feature agents, enhancements)
- Simple query service (title generation, descriptions, etc.)
- Backlog planning, commit messages, spec generation
- GitHub issue validation, suggestions

Environment variables set when profile is active:
- ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN/API_KEY
- ANTHROPIC_DEFAULT_HAIKU/SONNET/OPUS_MODEL
- API_TIMEOUT_MS, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC
This commit is contained in:
Stefan de Vogelaere
2026-01-18 13:50:41 +01:00
parent 044c3d50d1
commit 53298106e9
25 changed files with 1080 additions and 136 deletions

View File

@@ -31,6 +31,7 @@ import type {
ModelDefinition,
ServerLogLevel,
EventHook,
ClaudeApiProfile,
} from '@automaker/types';
import {
getAllCursorModelIds,
@@ -742,6 +743,10 @@ export interface AppState {
// Event Hooks
eventHooks: EventHook[]; // Event hooks for custom commands or webhooks
// Claude API Profiles
claudeApiProfiles: ClaudeApiProfile[]; // Claude-compatible API endpoint profiles
activeClaudeApiProfileId: string | null; // Active profile ID (null = use direct Anthropic API)
// Project Analysis
projectAnalysis: ProjectAnalysis | null;
isAnalyzing: boolean;
@@ -1172,6 +1177,13 @@ export interface AppActions {
// Event Hook actions
setEventHooks: (hooks: EventHook[]) => void;
// Claude API Profile actions
addClaudeApiProfile: (profile: ClaudeApiProfile) => Promise<void>;
updateClaudeApiProfile: (id: string, updates: Partial<ClaudeApiProfile>) => Promise<void>;
deleteClaudeApiProfile: (id: string) => Promise<void>;
setActiveClaudeApiProfile: (id: string | null) => Promise<void>;
setClaudeApiProfiles: (profiles: ClaudeApiProfile[]) => Promise<void>;
// MCP Server actions
addMCPServer: (server: Omit<MCPServerConfig, 'id'>) => void;
updateMCPServer: (id: string, updates: Partial<MCPServerConfig>) => void;
@@ -1426,6 +1438,8 @@ const initialState: AppState = {
subagentsSources: ['user', 'project'] as Array<'user' | 'project'>, // Load from both sources by default
promptCustomization: {}, // Empty by default - all prompts use built-in defaults
eventHooks: [], // No event hooks configured by default
claudeApiProfiles: [], // No Claude API profiles configured by default
activeClaudeApiProfileId: null, // Use direct Anthropic API by default
projectAnalysis: null,
isAnalyzing: false,
boardBackgroundByProject: {},
@@ -2428,6 +2442,51 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
// Event Hook actions
setEventHooks: (hooks) => set({ eventHooks: hooks }),
// Claude API Profile actions
addClaudeApiProfile: async (profile) => {
set({ claudeApiProfiles: [...get().claudeApiProfiles, profile] });
// Sync immediately to persist profile
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
updateClaudeApiProfile: async (id, updates) => {
set({
claudeApiProfiles: get().claudeApiProfiles.map((p) =>
p.id === id ? { ...p, ...updates } : p
),
});
// Sync immediately to persist changes
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
deleteClaudeApiProfile: async (id) => {
const currentActiveId = get().activeClaudeApiProfileId;
set({
claudeApiProfiles: get().claudeApiProfiles.filter((p) => p.id !== id),
// Clear active if the deleted profile was active
activeClaudeApiProfileId: currentActiveId === id ? null : currentActiveId,
});
// Sync immediately to persist deletion
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
setActiveClaudeApiProfile: async (id) => {
set({ activeClaudeApiProfileId: id });
// Sync immediately to persist active profile change
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
setClaudeApiProfiles: async (profiles) => {
set({ claudeApiProfiles: profiles });
// Sync immediately to persist profiles
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
// MCP Server actions
addMCPServer: (server) => {
const id = `mcp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;