diff --git a/ui/src/adapters/claude-local/config-fields.tsx b/ui/src/adapters/claude-local/config-fields.tsx index 1e7804ba..603f0b71 100644 --- a/ui/src/adapters/claude-local/config-fields.tsx +++ b/ui/src/adapters/claude-local/config-fields.tsx @@ -10,7 +10,11 @@ import { const inputClass = "w-full rounded-md border border-border px-2.5 py-1.5 bg-transparent outline-none text-sm font-mono placeholder:text-muted-foreground/40"; -export function ClaudeLocalConfigFields({ +export function ClaudeLocalConfigFields(_props: AdapterConfigFieldsProps) { + return null; +} + +export function ClaudeLocalAdvancedFields({ isCreate, values, set, @@ -38,41 +42,27 @@ export function ClaudeLocalConfigFields({ : mark("adapterConfig", "dangerouslySkipPermissions", v) } /> - - {/* Max turns — only shown in advanced section context, rendered here for availability */} + + {isCreate ? ( + set!({ maxTurnsPerRun: Number(e.target.value) })} + /> + ) : ( + mark("adapterConfig", "maxTurnsPerRun", v || 80)} + immediate + className={inputClass} + /> + )} + ); } - -export function ClaudeLocalAdvancedFields({ - isCreate, - values, - set, - config, - eff, - mark, -}: AdapterConfigFieldsProps) { - return ( - - {isCreate ? ( - set!({ maxTurnsPerRun: Number(e.target.value) })} - /> - ) : ( - mark("adapterConfig", "maxTurnsPerRun", v || 80)} - immediate - className={inputClass} - /> - )} - - ); -} diff --git a/ui/src/components/AgentConfigForm.tsx b/ui/src/components/AgentConfigForm.tsx index 37d393a0..bc279ae9 100644 --- a/ui/src/components/AgentConfigForm.tsx +++ b/ui/src/components/AgentConfigForm.tsx @@ -370,7 +370,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) { value={eff("identity", "capabilities", props.agent.capabilities ?? "")} onChange={(v) => mark("identity", "capabilities", v || null)} placeholder="Describe what this agent can do..." - contentClassName="min-h-[120px]" + contentClassName="min-h-[44px] text-sm font-mono" imageUploadHandler={async (file) => { const asset = await uploadMarkdownImage.mutateAsync({ file, @@ -510,7 +510,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) { : mark("adapterConfig", "promptTemplate", v || undefined) } placeholder="You are agent {{ agent.name }}. Your role is {{ agent.role }}..." - contentClassName="min-h-[180px]" + contentClassName="min-h-[88px] text-sm font-mono" imageUploadHandler={async (file) => { const namespace = isCreate ? "agents/drafts/prompt-template" @@ -524,166 +524,166 @@ export function AgentConfigForm(props: AgentConfigFormProps) { {/* Adapter-specific fields */} - - {/* Advanced adapter section — collapsible in both modes */} - {isLocal && ( - setAdapterAdvancedOpen(!adapterAdvancedOpen)} - > -
- - - isCreate - ? set!({ command: v }) - : mark("adapterConfig", "command", v || undefined) - } - immediate - className={inputClass} - placeholder={adapterType === "codex_local" ? "codex" : "claude"} - /> - - - - isCreate - ? set!({ model: v }) - : mark("adapterConfig", "model", v || undefined) - } - open={modelOpen} - onOpenChange={setModelOpen} - /> - - - isCreate - ? set!({ thinkingEffort: v }) - : mark("adapterConfig", thinkingEffortKey, v || undefined) - } - open={thinkingEffortOpen} - onOpenChange={setThinkingEffortOpen} - /> - {adapterType === "codex_local" && - codexSearchEnabled && - currentThinkingEffort === "minimal" && ( -

- Codex may reject `minimal` thinking when search is enabled. -

- )} - - - isCreate - ? set!({ bootstrapPrompt: v }) - : mark("adapterConfig", "bootstrapPromptTemplate", v || undefined) - } - placeholder="Optional initial setup prompt for the first run" - contentClassName="min-h-[120px]" - imageUploadHandler={async (file) => { - const namespace = isCreate - ? "agents/drafts/bootstrap-prompt" - : `agents/${props.agent.id}/bootstrap-prompt`; - const asset = await uploadMarkdownImage.mutateAsync({ file, namespace }); - return asset.contentPath; - }} - /> - - {adapterType === "claude_local" && ( - - )} - - - - isCreate - ? set!({ extraArgs: v }) - : mark("adapterConfig", "extraArgs", v ? parseCommaArgs(v) : undefined) - } - immediate - className={inputClass} - placeholder="e.g. --verbose, --foo=bar" - /> - - - - ) - : ((eff("adapterConfig", "env", config.env ?? {}) as Record) - ) - } - secrets={availableSecrets} - onCreateSecret={async (name, value) => { - const created = await createSecret.mutateAsync({ name, value }); - return created; - }} - onChange={(env) => - isCreate - ? set!({ envBindings: env ?? {}, envVars: "" }) - : mark("adapterConfig", "env", env) - } - /> - - - {/* Edit-only: timeout + grace period */} - {!isCreate && ( - <> - - mark("adapterConfig", "timeoutSec", v)} - immediate - className={inputClass} - /> - - - mark("adapterConfig", "graceSec", v)} - immediate - className={inputClass} - /> - - - )} -
-
- )} + + {/* Advanced adapter section — collapsible in both modes */} + {isLocal && ( + setAdapterAdvancedOpen(!adapterAdvancedOpen)} + > +
+ + + isCreate + ? set!({ command: v }) + : mark("adapterConfig", "command", v || undefined) + } + immediate + className={inputClass} + placeholder={adapterType === "codex_local" ? "codex" : "claude"} + /> + + + + isCreate + ? set!({ model: v }) + : mark("adapterConfig", "model", v || undefined) + } + open={modelOpen} + onOpenChange={setModelOpen} + /> + + + isCreate + ? set!({ thinkingEffort: v }) + : mark("adapterConfig", thinkingEffortKey, v || undefined) + } + open={thinkingEffortOpen} + onOpenChange={setThinkingEffortOpen} + /> + {adapterType === "codex_local" && + codexSearchEnabled && + currentThinkingEffort === "minimal" && ( +

+ Codex may reject `minimal` thinking when search is enabled. +

+ )} + + + isCreate + ? set!({ bootstrapPrompt: v }) + : mark("adapterConfig", "bootstrapPromptTemplate", v || undefined) + } + placeholder="Optional initial setup prompt for the first run" + contentClassName="min-h-[44px] text-sm font-mono" + imageUploadHandler={async (file) => { + const namespace = isCreate + ? "agents/drafts/bootstrap-prompt" + : `agents/${props.agent.id}/bootstrap-prompt`; + const asset = await uploadMarkdownImage.mutateAsync({ file, namespace }); + return asset.contentPath; + }} + /> + + {adapterType === "claude_local" && ( + + )} + + + + isCreate + ? set!({ extraArgs: v }) + : mark("adapterConfig", "extraArgs", v ? parseCommaArgs(v) : undefined) + } + immediate + className={inputClass} + placeholder="e.g. --verbose, --foo=bar" + /> + + + + ) + : ((eff("adapterConfig", "env", config.env ?? {}) as Record) + ) + } + secrets={availableSecrets} + onCreateSecret={async (name, value) => { + const created = await createSecret.mutateAsync({ name, value }); + return created; + }} + onChange={(env) => + isCreate + ? set!({ envBindings: env ?? {}, envVars: "" }) + : mark("adapterConfig", "env", env) + } + /> + + + {/* Edit-only: timeout + grace period */} + {!isCreate && ( + <> + + mark("adapterConfig", "timeoutSec", v)} + immediate + className={inputClass} + /> + + + mark("adapterConfig", "graceSec", v)} + immediate + className={inputClass} + /> + + + )} +
+
+ )} {/* ---- Heartbeat Policy ---- */} @@ -757,6 +757,18 @@ export function AgentConfigForm(props: AgentConfigFormProps) { className={inputClass} /> + + mark("heartbeat", "maxConcurrentRuns", v)} + immediate + className={inputClass} + /> +