Files
kandev/apps/web/app/settings/agents/page.tsx
T
2026-01-12 20:56:03 +00:00

232 lines
8.4 KiB
TypeScript

'use client';
import { useState } from 'react';
import { IconPlus } from '@tabler/icons-react';
import { Button } from '@kandev/ui/button';
import { Input } from '@kandev/ui/input';
import { Label } from '@kandev/ui/label';
import { Card, CardContent } from '@kandev/ui/card';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@kandev/ui/select';
import { Separator } from '@kandev/ui/separator';
import { AgentCard } from '@/components/settings/agent-card';
import { SETTINGS_DATA } from '@/lib/settings/dummy-data';
import type { AgentProfile, AgentType } from '@/lib/settings/types';
import { generateUUID } from '@/lib/utils';
const AGENT_OPTIONS: { value: AgentType; label: string }[] = [
{ value: 'claude-code', label: 'Claude Code' },
{ value: 'codex', label: 'Codex' },
{ value: 'auggie', label: 'Auggie' },
];
const MODEL_OPTIONS: Record<AgentType, { value: string; label: string }[]> = {
'claude-code': [
{ value: 'claude-sonnet-4.5', label: 'Claude Sonnet 4.5' },
{ value: 'claude-opus-4', label: 'Claude Opus 4' },
{ value: 'claude-haiku-4', label: 'Claude Haiku 4' },
],
'codex': [
{ value: 'codex-v2', label: 'Codex v2' },
{ value: 'codex-v1', label: 'Codex v1' },
],
'auggie': [
{ value: 'auggie-v1', label: 'Auggie v1' },
{ value: 'auggie-lite', label: 'Auggie Lite' },
],
};
export default function AgentsSettingsPage() {
const [agents, setAgents] = useState<AgentProfile[]>(SETTINGS_DATA.agents);
const [isAdding, setIsAdding] = useState(false);
const [newAgent, setNewAgent] = useState<{
agent: AgentType;
name: string;
model: string;
autoApprove: boolean;
temperature: number;
}>({
agent: 'claude-code',
name: '',
model: 'claude-sonnet-4.5',
autoApprove: false,
temperature: 0.7,
});
const handleAdd = (e: React.FormEvent) => {
e.preventDefault();
const profile: AgentProfile = {
id: generateUUID(),
...newAgent,
};
setAgents([...agents, profile]);
setIsAdding(false);
setNewAgent({
agent: 'claude-code',
name: '',
model: 'claude-sonnet-4.5',
autoApprove: false,
temperature: 0.7,
});
};
const handleAgentTypeChange = (type: AgentType) => {
const defaultModel = MODEL_OPTIONS[type][0].value;
setNewAgent({ ...newAgent, agent: type, model: defaultModel });
};
return (
<div className="space-y-8">
<div className="flex items-start justify-between">
<div>
<h2 className="text-2xl font-bold">Agents</h2>
<p className="text-sm text-muted-foreground mt-1">
Configure agent profiles and their behavior
</p>
</div>
<Button size="sm" onClick={() => setIsAdding(true)}>
<IconPlus className="h-4 w-4 mr-2" />
Add Agent Profile
</Button>
</div>
<Separator />
<div className="space-y-4">
<div className="grid gap-3">
{isAdding && (
<Card>
<CardContent className="pt-6">
<form onSubmit={handleAdd} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="profile-name">Profile Name</Label>
<Input
id="profile-name"
value={newAgent.name}
onChange={(e) => setNewAgent({ ...newAgent, name: e.target.value })}
placeholder="My Profile"
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="agent-type">Agent Type</Label>
<Select
value={newAgent.agent}
onValueChange={(value) => handleAgentTypeChange(value as AgentType)}
>
<SelectTrigger id="agent-type">
<SelectValue />
</SelectTrigger>
<SelectContent>
{AGENT_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="model">Model</Label>
<Select
value={newAgent.model}
onValueChange={(value) => setNewAgent({ ...newAgent, model: value })}
>
<SelectTrigger id="model">
<SelectValue />
</SelectTrigger>
<SelectContent>
{MODEL_OPTIONS[newAgent.agent].map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="temperature">Temperature: {newAgent.temperature}</Label>
<input
id="temperature"
type="range"
min="0"
max="1"
step="0.1"
value={newAgent.temperature}
onChange={(e) =>
setNewAgent({ ...newAgent, temperature: parseFloat(e.target.value) })
}
className="w-full h-2 bg-muted rounded-lg appearance-none cursor-pointer"
/>
<div className="flex justify-between text-xs text-muted-foreground">
<span>Precise</span>
<span>Creative</span>
</div>
</div>
<div className="flex items-center justify-between p-4 border rounded-md">
<div>
<Label htmlFor="auto-approve" className="text-base font-medium">
Auto-approve all actions
</Label>
<p className="text-sm text-muted-foreground">
Automatically approve agent actions without prompting
</p>
</div>
<button
id="auto-approve"
type="button"
role="switch"
aria-checked={newAgent.autoApprove}
onClick={() =>
setNewAgent({ ...newAgent, autoApprove: !newAgent.autoApprove })
}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${
newAgent.autoApprove ? 'bg-primary' : 'bg-muted'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-background transition-transform ${
newAgent.autoApprove ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
<div className="flex gap-2 justify-end">
<Button type="button" variant="outline" onClick={() => setIsAdding(false)}>
Cancel
</Button>
<Button type="submit">Add Profile</Button>
</div>
</form>
</CardContent>
</Card>
)}
{agents.map((agent) => (
<AgentCard
key={agent.id}
agent={agent}
/>
))}
{agents.length === 0 && !isAdding && (
<Card>
<CardContent className="py-8 text-center">
<p className="text-sm text-muted-foreground">
No agent profiles configured. Add your first profile to get started.
</p>
</CardContent>
</Card>
)}
</div>
</div>
</div>
);
}