mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 20:43:36 +00:00
feat: add per-project default model override for new features (#640)
* feat: add per-project default model override for new features
- Add defaultFeatureModel to ProjectSettings type for project-level override
- Add defaultFeatureModel to Project interface for UI state
- Display Default Feature Model in Model Defaults section alongside phase models
- Include Default Feature Model in global Bulk Replace dialog
- Add Default Feature Model override section to Project Settings
- Add setProjectDefaultFeatureModel store action for project-level overrides
- Update clearAllProjectPhaseModelOverrides to also clear defaultFeatureModel
- Update add-feature-dialog to use project override when available
- Include Default Feature Model in Project Bulk Replace dialog
This allows projects with different complexity levels to use different
default models (e.g., Haiku for simple tasks, Opus for complex projects).
* fix: add server-side __CLEAR__ handler for defaultFeatureModel
- Add handler in settings-service.ts to properly delete defaultFeatureModel
when '__CLEAR__' marker is sent from the UI
- Fix bulk-replace-dialog.tsx to correctly return claude-opus when resetting
default feature model to Anthropic Direct (was incorrectly using
enhancementModel's settings which default to sonnet)
These fixes ensure:
1. Clearing project default model override properly removes the setting
instead of storing literal '__CLEAR__' string
2. Global bulk replace correctly resets default feature model to opus
* fix: include defaultFeatureModel in Reset to Defaults action
- Updated resetPhaseModels to also reset defaultFeatureModel to claude-opus
- Fixed initial state to use canonical 'claude-opus' instead of 'opus'
* refactor: use DEFAULT_GLOBAL_SETTINGS constant for defaultFeatureModel
Address PR review feedback:
- Replace hardcoded { model: 'claude-opus' } with DEFAULT_GLOBAL_SETTINGS.defaultFeatureModel
- Fix Prettier formatting for long destructuring lines
- Import DEFAULT_GLOBAL_SETTINGS from @automaker/types where needed
This improves maintainability by centralizing the default value.
This commit is contained in:
committed by
GitHub
parent
3ebd67f35f
commit
5ab53afd7f
@@ -42,6 +42,7 @@ import {
|
||||
DEFAULT_PHASE_MODELS,
|
||||
DEFAULT_OPENCODE_MODEL,
|
||||
DEFAULT_MAX_CONCURRENCY,
|
||||
DEFAULT_GLOBAL_SETTINGS,
|
||||
} from '@automaker/types';
|
||||
|
||||
const logger = createLogger('AppStore');
|
||||
@@ -1055,6 +1056,12 @@ export interface AppActions {
|
||||
) => void;
|
||||
clearAllProjectPhaseModelOverrides: (projectId: string) => void;
|
||||
|
||||
// Project Default Feature Model Override
|
||||
setProjectDefaultFeatureModel: (
|
||||
projectId: string,
|
||||
entry: import('@automaker/types').PhaseModelEntry | null // null = use global
|
||||
) => void;
|
||||
|
||||
// Feature actions
|
||||
setFeatures: (features: Feature[]) => void;
|
||||
updateFeature: (id: string, updates: Partial<Feature>) => void;
|
||||
@@ -1527,7 +1534,7 @@ const initialState: AppState = {
|
||||
specCreatingForProject: null,
|
||||
defaultPlanningMode: 'skip' as PlanningMode,
|
||||
defaultRequirePlanApproval: false,
|
||||
defaultFeatureModel: { model: 'opus' } as PhaseModelEntry,
|
||||
defaultFeatureModel: DEFAULT_GLOBAL_SETTINGS.defaultFeatureModel,
|
||||
pendingPlanApproval: null,
|
||||
claudeRefreshInterval: 60,
|
||||
claudeUsage: null,
|
||||
@@ -2105,9 +2112,11 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear overrides from project
|
||||
// Clear all model overrides from project (phaseModelOverrides + defaultFeatureModel)
|
||||
const projects = get().projects.map((p) =>
|
||||
p.id === projectId ? { ...p, phaseModelOverrides: undefined } : p
|
||||
p.id === projectId
|
||||
? { ...p, phaseModelOverrides: undefined, defaultFeatureModel: undefined }
|
||||
: p
|
||||
);
|
||||
set({ projects });
|
||||
|
||||
@@ -2118,6 +2127,49 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
currentProject: {
|
||||
...currentProject,
|
||||
phaseModelOverrides: undefined,
|
||||
defaultFeatureModel: undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Persist to server (clear both)
|
||||
const httpClient = getHttpApiClient();
|
||||
httpClient.settings
|
||||
.updateProject(project.path, {
|
||||
phaseModelOverrides: '__CLEAR__',
|
||||
defaultFeatureModel: '__CLEAR__',
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to clear model overrides:', error);
|
||||
});
|
||||
},
|
||||
|
||||
setProjectDefaultFeatureModel: (projectId, entry) => {
|
||||
// Find the project to get its path for server sync
|
||||
const project = get().projects.find((p) => p.id === projectId);
|
||||
if (!project) {
|
||||
console.error('Cannot set default feature model: project not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the project's defaultFeatureModel
|
||||
const projects = get().projects.map((p) =>
|
||||
p.id === projectId
|
||||
? {
|
||||
...p,
|
||||
defaultFeatureModel: entry ?? undefined,
|
||||
}
|
||||
: p
|
||||
);
|
||||
set({ projects });
|
||||
|
||||
// Also update currentProject if it's the same project
|
||||
const currentProject = get().currentProject;
|
||||
if (currentProject?.id === projectId) {
|
||||
set({
|
||||
currentProject: {
|
||||
...currentProject,
|
||||
defaultFeatureModel: entry ?? undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -2126,10 +2178,10 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
const httpClient = getHttpApiClient();
|
||||
httpClient.settings
|
||||
.updateProject(project.path, {
|
||||
phaseModelOverrides: '__CLEAR__',
|
||||
defaultFeatureModel: entry ?? '__CLEAR__',
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to clear phaseModelOverrides:', error);
|
||||
console.error('Failed to persist defaultFeatureModel:', error);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -2571,7 +2623,10 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
await syncSettingsToServer();
|
||||
},
|
||||
resetPhaseModels: async () => {
|
||||
set({ phaseModels: DEFAULT_PHASE_MODELS });
|
||||
set({
|
||||
phaseModels: DEFAULT_PHASE_MODELS,
|
||||
defaultFeatureModel: DEFAULT_GLOBAL_SETTINGS.defaultFeatureModel,
|
||||
});
|
||||
// Sync to server settings file
|
||||
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
|
||||
await syncSettingsToServer();
|
||||
|
||||
Reference in New Issue
Block a user