Add agent workflows & stuff
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useMutation } from 'convex/react';
|
||||
import { Bot } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import type { Doc } from '@spoon/backend/convex/_generated/dataModel.js';
|
||||
import { api } from '@spoon/backend/convex/_generated/api.js';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
Input,
|
||||
Label,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
Switch,
|
||||
} from '@spoon/ui';
|
||||
|
||||
const efforts = ['minimal', 'low', 'medium', 'high', 'xhigh'] as const;
|
||||
|
||||
type AgentSettings = {
|
||||
enabled: boolean;
|
||||
defaultBaseBranch?: string;
|
||||
branchPrefix: string;
|
||||
installCommand?: string;
|
||||
checkCommand?: string;
|
||||
testCommand?: string;
|
||||
agentModel: string;
|
||||
reasoningEffort: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
||||
};
|
||||
|
||||
export const SpoonAgentSettingsForm = ({
|
||||
spoon,
|
||||
settings,
|
||||
}: {
|
||||
spoon: Doc<'spoons'>;
|
||||
settings?: AgentSettings | null;
|
||||
}) => {
|
||||
const update = useMutation(api.spoonAgentSettings.update);
|
||||
const [enabled, setEnabled] = useState(settings?.enabled ?? true);
|
||||
const [defaultBaseBranch, setDefaultBaseBranch] = useState(
|
||||
settings?.defaultBaseBranch ??
|
||||
spoon.forkDefaultBranch ??
|
||||
spoon.upstreamDefaultBranch,
|
||||
);
|
||||
const [branchPrefix, setBranchPrefix] = useState(
|
||||
settings?.branchPrefix ?? 'spoon/agent',
|
||||
);
|
||||
const [installCommand, setInstallCommand] = useState(
|
||||
settings?.installCommand ?? '',
|
||||
);
|
||||
const [checkCommand, setCheckCommand] = useState(
|
||||
settings?.checkCommand ?? '',
|
||||
);
|
||||
const [testCommand, setTestCommand] = useState(settings?.testCommand ?? '');
|
||||
const [agentModel, setAgentModel] = useState(
|
||||
settings?.agentModel ?? 'gpt-5.1-codex',
|
||||
);
|
||||
const [reasoningEffort, setReasoningEffort] = useState<
|
||||
'minimal' | 'low' | 'medium' | 'high' | 'xhigh'
|
||||
>(
|
||||
settings?.reasoningEffort === 'none'
|
||||
? 'minimal'
|
||||
: (settings?.reasoningEffort ?? 'high'),
|
||||
);
|
||||
|
||||
const save = async () => {
|
||||
try {
|
||||
await update({
|
||||
spoonId: spoon._id,
|
||||
enabled,
|
||||
defaultBaseBranch,
|
||||
branchPrefix,
|
||||
installCommand: installCommand || undefined,
|
||||
checkCommand: checkCommand || undefined,
|
||||
testCommand: testCommand || undefined,
|
||||
agentModel,
|
||||
reasoningEffort,
|
||||
});
|
||||
toast.success('Agent settings saved.');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error('Could not save agent settings.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className='shadow-none'>
|
||||
<CardHeader>
|
||||
<CardTitle className='flex items-center gap-2 text-base'>
|
||||
<Bot className='size-4' />
|
||||
Agent runtime
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className='space-y-4'>
|
||||
<div className='flex items-center justify-between gap-4'>
|
||||
<Label htmlFor='agentEnabled'>Enable agent jobs</Label>
|
||||
<Switch
|
||||
id='agentEnabled'
|
||||
checked={enabled}
|
||||
onCheckedChange={setEnabled}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-3 md:grid-cols-2'>
|
||||
<div className='grid gap-2'>
|
||||
<Label htmlFor='defaultBaseBranch'>Default base branch</Label>
|
||||
<Input
|
||||
id='defaultBaseBranch'
|
||||
value={defaultBaseBranch}
|
||||
onChange={(event) => setDefaultBaseBranch(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-2'>
|
||||
<Label htmlFor='branchPrefix'>Branch prefix</Label>
|
||||
<Input
|
||||
id='branchPrefix'
|
||||
value={branchPrefix}
|
||||
onChange={(event) => setBranchPrefix(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-2'>
|
||||
<Label htmlFor='agentModel'>Model</Label>
|
||||
<Input
|
||||
id='agentModel'
|
||||
value={agentModel}
|
||||
onChange={(event) => setAgentModel(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-2'>
|
||||
<Label>Reasoning effort</Label>
|
||||
<Select
|
||||
value={reasoningEffort}
|
||||
onValueChange={(value) =>
|
||||
setReasoningEffort(
|
||||
value as 'minimal' | 'low' | 'medium' | 'high' | 'xhigh',
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{efforts.map((effort) => (
|
||||
<SelectItem key={effort} value={effort}>
|
||||
{effort}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className='grid gap-2'>
|
||||
<Label htmlFor='installCommand'>Install command</Label>
|
||||
<Input
|
||||
id='installCommand'
|
||||
value={installCommand}
|
||||
placeholder='bun install'
|
||||
onChange={(event) => setInstallCommand(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-2'>
|
||||
<Label htmlFor='checkCommand'>Check command</Label>
|
||||
<Input
|
||||
id='checkCommand'
|
||||
value={checkCommand}
|
||||
placeholder='bun typecheck'
|
||||
onChange={(event) => setCheckCommand(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-2'>
|
||||
<Label htmlFor='testCommand'>Test command</Label>
|
||||
<Input
|
||||
id='testCommand'
|
||||
value={testCommand}
|
||||
placeholder='bun test'
|
||||
onChange={(event) => setTestCommand(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Button type='button' onClick={save}>
|
||||
Save agent settings
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user