mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 08:53:36 +00:00
feat: add default AI profile selection to settings view
- Introduced default AI profile management in the settings view, allowing users to select a default profile for new features. - Updated the Add Feature dialog to utilize the selected AI profile, setting default model and thinking level based on the chosen profile. - Enhanced the Feature Defaults section to display and manage the default AI profile, including a dropdown for selection and relevant information display.
This commit is contained in:
@@ -126,16 +126,25 @@ export function AddFeatureDialog({
|
|||||||
enhancementModel,
|
enhancementModel,
|
||||||
defaultPlanningMode,
|
defaultPlanningMode,
|
||||||
defaultRequirePlanApproval,
|
defaultRequirePlanApproval,
|
||||||
|
defaultAIProfileId,
|
||||||
useWorktrees,
|
useWorktrees,
|
||||||
} = useAppStore();
|
} = useAppStore();
|
||||||
|
|
||||||
// Sync defaults when dialog opens
|
// Sync defaults when dialog opens
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
|
// Find the default profile if one is set
|
||||||
|
const defaultProfile = defaultAIProfileId
|
||||||
|
? aiProfiles.find((p) => p.id === defaultAIProfileId)
|
||||||
|
: null;
|
||||||
|
|
||||||
setNewFeature((prev) => ({
|
setNewFeature((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
skipTests: defaultSkipTests,
|
skipTests: defaultSkipTests,
|
||||||
branchName: defaultBranch || "",
|
branchName: defaultBranch || "",
|
||||||
|
// Use default profile's model/thinkingLevel if set, else fallback to defaults
|
||||||
|
model: defaultProfile?.model ?? "opus",
|
||||||
|
thinkingLevel: defaultProfile?.thinkingLevel ?? "none",
|
||||||
}));
|
}));
|
||||||
setUseCurrentBranch(true);
|
setUseCurrentBranch(true);
|
||||||
setPlanningMode(defaultPlanningMode);
|
setPlanningMode(defaultPlanningMode);
|
||||||
@@ -147,6 +156,8 @@ export function AddFeatureDialog({
|
|||||||
defaultBranch,
|
defaultBranch,
|
||||||
defaultPlanningMode,
|
defaultPlanningMode,
|
||||||
defaultRequirePlanApproval,
|
defaultRequirePlanApproval,
|
||||||
|
defaultAIProfileId,
|
||||||
|
aiProfiles,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ export function SettingsView() {
|
|||||||
setDefaultPlanningMode,
|
setDefaultPlanningMode,
|
||||||
defaultRequirePlanApproval,
|
defaultRequirePlanApproval,
|
||||||
setDefaultRequirePlanApproval,
|
setDefaultRequirePlanApproval,
|
||||||
|
defaultAIProfileId,
|
||||||
|
setDefaultAIProfileId,
|
||||||
|
aiProfiles,
|
||||||
} = useAppStore();
|
} = useAppStore();
|
||||||
|
|
||||||
// Convert electron Project to settings-view Project type
|
// Convert electron Project to settings-view Project type
|
||||||
@@ -127,12 +130,15 @@ export function SettingsView() {
|
|||||||
useWorktrees={useWorktrees}
|
useWorktrees={useWorktrees}
|
||||||
defaultPlanningMode={defaultPlanningMode}
|
defaultPlanningMode={defaultPlanningMode}
|
||||||
defaultRequirePlanApproval={defaultRequirePlanApproval}
|
defaultRequirePlanApproval={defaultRequirePlanApproval}
|
||||||
|
defaultAIProfileId={defaultAIProfileId}
|
||||||
|
aiProfiles={aiProfiles}
|
||||||
onShowProfilesOnlyChange={setShowProfilesOnly}
|
onShowProfilesOnlyChange={setShowProfilesOnly}
|
||||||
onDefaultSkipTestsChange={setDefaultSkipTests}
|
onDefaultSkipTestsChange={setDefaultSkipTests}
|
||||||
onEnableDependencyBlockingChange={setEnableDependencyBlocking}
|
onEnableDependencyBlockingChange={setEnableDependencyBlocking}
|
||||||
onUseWorktreesChange={setUseWorktrees}
|
onUseWorktreesChange={setUseWorktrees}
|
||||||
onDefaultPlanningModeChange={setDefaultPlanningMode}
|
onDefaultPlanningModeChange={setDefaultPlanningMode}
|
||||||
onDefaultRequirePlanApprovalChange={setDefaultRequirePlanApproval}
|
onDefaultRequirePlanApprovalChange={setDefaultRequirePlanApproval}
|
||||||
|
onDefaultAIProfileIdChange={setDefaultAIProfileId}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "danger":
|
case "danger":
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Label } from "@/components/ui/label";
|
|||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import {
|
import {
|
||||||
FlaskConical, Settings2, TestTube, GitBranch, AlertCircle,
|
FlaskConical, Settings2, TestTube, GitBranch, AlertCircle,
|
||||||
Zap, ClipboardList, FileText, ScrollText, ShieldCheck
|
Zap, ClipboardList, FileText, ScrollText, ShieldCheck, User
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
import type { AIProfile } from "@/store/app-store";
|
||||||
|
|
||||||
type PlanningMode = 'skip' | 'lite' | 'spec' | 'full';
|
type PlanningMode = 'skip' | 'lite' | 'spec' | 'full';
|
||||||
|
|
||||||
@@ -22,12 +23,15 @@ interface FeatureDefaultsSectionProps {
|
|||||||
useWorktrees: boolean;
|
useWorktrees: boolean;
|
||||||
defaultPlanningMode: PlanningMode;
|
defaultPlanningMode: PlanningMode;
|
||||||
defaultRequirePlanApproval: boolean;
|
defaultRequirePlanApproval: boolean;
|
||||||
|
defaultAIProfileId: string | null;
|
||||||
|
aiProfiles: AIProfile[];
|
||||||
onShowProfilesOnlyChange: (value: boolean) => void;
|
onShowProfilesOnlyChange: (value: boolean) => void;
|
||||||
onDefaultSkipTestsChange: (value: boolean) => void;
|
onDefaultSkipTestsChange: (value: boolean) => void;
|
||||||
onEnableDependencyBlockingChange: (value: boolean) => void;
|
onEnableDependencyBlockingChange: (value: boolean) => void;
|
||||||
onUseWorktreesChange: (value: boolean) => void;
|
onUseWorktreesChange: (value: boolean) => void;
|
||||||
onDefaultPlanningModeChange: (value: PlanningMode) => void;
|
onDefaultPlanningModeChange: (value: PlanningMode) => void;
|
||||||
onDefaultRequirePlanApprovalChange: (value: boolean) => void;
|
onDefaultRequirePlanApprovalChange: (value: boolean) => void;
|
||||||
|
onDefaultAIProfileIdChange: (value: string | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FeatureDefaultsSection({
|
export function FeatureDefaultsSection({
|
||||||
@@ -37,13 +41,20 @@ export function FeatureDefaultsSection({
|
|||||||
useWorktrees,
|
useWorktrees,
|
||||||
defaultPlanningMode,
|
defaultPlanningMode,
|
||||||
defaultRequirePlanApproval,
|
defaultRequirePlanApproval,
|
||||||
|
defaultAIProfileId,
|
||||||
|
aiProfiles,
|
||||||
onShowProfilesOnlyChange,
|
onShowProfilesOnlyChange,
|
||||||
onDefaultSkipTestsChange,
|
onDefaultSkipTestsChange,
|
||||||
onEnableDependencyBlockingChange,
|
onEnableDependencyBlockingChange,
|
||||||
onUseWorktreesChange,
|
onUseWorktreesChange,
|
||||||
onDefaultPlanningModeChange,
|
onDefaultPlanningModeChange,
|
||||||
onDefaultRequirePlanApprovalChange,
|
onDefaultRequirePlanApprovalChange,
|
||||||
|
onDefaultAIProfileIdChange,
|
||||||
}: FeatureDefaultsSectionProps) {
|
}: FeatureDefaultsSectionProps) {
|
||||||
|
// Find the selected profile name for display
|
||||||
|
const selectedProfile = defaultAIProfileId
|
||||||
|
? aiProfiles.find((p) => p.id === defaultAIProfileId)
|
||||||
|
: null;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -169,6 +180,49 @@ export function FeatureDefaultsSection({
|
|||||||
{/* Separator */}
|
{/* Separator */}
|
||||||
{defaultPlanningMode === 'skip' && <div className="border-t border-border/30" />}
|
{defaultPlanningMode === 'skip' && <div className="border-t border-border/30" />}
|
||||||
|
|
||||||
|
{/* Default AI Profile */}
|
||||||
|
<div className="group flex items-start space-x-3 p-3 rounded-xl hover:bg-accent/30 transition-colors duration-200 -mx-3">
|
||||||
|
<div className="w-10 h-10 mt-0.5 rounded-xl flex items-center justify-center shrink-0 bg-brand-500/10">
|
||||||
|
<User className="w-5 h-5 text-brand-500" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 space-y-2">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Label className="text-foreground font-medium">
|
||||||
|
Default AI Profile
|
||||||
|
</Label>
|
||||||
|
<Select
|
||||||
|
value={defaultAIProfileId ?? "none"}
|
||||||
|
onValueChange={(v: string) => onDefaultAIProfileIdChange(v === "none" ? null : v)}
|
||||||
|
>
|
||||||
|
<SelectTrigger
|
||||||
|
className="w-[180px] h-8"
|
||||||
|
data-testid="default-ai-profile-select"
|
||||||
|
>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="none">
|
||||||
|
<span className="text-muted-foreground">None (pick manually)</span>
|
||||||
|
</SelectItem>
|
||||||
|
{aiProfiles.map((profile) => (
|
||||||
|
<SelectItem key={profile.id} value={profile.id}>
|
||||||
|
<span>{profile.name}</span>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground/80 leading-relaxed">
|
||||||
|
{selectedProfile
|
||||||
|
? `New features will use the "${selectedProfile.name}" profile (${selectedProfile.model}, ${selectedProfile.thinkingLevel} thinking).`
|
||||||
|
: "Pre-select an AI profile when creating new features. Choose \"None\" to pick manually each time."}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Separator */}
|
||||||
|
<div className="border-t border-border/30" />
|
||||||
|
|
||||||
{/* Profiles Only Setting */}
|
{/* Profiles Only Setting */}
|
||||||
<div className="group flex items-start space-x-3 p-3 rounded-xl hover:bg-accent/30 transition-colors duration-200 -mx-3">
|
<div className="group flex items-start space-x-3 p-3 rounded-xl hover:bg-accent/30 transition-colors duration-200 -mx-3">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
|||||||
@@ -494,6 +494,7 @@ export interface AppState {
|
|||||||
|
|
||||||
defaultPlanningMode: PlanningMode;
|
defaultPlanningMode: PlanningMode;
|
||||||
defaultRequirePlanApproval: boolean;
|
defaultRequirePlanApproval: boolean;
|
||||||
|
defaultAIProfileId: string | null;
|
||||||
|
|
||||||
// Plan Approval State
|
// Plan Approval State
|
||||||
// When a plan requires user approval, this holds the pending approval details
|
// When a plan requires user approval, this holds the pending approval details
|
||||||
@@ -742,6 +743,7 @@ export interface AppActions {
|
|||||||
|
|
||||||
setDefaultPlanningMode: (mode: PlanningMode) => void;
|
setDefaultPlanningMode: (mode: PlanningMode) => void;
|
||||||
setDefaultRequirePlanApproval: (require: boolean) => void;
|
setDefaultRequirePlanApproval: (require: boolean) => void;
|
||||||
|
setDefaultAIProfileId: (profileId: string | null) => void;
|
||||||
|
|
||||||
// Plan Approval actions
|
// Plan Approval actions
|
||||||
setPendingPlanApproval: (approval: {
|
setPendingPlanApproval: (approval: {
|
||||||
@@ -841,6 +843,7 @@ const initialState: AppState = {
|
|||||||
specCreatingForProject: null,
|
specCreatingForProject: null,
|
||||||
defaultPlanningMode: 'skip' as PlanningMode,
|
defaultPlanningMode: 'skip' as PlanningMode,
|
||||||
defaultRequirePlanApproval: false,
|
defaultRequirePlanApproval: false,
|
||||||
|
defaultAIProfileId: null,
|
||||||
pendingPlanApproval: null,
|
pendingPlanApproval: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2265,6 +2268,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
|||||||
|
|
||||||
setDefaultPlanningMode: (mode) => set({ defaultPlanningMode: mode }),
|
setDefaultPlanningMode: (mode) => set({ defaultPlanningMode: mode }),
|
||||||
setDefaultRequirePlanApproval: (require) => set({ defaultRequirePlanApproval: require }),
|
setDefaultRequirePlanApproval: (require) => set({ defaultRequirePlanApproval: require }),
|
||||||
|
setDefaultAIProfileId: (profileId) => set({ defaultAIProfileId: profileId }),
|
||||||
|
|
||||||
// Plan Approval actions
|
// Plan Approval actions
|
||||||
setPendingPlanApproval: (approval) => set({ pendingPlanApproval: approval }),
|
setPendingPlanApproval: (approval) => set({ pendingPlanApproval: approval }),
|
||||||
@@ -2340,6 +2344,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
|||||||
boardBackgroundByProject: state.boardBackgroundByProject,
|
boardBackgroundByProject: state.boardBackgroundByProject,
|
||||||
defaultPlanningMode: state.defaultPlanningMode,
|
defaultPlanningMode: state.defaultPlanningMode,
|
||||||
defaultRequirePlanApproval: state.defaultRequirePlanApproval,
|
defaultRequirePlanApproval: state.defaultRequirePlanApproval,
|
||||||
|
defaultAIProfileId: state.defaultAIProfileId,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user