feat: refactor Claude API Profiles to Claude Compatible Providers

- 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
This commit is contained in:
Stefan de Vogelaere
2026-01-20 19:13:34 +01:00
parent 47e6ed6a17
commit 2ceab3d65e
40 changed files with 3730 additions and 1019 deletions

View File

@@ -109,25 +109,45 @@ export function useProjectSettingsLoader() {
);
}
// Apply activeClaudeApiProfileId if present
// This is stored directly on the project, so we need to update the currentProject
// Apply activeClaudeApiProfileId and phaseModelOverrides if present
// These are stored directly on the project, so we need to update both
// currentProject AND the projects array to keep them in sync
// Type assertion needed because API returns Record<string, unknown>
const settingsWithProfile = result.settings as Record<string, unknown>;
const activeClaudeApiProfileId = settingsWithProfile.activeClaudeApiProfileId as
| string
| null
| undefined;
if (activeClaudeApiProfileId !== undefined) {
const updatedProject = useAppStore.getState().currentProject;
if (
updatedProject &&
updatedProject.path === requestedProjectPath &&
updatedProject.activeClaudeApiProfileId !== activeClaudeApiProfileId
) {
setCurrentProject({
const phaseModelOverrides = settingsWithProfile.phaseModelOverrides as
| import('@automaker/types').PhaseModelConfig
| undefined;
// Check if we need to update the project
const storeState = useAppStore.getState();
const updatedProject = storeState.currentProject;
if (updatedProject && updatedProject.path === requestedProjectPath) {
const needsUpdate =
(activeClaudeApiProfileId !== undefined &&
updatedProject.activeClaudeApiProfileId !== activeClaudeApiProfileId) ||
(phaseModelOverrides !== undefined &&
JSON.stringify(updatedProject.phaseModelOverrides) !==
JSON.stringify(phaseModelOverrides));
if (needsUpdate) {
const updatedProjectData = {
...updatedProject,
activeClaudeApiProfileId,
});
...(activeClaudeApiProfileId !== undefined && { activeClaudeApiProfileId }),
...(phaseModelOverrides !== undefined && { phaseModelOverrides }),
};
// Update currentProject
setCurrentProject(updatedProjectData);
// Also update the project in the projects array to keep them in sync
const updatedProjects = storeState.projects.map((p) =>
p.id === updatedProject.id ? updatedProjectData : p
);
useAppStore.setState({ projects: updatedProjects });
}
}
}