refactor: move Agent Profiles from dashboard to Settings

Move the Agent Profiles configuration from a separate dashboard tab
to the Settings page under "Agent Settings". This provides a more
intuitive location for users to configure their default agent profile.

Changes:
- Create AgentProfileSettings component for settings page
- Add agent profiles to GeneralSettings 'agent' section
- Remove 'agent-profiles' from sidebar navigation
- Remove AgentProfiles view from App.tsx routing
- Update SidebarView type

The agent profiles are now accessible via Settings > Agent Settings,
alongside other agent-related configuration options.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
AndyMik90
2025-12-20 12:37:47 +01:00
parent 9ab5a4f2cc
commit 10949905f7
4 changed files with 178 additions and 64 deletions
-4
View File
@@ -29,7 +29,6 @@ import { Insights } from './components/Insights';
import { GitHubIssues } from './components/GitHubIssues';
import { Changelog } from './components/Changelog';
import { Worktrees } from './components/Worktrees';
import { AgentProfiles } from './components/AgentProfiles';
import { WelcomeScreen } from './components/WelcomeScreen';
import { RateLimitModal } from './components/RateLimitModal';
import { SDKRateLimitModal } from './components/SDKRateLimitModal';
@@ -462,9 +461,6 @@ export function App() {
{activeView === 'worktrees' && selectedProjectId && (
<Worktrees projectId={selectedProjectId} />
)}
{activeView === 'agent-profiles' && (
<AgentProfiles />
)}
{activeView === 'agent-tools' && (
<div className="flex h-full items-center justify-center">
<div className="text-center">
@@ -16,8 +16,7 @@ import {
FileText,
Sparkles,
GitBranch,
HelpCircle,
UserCog
HelpCircle
} from 'lucide-react';
import { Button } from './ui/button';
import { ScrollArea } from './ui/scroll-area';
@@ -57,7 +56,7 @@ import { GitSetupModal } from './GitSetupModal';
import { RateLimitIndicator } from './RateLimitIndicator';
import type { Project, AutoBuildVersionInfo, GitStatus } from '../../shared/types';
export type SidebarView = 'kanban' | 'terminals' | 'roadmap' | 'context' | 'ideation' | 'github-issues' | 'changelog' | 'insights' | 'worktrees' | 'agent-tools' | 'agent-profiles';
export type SidebarView = 'kanban' | 'terminals' | 'roadmap' | 'context' | 'ideation' | 'github-issues' | 'changelog' | 'insights' | 'worktrees' | 'agent-tools';
interface SidebarProps {
onSettingsClick: () => void;
@@ -85,8 +84,7 @@ const projectNavItems: NavItem[] = [
const toolsNavItems: NavItem[] = [
{ id: 'github-issues', label: 'GitHub Issues', icon: Github, shortcut: 'G' },
{ id: 'worktrees', label: 'Worktrees', icon: GitBranch, shortcut: 'W' },
{ id: 'agent-profiles', label: 'Agent Profiles', icon: UserCog, shortcut: 'P' }
{ id: 'worktrees', label: 'Worktrees', icon: GitBranch, shortcut: 'W' }
];
export function Sidebar({
@@ -0,0 +1,132 @@
import { Brain, Scale, Zap, Check, Sparkles } from 'lucide-react';
import { cn } from '../../lib/utils';
import { DEFAULT_AGENT_PROFILES, AVAILABLE_MODELS, THINKING_LEVELS } from '../../../shared/constants';
import { useSettingsStore, saveSettings } from '../../stores/settings-store';
import { SettingsSection } from './SettingsSection';
import type { AgentProfile } from '../../../shared/types/settings';
/**
* Icon mapping for agent profile icons
*/
const iconMap: Record<string, React.ElementType> = {
Brain,
Scale,
Zap,
Sparkles
};
/**
* Agent Profile Settings component
* Displays preset agent profiles for quick model/thinking level configuration
* Used in the Settings page under Agent Settings
*/
export function AgentProfileSettings() {
const settings = useSettingsStore((state) => state.settings);
const selectedProfileId = settings.selectedAgentProfile || 'auto';
const handleSelectProfile = async (profileId: string) => {
await saveSettings({ selectedAgentProfile: profileId });
};
/**
* Get human-readable model label
*/
const getModelLabel = (modelValue: string): string => {
const model = AVAILABLE_MODELS.find((m) => m.value === modelValue);
return model?.label || modelValue;
};
/**
* Get human-readable thinking level label
*/
const getThinkingLabel = (thinkingValue: string): string => {
const level = THINKING_LEVELS.find((l) => l.value === thinkingValue);
return level?.label || thinkingValue;
};
/**
* Render a single profile card
*/
const renderProfileCard = (profile: AgentProfile) => {
const isSelected = selectedProfileId === profile.id;
const Icon = iconMap[profile.icon || 'Brain'] || Brain;
return (
<button
key={profile.id}
onClick={() => handleSelectProfile(profile.id)}
className={cn(
'relative w-full rounded-lg border p-4 text-left transition-all duration-200',
'hover:border-primary/50 hover:shadow-sm',
isSelected
? 'border-primary bg-primary/5'
: 'border-border bg-card'
)}
>
{/* Selected indicator */}
{isSelected && (
<div className="absolute right-3 top-3 flex h-5 w-5 items-center justify-center rounded-full bg-primary">
<Check className="h-3 w-3 text-primary-foreground" />
</div>
)}
{/* Profile content */}
<div className="flex items-start gap-3">
<div
className={cn(
'flex h-10 w-10 items-center justify-center rounded-lg shrink-0',
isSelected ? 'bg-primary/10' : 'bg-muted'
)}
>
<Icon
className={cn(
'h-5 w-5',
isSelected ? 'text-primary' : 'text-muted-foreground'
)}
/>
</div>
<div className="flex-1 min-w-0 pr-6">
<h3 className="font-medium text-sm text-foreground">{profile.name}</h3>
<p className="mt-0.5 text-xs text-muted-foreground line-clamp-2">
{profile.description}
</p>
{/* Model and thinking level badges */}
<div className="mt-2 flex flex-wrap gap-1.5">
<span className="inline-flex items-center rounded bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
{getModelLabel(profile.model)}
</span>
<span className="inline-flex items-center rounded bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
{getThinkingLabel(profile.thinkingLevel)} Thinking
</span>
</div>
</div>
</div>
</button>
);
};
return (
<SettingsSection
title="Default Agent Profile"
description="Select a preset configuration for model and thinking level"
>
<div className="space-y-4">
{/* Description */}
<div className="rounded-lg bg-muted/50 p-3">
<p className="text-xs text-muted-foreground">
Agent profiles provide preset configurations for Claude model and thinking level.
When you create a new task, these settings will be used as defaults. You can always
override them in the task creation wizard.
</p>
</div>
{/* Profile cards - 2 column grid on larger screens */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
{DEFAULT_AGENT_PROFILES.map(renderProfileCard)}
</div>
</div>
</SettingsSection>
);
}
@@ -3,6 +3,7 @@ import { Input } from '../ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
import { Switch } from '../ui/switch';
import { SettingsSection } from './SettingsSection';
import { AgentProfileSettings } from './AgentProfileSettings';
import { AVAILABLE_MODELS } from '../../../shared/constants';
import type { AppSettings } from '../../../shared/types';
@@ -18,64 +19,51 @@ interface GeneralSettingsProps {
export function GeneralSettings({ settings, onSettingsChange, section }: GeneralSettingsProps) {
if (section === 'agent') {
return (
<SettingsSection
title="Default Agent Settings"
description="Configure defaults for new projects"
>
<div className="space-y-6">
<div className="space-y-3">
<Label htmlFor="defaultModel" className="text-sm font-medium text-foreground">Default Model</Label>
<p className="text-sm text-muted-foreground">The AI model used for agent tasks</p>
<Select
value={settings.defaultModel}
onValueChange={(value) => onSettingsChange({ ...settings, defaultModel: value })}
>
<SelectTrigger id="defaultModel" className="w-full max-w-md">
<SelectValue />
</SelectTrigger>
<SelectContent>
{AVAILABLE_MODELS.map((model) => (
<SelectItem key={model.value} value={model.value}>
{model.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-3">
<Label htmlFor="agentFramework" className="text-sm font-medium text-foreground">Agent Framework</Label>
<p className="text-sm text-muted-foreground">The coding framework used for autonomous tasks</p>
<Select
value={settings.agentFramework}
onValueChange={(value) => onSettingsChange({ ...settings, agentFramework: value })}
>
<SelectTrigger id="agentFramework" className="w-full max-w-md">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="auto-claude">Auto Claude</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-3">
<div className="flex items-center justify-between max-w-md">
<div className="space-y-1">
<Label htmlFor="autoNameTerminals" className="text-sm font-medium text-foreground">
AI Terminal Naming
</Label>
<p className="text-sm text-muted-foreground">
Automatically name terminals based on commands (uses Haiku)
</p>
<div className="space-y-8">
{/* Agent Profile Selection */}
<AgentProfileSettings />
{/* Other Agent Settings */}
<SettingsSection
title="Other Agent Settings"
description="Additional agent configuration options"
>
<div className="space-y-6">
<div className="space-y-3">
<Label htmlFor="agentFramework" className="text-sm font-medium text-foreground">Agent Framework</Label>
<p className="text-sm text-muted-foreground">The coding framework used for autonomous tasks</p>
<Select
value={settings.agentFramework}
onValueChange={(value) => onSettingsChange({ ...settings, agentFramework: value })}
>
<SelectTrigger id="agentFramework" className="w-full max-w-md">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="auto-claude">Auto Claude</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-3">
<div className="flex items-center justify-between max-w-md">
<div className="space-y-1">
<Label htmlFor="autoNameTerminals" className="text-sm font-medium text-foreground">
AI Terminal Naming
</Label>
<p className="text-sm text-muted-foreground">
Automatically name terminals based on commands (uses Haiku)
</p>
</div>
<Switch
id="autoNameTerminals"
checked={settings.autoNameTerminals}
onCheckedChange={(checked) => onSettingsChange({ ...settings, autoNameTerminals: checked })}
/>
</div>
<Switch
id="autoNameTerminals"
checked={settings.autoNameTerminals}
onCheckedChange={(checked) => onSettingsChange({ ...settings, autoNameTerminals: checked })}
/>
</div>
</div>
</div>
</SettingsSection>
</SettingsSection>
</div>
);
}