feat(web): per-thread/per-spoon runtime picker and Anthropic OAuth provider profile

This commit is contained in:
Gabriel Brown committed 2026-07-11 11:20:33 -04:00
1 parent 6ec2e51312
commit 702e53a4ba
4 files changed
+190 -36

No files matched your search

@@ -24,9 +24,17 @@ import {
} from '@spoon/ui';
const efforts = ['minimal', 'low', 'medium', 'high', 'xhigh'] as const;
type RuntimeName = 'codex' | 'opencode' | 'claude';
const runtimeLabels: Record<RuntimeName, string> = {
codex: 'Codex',
opencode: 'OpenCode',
claude: 'Claude',
};
type AgentSettings = {
enabled: boolean;
runtime?: 'opencode' | 'openai_direct';
runtime?: RuntimeName | 'openai_direct';
defaultBaseBranch?: string;
branchPrefix: string;
installCommand?: string;
@@ -91,6 +99,7 @@ export const SpoonAgentSettingsForm = ({
const [aiProviderProfileId, setAiProviderProfileId] = useState(
settings?.aiProviderProfileId ?? '__default',
);
const [runtime, setRuntime] = useState<RuntimeName | undefined>();
const selectedProfile = profiles.find(
(profile) =>
profile._id ===
@@ -118,6 +127,19 @@ export const SpoonAgentSettingsForm = ({
: settings.reasoningEffort,
);
const supportedRuntimes = (selectedProfile?.supportedRuntimes ??
[]) as RuntimeName[];
const settingsRuntime = settings?.runtime as RuntimeName | undefined;
const effectiveRuntime =
runtime && supportedRuntimes.includes(runtime)
? runtime
: settingsRuntime && supportedRuntimes.includes(settingsRuntime)
? settingsRuntime
: supportedRuntimes[0];
const runtimeValid = Boolean(
effectiveRuntime && supportedRuntimes.includes(effectiveRuntime),
);
const selectableModels = selectedModelProfile?.configured
? selectedModelProfile.models
: [];
@@ -135,7 +157,7 @@ export const SpoonAgentSettingsForm = ({
await update({
spoonId: spoon._id,
enabled,
runtime: 'opencode',
runtime: effectiveRuntime,
defaultBaseBranch,
branchPrefix,
installCommand: installCommand || undefined,
@@ -186,7 +208,25 @@ export const SpoonAgentSettingsForm = ({
<div className='grid gap-3 md:grid-cols-2'>
<div className='grid gap-2'>
<Label>Runtime</Label>
<Input value='OpenCode workspace' disabled />
<Select
value={effectiveRuntime ?? ''}
onValueChange={(value) => setRuntime(value as RuntimeName)}
disabled={!supportedRuntimes.length}
>
<SelectTrigger>
<SelectValue placeholder='Select a provider profile first' />
</SelectTrigger>
<SelectContent>
{supportedRuntimes.map((name) => (
<SelectItem key={name} value={name}>
{runtimeLabels[name]}
</SelectItem>
))}
</SelectContent>
</Select>
<p className='text-muted-foreground text-xs'>
Runtimes available for the selected provider profile.
</p>
</div>
<div className='grid gap-2'>
<Label>AI provider profile</Label>
@@ -400,6 +440,7 @@ export const SpoonAgentSettingsForm = ({
onClick={save}
disabled={
!selectedProfile?.configured ||
!runtimeValid ||
!selectableModels.some((model) => model.id === selectedAgentModel)
}
>