2026-03-10 20:58:18 -05:00
import { useState , useEffect , useRef , useMemo , useCallback } from "react" ;
2026-02-19 15:44:05 -06:00
import { useMutation , useQuery , useQueryClient } from "@tanstack/react-query" ;
2026-02-20 12:28:42 -06:00
import type {
Agent ,
AdapterEnvironmentTestResult ,
CompanySecret ,
EnvBinding ,
2026-03-03 08:45:26 -06:00
} from "@paperclipai/shared" ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
import type { AdapterModel } from "../api/agents" ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
import { agentsApi } from "../api/agents" ;
2026-02-19 15:44:05 -06:00
import { secretsApi } from "../api/secrets" ;
2026-02-20 12:28:42 -06:00
import { assetsApi } from "../api/assets" ;
2026-03-03 12:41:50 -06:00
import {
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX ,
DEFAULT_CODEX_LOCAL_MODEL ,
} from "@paperclipai/adapter-codex-local" ;
2026-03-05 06:31:22 -06:00
import { DEFAULT_CURSOR_LOCAL_MODEL } from "@paperclipai/adapter-cursor-local" ;
2026-03-08 16:43:34 +05:30
import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local" ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
import {
Popover ,
PopoverContent ,
PopoverTrigger ,
} from "@/components/ui/popover" ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
import { Button } from "@/components/ui/button" ;
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
import { FolderOpen , Heart , ChevronDown , X } from "lucide-react" ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
import { cn } from "../lib/utils" ;
2026-03-05 15:52:59 +01:00
import { extractModelName , extractProviderId } from "../lib/model-utils" ;
2026-02-19 15:44:05 -06:00
import { queryKeys } from "../lib/queryKeys" ;
import { useCompany } from "../context/CompanyContext" ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
import {
Field ,
ToggleField ,
ToggleWithNumber ,
CollapsibleSection ,
DraftInput ,
DraftNumberInput ,
help ,
adapterLabels ,
} from "./agent-config-primitives" ;
2026-02-26 16:33:48 -06:00
import { defaultCreateValues } from "./agent-config-defaults" ;
2026-02-18 13:53:03 -06:00
import { getUIAdapter } from "../adapters" ;
import { ClaudeLocalAdvancedFields } from "../adapters/claude-local/config-fields" ;
2026-02-20 12:28:42 -06:00
import { MarkdownEditor } from "./MarkdownEditor" ;
2026-03-02 16:08:59 -06:00
import { ChoosePathButton } from "./PathInstructionsModal" ;
2026-03-05 15:24:20 +01:00
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon" ;
2026-03-20 20:06:19 +00:00
import { ReportsToPicker } from "./ReportsToPicker" ;
2026-04-06 09:34:15 -05:00
import { EnvVarEditor } from "./EnvVarEditor" ;
2026-03-20 07:04:41 -05:00
import { shouldShowLegacyWorkingDirectoryField } from "../lib/legacy-agent-config" ;
2026-03-31 20:21:13 +01:00
import { listAdapterOptions , listVisibleAdapterTypes } from "../adapters/metadata" ;
import { getAdapterLabel } from "../adapters/adapter-display-registry" ;
import { useDisabledAdaptersSync } from "../adapters/use-disabled-adapters" ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
/* ---- Create mode values ---- */
2026-03-03 08:45:26 -06:00
// Canonical type lives in @paperclipai/adapter-utils; re-exported here
2026-02-18 14:23:16 -06:00
// so existing imports from this file keep working.
2026-03-03 08:45:26 -06:00
export type { CreateConfigValues } from "@paperclipai/adapter-utils" ;
import type { CreateConfigValues } from "@paperclipai/adapter-utils" ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
/* ---- Props ---- */
type AgentConfigFormProps = {
adapterModels? : AdapterModel [ ] ;
2026-02-18 13:02:23 -06:00
onDirtyChange ? : ( dirty : boolean ) = > void ;
onSaveActionChange ? : ( save : ( ( ) = > void ) | null ) = > void ;
onCancelActionChange ? : ( cancel : ( ( ) = > void ) | null ) = > void ;
hideInlineSave? : boolean ;
2026-03-16 15:41:06 -05:00
showAdapterTypeField? : boolean ;
showAdapterTestEnvironmentButton? : boolean ;
showCreateRunPolicySection? : boolean ;
hideInstructionsFile? : boolean ;
2026-03-17 10:32:50 -05:00
/** Hide the prompt template field from the Identity section (used when it's shown in a separate Prompts tab). */
hidePromptTemplate? : boolean ;
2026-02-23 14:41:21 -06:00
/** "cards" renders each section as heading + bordered card (for settings pages). Default: "inline" (border-b dividers). */
sectionLayout ? : "inline" | "cards" ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
} & (
| {
mode : "create" ;
values : CreateConfigValues ;
onChange : ( patch : Partial < CreateConfigValues > ) = > void ;
}
| {
mode : "edit" ;
agent : Agent ;
onSave : ( patch : Record < string , unknown > ) = > void ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
isSaving? : boolean ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
}
) ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
/* ---- Edit mode overlay (dirty tracking) ---- */
interface Overlay {
identity : Record < string , unknown > ;
adapterType? : string ;
adapterConfig : Record < string , unknown > ;
heartbeat : Record < string , unknown > ;
runtime : Record < string , unknown > ;
}
const emptyOverlay : Overlay = {
identity : { } ,
adapterConfig : { } ,
heartbeat : { } ,
runtime : { } ,
} ;
2026-03-03 09:36:49 -06:00
/** Stable empty object used as fallback for missing env config to avoid new-object-per-render. */
const EMPTY_ENV : Record < string , EnvBinding > = { } ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
function isOverlayDirty ( o : Overlay ) : boolean {
return (
Object . keys ( o . identity ) . length > 0 ||
o . adapterType !== undefined ||
Object . keys ( o . adapterConfig ) . length > 0 ||
Object . keys ( o . heartbeat ) . length > 0 ||
Object . keys ( o . runtime ) . length > 0
) ;
}
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
/* ---- Shared input class ---- */
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" ;
2026-02-18 13:02:23 -06:00
function parseCommaArgs ( value : string ) : string [ ] {
return value
. split ( "," )
. map ( ( item ) = > item . trim ( ) )
. filter ( Boolean ) ;
}
function formatArgList ( value : unknown ) : string {
if ( Array . isArray ( value ) ) {
return value
. filter ( ( item ) : item is string = > typeof item === "string" )
. join ( ", " ) ;
}
return typeof value === "string" ? value : "" ;
}
2026-02-20 10:32:32 -06:00
const codexThinkingEffortOptions = [
{ id : "" , label : "Auto" } ,
{ id : "minimal" , label : "Minimal" } ,
{ id : "low" , label : "Low" } ,
{ id : "medium" , label : "Medium" } ,
{ id : "high" , label : "High" } ,
2026-03-05 18:59:42 -06:00
{ id : "xhigh" , label : "X-High" } ,
2026-02-20 10:32:32 -06:00
] as const ;
2026-03-05 15:24:20 +01:00
const openCodeThinkingEffortOptions = [
2026-03-04 16:48:54 -06:00
{ id : "" , label : "Auto" } ,
{ id : "minimal" , label : "Minimal" } ,
{ id : "low" , label : "Low" } ,
{ id : "medium" , label : "Medium" } ,
{ id : "high" , label : "High" } ,
2026-03-05 18:59:42 -06:00
{ id : "xhigh" , label : "X-High" } ,
2026-03-04 16:48:54 -06:00
{ id : "max" , label : "Max" } ,
] as const ;
2026-03-05 06:31:22 -06:00
const cursorModeOptions = [
{ id : "" , label : "Auto" } ,
{ id : "plan" , label : "Plan" } ,
{ id : "ask" , label : "Ask" } ,
] as const ;
2026-02-20 10:32:32 -06:00
const claudeThinkingEffortOptions = [
{ id : "" , label : "Auto" } ,
{ id : "low" , label : "Low" } ,
{ id : "medium" , label : "Medium" } ,
{ id : "high" , label : "High" } ,
] as const ;
2026-02-18 13:02:23 -06:00
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
/* ---- Form ---- */
export function AgentConfigForm ( props : AgentConfigFormProps ) {
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
const { mode , adapterModels : externalModels } = props ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
const isCreate = mode === "create" ;
2026-02-23 14:41:21 -06:00
const cards = props . sectionLayout === "cards" ;
2026-03-16 15:41:06 -05:00
const showAdapterTypeField = props . showAdapterTypeField ? ? true ;
const showAdapterTestEnvironmentButton = props . showAdapterTestEnvironmentButton ? ? true ;
const showCreateRunPolicySection = props . showCreateRunPolicySection ? ? true ;
const hideInstructionsFile = props . hideInstructionsFile ? ? false ;
2026-02-19 15:44:05 -06:00
const { selectedCompanyId } = useCompany ( ) ;
const queryClient = useQueryClient ( ) ;
2026-03-31 20:21:13 +01:00
// Sync disabled adapter types from server so dropdown filters them out
const disabledTypes = useDisabledAdaptersSync ( ) ;
2026-02-19 15:44:05 -06:00
const { data : availableSecrets = [ ] } = useQuery ( {
queryKey : selectedCompanyId ? queryKeys . secrets . list ( selectedCompanyId ) : [ "secrets" , "none" ] ,
queryFn : ( ) = > secretsApi . list ( selectedCompanyId ! ) ,
enabled : Boolean ( selectedCompanyId ) ,
} ) ;
const createSecret = useMutation ( {
mutationFn : ( input : { name : string ; value : string } ) = > {
if ( ! selectedCompanyId ) throw new Error ( "Select a company to create secrets" ) ;
return secretsApi . create ( selectedCompanyId , input ) ;
} ,
onSuccess : ( ) = > {
if ( ! selectedCompanyId ) return ;
queryClient . invalidateQueries ( { queryKey : queryKeys.secrets.list ( selectedCompanyId ) } ) ;
} ,
} ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
2026-02-20 12:28:42 -06:00
const uploadMarkdownImage = useMutation ( {
mutationFn : async ( { file , namespace } : { file : File ; namespace : string } ) = > {
if ( ! selectedCompanyId ) throw new Error ( "Select a company to upload images" ) ;
return assetsApi . uploadImage ( selectedCompanyId , file , namespace ) ;
} ,
} ) ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
// ---- Edit mode: overlay for dirty tracking ----
const [ overlay , setOverlay ] = useState < Overlay > ( emptyOverlay ) ;
const agentRef = useRef < Agent | null > ( null ) ;
// Clear overlay when agent data refreshes (after save)
useEffect ( ( ) = > {
if ( ! isCreate ) {
if ( agentRef . current !== null && props . agent !== agentRef . current ) {
setOverlay ( { . . . emptyOverlay } ) ;
}
agentRef . current = props . agent ;
}
} , [ isCreate , ! isCreate ? props.agent : undefined ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
const isDirty = ! isCreate && isOverlayDirty ( overlay ) ;
/** Read effective value: overlay if dirty, else original */
function eff < T > ( group : keyof Omit < Overlay , "adapterType" > , field : string , original : T ) : T {
const o = overlay [ group ] ;
if ( field in o ) return o [ field ] as T ;
return original ;
}
/** Mark field dirty in overlay */
function mark ( group : keyof Omit < Overlay , "adapterType" > , field : string , value : unknown ) {
setOverlay ( ( prev ) = > ( {
. . . prev ,
[ group ] : { . . . prev [ group ] , [ field ] : value } ,
} ) ) ;
}
/** Build accumulated patch and send to parent */
2026-03-10 20:58:18 -05:00
const handleCancel = useCallback ( ( ) = > {
setOverlay ( { . . . emptyOverlay } ) ;
} , [ ] ) ;
const handleSave = useCallback ( ( ) = > {
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
if ( isCreate || ! isDirty ) return ;
const agent = props . agent ;
const patch : Record < string , unknown > = { } ;
if ( Object . keys ( overlay . identity ) . length > 0 ) {
Object . assign ( patch , overlay . identity ) ;
}
if ( overlay . adapterType !== undefined ) {
patch . adapterType = overlay . adapterType ;
2026-03-28 01:34:48 +01:00
// When adapter type changes, replace adapter-specific fields but preserve
// adapter-agnostic fields (env, promptTemplate, etc.) that are shared
// across all adapter types.
const existing = ( agent . adapterConfig ? ? { } ) as Record < string , unknown > ;
const adapterAgnosticKeys = [
"env" ,
"promptTemplate" ,
"instructionsFilePath" ,
"cwd" ,
"timeoutSec" ,
"graceSec" ,
"bootstrapPromptTemplate" ,
] ;
const preserved : Record < string , unknown > = { } ;
for ( const key of adapterAgnosticKeys ) {
if ( key in existing ) {
preserved [ key ] = existing [ key ] ;
}
}
patch . adapterConfig = { . . . preserved , . . . overlay . adapterConfig } ;
2026-02-26 16:33:48 -06:00
} else if ( Object . keys ( overlay . adapterConfig ) . length > 0 ) {
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
const existing = ( agent . adapterConfig ? ? { } ) as Record < string , unknown > ;
patch . adapterConfig = { . . . existing , . . . overlay . adapterConfig } ;
}
if ( Object . keys ( overlay . heartbeat ) . length > 0 ) {
const existingRc = ( agent . runtimeConfig ? ? { } ) as Record < string , unknown > ;
const existingHb = ( existingRc . heartbeat ? ? { } ) as Record < string , unknown > ;
patch . runtimeConfig = { . . . existingRc , heartbeat : { . . . existingHb , . . . overlay . heartbeat } } ;
}
if ( Object . keys ( overlay . runtime ) . length > 0 ) {
Object . assign ( patch , overlay . runtime ) ;
}
props . onSave ( patch ) ;
2026-03-10 20:58:18 -05:00
} , [ isCreate , isDirty , overlay , props ] ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
2026-02-18 13:02:23 -06:00
useEffect ( ( ) = > {
if ( ! isCreate ) {
props . onDirtyChange ? . ( isDirty ) ;
2026-03-10 20:58:18 -05:00
props . onSaveActionChange ? . ( handleSave ) ;
props . onCancelActionChange ? . ( handleCancel ) ;
2026-02-18 13:02:23 -06:00
}
2026-03-10 20:58:18 -05:00
} , [ isCreate , isDirty , props . onDirtyChange , props . onSaveActionChange , props . onCancelActionChange , handleSave , handleCancel ] ) ;
useEffect ( ( ) = > {
if ( isCreate ) return ;
return ( ) = > {
props . onSaveActionChange ? . ( null ) ;
props . onCancelActionChange ? . ( null ) ;
props . onDirtyChange ? . ( false ) ;
} ;
} , [ isCreate , props . onDirtyChange , props . onSaveActionChange , props . onCancelActionChange ] ) ;
2026-02-18 13:02:23 -06:00
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
// ---- Resolve values ----
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
const config = ! isCreate ? ( ( props . agent . adapterConfig ? ? { } ) as Record < string , unknown > ) : { } ;
const runtimeConfig = ! isCreate ? ( ( props . agent . runtimeConfig ? ? { } ) as Record < string , unknown > ) : { } ;
const heartbeat = ! isCreate ? ( ( runtimeConfig . heartbeat ? ? { } ) as Record < string , unknown > ) : { } ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
const adapterType = isCreate
? props . values . adapterType
: overlay . adapterType ? ? props . agent . adapterType ;
2026-03-31 20:21:13 +01:00
const NONLOCAL_TYPES = new Set ( [ "process" , "http" , "openclaw_gateway" ] ) ;
const isLocal = ! NONLOCAL_TYPES . has ( adapterType ) ;
2026-03-20 07:04:41 -05:00
const showLegacyWorkingDirectoryField =
isLocal && shouldShowLegacyWorkingDirectoryField ( { isCreate , adapterConfig : config } ) ;
2026-02-18 13:53:03 -06:00
const uiAdapter = useMemo ( ( ) = > getUIAdapter ( adapterType ) , [ adapterType ] ) ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
// Fetch adapter models for the effective adapter type
2026-03-05 15:24:20 +01:00
const {
data : fetchedModels ,
error : fetchedModelsError ,
} = useQuery ( {
queryKey : selectedCompanyId
? queryKeys . agents . adapterModels ( selectedCompanyId , adapterType )
: [ "agents" , "none" , "adapter-models" , adapterType ] ,
queryFn : ( ) = > agentsApi . adapterModels ( selectedCompanyId ! , adapterType ) ,
enabled : Boolean ( selectedCompanyId ) ,
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
} ) ;
const models = fetchedModels ? ? externalModels ? ? [ ] ;
2026-03-28 01:34:48 +01:00
const {
data : detectedModelData ,
refetch : refetchDetectedModel ,
} = useQuery ( {
queryKey : selectedCompanyId
? queryKeys . agents . detectModel ( selectedCompanyId , adapterType )
: [ "agents" , "none" , "detect-model" , adapterType ] ,
queryFn : ( ) = > {
if ( ! selectedCompanyId ) {
2026-03-31 20:21:13 +01:00
throw new Error ( "Select a company to detect the model" ) ;
2026-03-28 01:34:48 +01:00
}
return agentsApi . detectModel ( selectedCompanyId , adapterType ) ;
} ,
2026-03-31 20:21:13 +01:00
enabled : Boolean ( selectedCompanyId && isLocal ) ,
2026-03-28 01:34:48 +01:00
} ) ;
const detectedModel = detectedModelData ? . model ? ? null ;
2026-03-31 20:21:13 +01:00
const detectedModelCandidates = detectedModelData ? . candidates ? ? [ ] ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
2026-03-20 20:06:19 +00:00
const { data : companyAgents = [ ] } = useQuery ( {
queryKey : selectedCompanyId ? queryKeys . agents . list ( selectedCompanyId ) : [ "agents" , "none" , "list" ] ,
queryFn : ( ) = > agentsApi . list ( selectedCompanyId ! ) ,
enabled : Boolean ( ! isCreate && selectedCompanyId ) ,
} ) ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
2026-02-18 13:53:03 -06:00
/** Props passed to adapter-specific config field components */
const adapterFieldProps = {
mode ,
isCreate ,
adapterType ,
values : isCreate ? props.values : null ,
set : isCreate ? ( patch : Partial < CreateConfigValues > ) = > props . onChange ( patch ) : null ,
config ,
eff : eff as < T > ( group : "adapterConfig" , field : string , original : T ) = > T ,
mark : mark as ( group : "adapterConfig" , field : string , value : unknown ) = > void ,
models ,
2026-03-16 15:41:06 -05:00
hideInstructionsFile ,
2026-02-18 13:53:03 -06:00
} ;
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
// Section toggle state — advanced always starts collapsed
2026-02-20 14:11:30 -06:00
const [ runPolicyAdvancedOpen , setRunPolicyAdvancedOpen ] = useState ( false ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
// Popover states
const [ modelOpen , setModelOpen ] = useState ( false ) ;
2026-02-20 10:32:32 -06:00
const [ thinkingEffortOpen , setThinkingEffortOpen ] = useState ( false ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
// Create mode helpers
const val = isCreate ? props.values : null ;
const set = isCreate
? ( patch : Partial < CreateConfigValues > ) = > props . onChange ( patch )
: null ;
2026-02-20 12:28:42 -06:00
function buildAdapterConfigForTest ( ) : Record < string , unknown > {
if ( isCreate ) {
return uiAdapter . buildAdapterConfig ( val ! ) ;
}
const base = config as Record < string , unknown > ;
return { . . . base , . . . overlay . adapterConfig } ;
}
const testEnvironment = useMutation ( {
mutationFn : async ( ) = > {
if ( ! selectedCompanyId ) {
throw new Error ( "Select a company to test adapter environment" ) ;
}
return agentsApi . testEnvironment ( selectedCompanyId , adapterType , {
adapterConfig : buildAdapterConfigForTest ( ) ,
} ) ;
} ,
} ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
// Current model for display
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
const currentModelId = isCreate
? val ! . model
: eff ( "adapterConfig" , "model" , String ( config . model ? ? "" ) ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
2026-03-04 16:48:54 -06:00
const thinkingEffortKey =
adapterType === "codex_local"
? "modelReasoningEffort"
2026-03-05 06:31:22 -06:00
: adapterType === "cursor"
? "mode"
2026-03-06 15:23:55 +00:00
: adapterType === "opencode_local"
? "variant"
: "effort" ;
2026-02-20 10:32:32 -06:00
const thinkingEffortOptions =
2026-03-04 16:48:54 -06:00
adapterType === "codex_local"
? codexThinkingEffortOptions
2026-03-05 06:31:22 -06:00
: adapterType === "cursor"
? cursorModeOptions
2026-03-06 15:23:55 +00:00
: adapterType === "opencode_local"
? openCodeThinkingEffortOptions
: claudeThinkingEffortOptions ;
2026-02-20 10:32:32 -06:00
const currentThinkingEffort = isCreate
? val ! . thinkingEffort
: adapterType === "codex_local"
? eff (
"adapterConfig" ,
"modelReasoningEffort" ,
String ( config . modelReasoningEffort ? ? config . reasoningEffort ? ? "" ) ,
)
2026-03-05 06:31:22 -06:00
: adapterType === "cursor"
? eff ( "adapterConfig" , "mode" , String ( config . mode ? ? "" ) )
2026-03-08 16:43:34 +05:30
: adapterType === "opencode_local"
? eff ( "adapterConfig" , "variant" , String ( config . variant ? ? "" ) )
2026-02-20 10:32:32 -06:00
: eff ( "adapterConfig" , "effort" , String ( config . effort ? ? "" ) ) ;
2026-03-08 16:43:34 +05:30
const showThinkingEffort = adapterType !== "gemini_local" ;
2026-02-20 10:32:32 -06:00
const codexSearchEnabled = adapterType === "codex_local"
? ( isCreate ? Boolean ( val ! . search ) : eff ( "adapterConfig" , "search" , Boolean ( config . search ) ) )
: false ;
2026-03-16 19:35:11 -05:00
const effectiveRuntimeConfig = useMemo ( ( ) = > {
if ( isCreate ) {
return {
heartbeat : {
enabled : val ! . heartbeatEnabled ,
intervalSec : val ! . intervalSec ,
} ,
} ;
}
const mergedHeartbeat = {
. . . ( runtimeConfig . heartbeat && typeof runtimeConfig . heartbeat === "object"
? runtimeConfig . heartbeat as Record < string , unknown >
: { } ) ,
. . . overlay . heartbeat ,
} ;
return {
. . . runtimeConfig ,
heartbeat : mergedHeartbeat ,
} ;
} , [ isCreate , overlay . heartbeat , runtimeConfig , val ] ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
return (
2026-02-23 14:41:21 -06:00
< div className = { cn ( "relative" , cards && "space-y-6" ) } >
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
{ /* ---- Floating Save button (edit mode, when dirty) ---- */ }
2026-02-18 13:02:23 -06:00
{ isDirty && ! props . hideInlineSave && (
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
< div className = "sticky top-0 z-10 flex items-center justify-end px-4 py-2 bg-background/90 backdrop-blur-sm border-b border-primary/20" >
< div className = "flex items-center gap-3" >
< span className = "text-xs text-muted-foreground" > Unsaved changes < / span >
< Button
size = "sm"
onClick = { handleSave }
disabled = { ! isCreate && props . isSaving }
>
{ ! isCreate && props . isSaving ? "Saving..." : "Save" }
< / Button >
< / div >
< / div >
) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
{ /* ---- Identity (edit only) ---- */ }
{ ! isCreate && (
2026-02-23 14:41:21 -06:00
< div className = { cn ( ! cards && "border-b border-border" ) } >
{ cards
? < h3 className = "text-sm font-medium mb-3" > Identity < / h3 >
: < div className = "px-4 py-2 text-xs font-medium text-muted-foreground" > Identity < / div >
}
< div className = { cn ( cards ? "border border-border rounded-lg p-4 space-y-3" : "px-4 pb-3 space-y-3" ) } >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< Field label = "Name" hint = { help . name } >
< DraftInput
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
value = { eff ( "identity" , "name" , props . agent . name ) }
onCommit = { ( v ) = > mark ( "identity" , "name" , v ) }
2026-02-18 13:02:23 -06:00
immediate
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
className = { inputClass }
placeholder = "Agent name"
/ >
< / Field >
< Field label = "Title" hint = { help . title } >
< DraftInput
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
value = { eff ( "identity" , "title" , props . agent . title ? ? "" ) }
onCommit = { ( v ) = > mark ( "identity" , "title" , v || null ) }
2026-02-18 13:02:23 -06:00
immediate
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
className = { inputClass }
placeholder = "e.g. VP of Engineering"
/ >
< / Field >
2026-03-20 20:06:19 +00:00
< Field label = "Reports to" hint = { help . reportsTo } >
< ReportsToPicker
agents = { companyAgents }
value = { eff ( "identity" , "reportsTo" , props . agent . reportsTo ? ? null ) }
onChange = { ( id ) = > mark ( "identity" , "reportsTo" , id ) }
excludeAgentIds = { [ props . agent . id ] }
chooseLabel = "Choose manager…"
/ >
< / Field >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< Field label = "Capabilities" hint = { help . capabilities } >
2026-02-20 12:28:42 -06:00
< MarkdownEditor
2026-04-01 12:24:15 -05:00
value = { eff ( "identity" , "capabilities" , props . agent . capabilities ? ? "" ) ? ? "" }
2026-02-20 12:28:42 -06:00
onChange = { ( v ) = > mark ( "identity" , "capabilities" , v || null ) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
placeholder = "Describe what this agent can do..."
2026-02-20 12:50:36 -06:00
contentClassName = "min-h-[44px] text-sm font-mono"
2026-02-20 12:28:42 -06:00
imageUploadHandler = { async ( file ) = > {
const asset = await uploadMarkdownImage . mutateAsync ( {
file ,
namespace : ` agents/ ${ props . agent . id } /capabilities ` ,
} ) ;
return asset . contentPath ;
} }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
/ >
< / Field >
2026-03-17 10:32:50 -05:00
{ isLocal && ! props . hidePromptTemplate && (
2026-03-13 08:49:11 -05:00
< >
< Field label = "Prompt Template" hint = { help . promptTemplate } >
< MarkdownEditor
value = { eff (
"adapterConfig" ,
"promptTemplate" ,
String ( config . promptTemplate ? ? "" ) ,
) }
onChange = { ( v ) = > mark ( "adapterConfig" , "promptTemplate" , v ? ? "" ) }
placeholder = "You are agent {{ agent.name }}. Your role is {{ agent.role }}..."
contentClassName = "min-h-[88px] text-sm font-mono"
imageUploadHandler = { async ( file ) = > {
const namespace = ` agents/ ${ props . agent . id } /prompt-template ` ;
const asset = await uploadMarkdownImage . mutateAsync ( { file , namespace } ) ;
return asset . contentPath ;
} }
/ >
< / Field >
< div className = "rounded-md border border-amber-500/25 bg-amber-500/10 px-3 py-2 text-xs text-amber-100" >
Prompt template is replayed on every heartbeat . Keep it compact and dynamic to avoid recurring token cost and cache churn .
< / div >
< / >
2026-02-20 14:11:30 -06:00
) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / div >
< / div >
) }
2026-02-20 14:11:30 -06:00
{ /* ---- Adapter ---- */ }
2026-02-23 14:41:21 -06:00
< div className = { cn ( ! cards && ( isCreate ? "border-t border-border" : "border-b border-border" ) ) } >
< div className = { cn ( cards ? "flex items-center justify-between mb-3" : "px-4 py-2 flex items-center justify-between gap-2" ) } >
{ cards
? < h3 className = "text-sm font-medium" > Adapter < / h3 >
: < span className = "text-xs font-medium text-muted-foreground" > Adapter < / span >
}
2026-03-16 15:41:06 -05:00
{ showAdapterTestEnvironmentButton && (
< Button
type = "button"
variant = "outline"
size = "sm"
className = "h-7 px-2.5 text-xs"
onClick = { ( ) = > testEnvironment . mutate ( ) }
disabled = { testEnvironment . isPending || ! selectedCompanyId }
>
{ testEnvironment . isPending ? "Testing..." : "Test environment" }
< / Button >
) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / div >
2026-02-23 14:41:21 -06:00
< div className = { cn ( cards ? "border border-border rounded-lg p-4 space-y-3" : "px-4 pb-3 space-y-3" ) } >
2026-03-16 15:41:06 -05:00
{ showAdapterTypeField && (
< Field label = "Adapter type" hint = { help . adapterType } >
< AdapterTypeDropdown
value = { adapterType }
2026-03-31 20:21:13 +01:00
disabledTypes = { disabledTypes }
2026-03-16 15:41:06 -05:00
onChange = { ( t ) = > {
if ( isCreate ) {
// Reset all adapter-specific fields to defaults when switching adapter type
const { adapterType : _at , . . . defaults } = defaultCreateValues ;
const nextValues : CreateConfigValues = { . . . defaults , adapterType : t } ;
if ( t === "codex_local" ) {
nextValues . model = DEFAULT_CODEX_LOCAL_MODEL ;
nextValues . dangerouslyBypassSandbox =
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX ;
} else if ( t === "gemini_local" ) {
nextValues . model = DEFAULT_GEMINI_LOCAL_MODEL ;
} else if ( t === "cursor" ) {
nextValues . model = DEFAULT_CURSOR_LOCAL_MODEL ;
} else if ( t === "opencode_local" ) {
nextValues . model = "" ;
}
set ! ( nextValues ) ;
} else {
// Clear all adapter config and explicitly blank out model + effort/mode keys
// so the old adapter's values don't bleed through via eff()
setOverlay ( ( prev ) = > ( {
. . . prev ,
adapterType : t ,
adapterConfig : {
model :
t === "codex_local"
? DEFAULT_CODEX_LOCAL_MODEL
: t === "gemini_local"
? DEFAULT_GEMINI_LOCAL_MODEL
: t === "cursor"
? DEFAULT_CURSOR_LOCAL_MODEL
: "" ,
effort : "" ,
modelReasoningEffort : "" ,
variant : "" ,
mode : "" ,
. . . ( t === "codex_local"
? {
dangerouslyBypassApprovalsAndSandbox :
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX ,
}
: { } ) ,
} ,
} ) ) ;
2026-03-03 12:41:50 -06:00
}
2026-03-16 15:41:06 -05:00
} }
/ >
< / Field >
) }
2026-02-20 14:11:30 -06:00
2026-02-20 12:28:42 -06:00
{ testEnvironment . error && (
< div className = "rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive" >
{ testEnvironment . error instanceof Error
? testEnvironment . error . message
: "Environment test failed" }
< / div >
) }
{ testEnvironment . data && (
< AdapterEnvironmentResult result = { testEnvironment . data } / >
) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
{ /* Working directory */ }
2026-03-20 07:04:41 -05:00
{ showLegacyWorkingDirectoryField && (
< Field label = "Working directory (deprecated)" hint = { help . cwd } >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< div className = "flex items-center gap-2 rounded-md border border-border px-2.5 py-1.5" >
< FolderOpen className = "h-3.5 w-3.5 text-muted-foreground shrink-0" / >
< DraftInput
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
value = {
isCreate
? val ! . cwd
: eff ( "adapterConfig" , "cwd" , String ( config . cwd ? ? "" ) )
}
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
onCommit = { ( v ) = >
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
isCreate
? set ! ( { cwd : v } )
: mark ( "adapterConfig" , "cwd" , v || undefined )
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
}
2026-02-18 13:02:23 -06:00
immediate
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
className = "w-full bg-transparent outline-none text-sm font-mono placeholder:text-muted-foreground/40"
placeholder = "/path/to/project"
/ >
2026-03-02 16:08:59 -06:00
< ChoosePathButton / >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / div >
< / Field >
) }
2026-02-20 14:11:30 -06:00
{ /* Prompt template (create mode only — edit mode shows this in Identity) */ }
{ isLocal && isCreate && (
2026-03-13 08:49:11 -05:00
< >
< Field label = "Prompt Template" hint = { help . promptTemplate } >
< MarkdownEditor
value = { val ! . promptTemplate }
onChange = { ( v ) = > set ! ( { promptTemplate : v } ) }
placeholder = "You are agent {{ agent.name }}. Your role is {{ agent.role }}..."
contentClassName = "min-h-[88px] text-sm font-mono"
imageUploadHandler = { async ( file ) = > {
const namespace = "agents/drafts/prompt-template" ;
const asset = await uploadMarkdownImage . mutateAsync ( { file , namespace } ) ;
return asset . contentPath ;
} }
/ >
< / Field >
< div className = "rounded-md border border-amber-500/25 bg-amber-500/10 px-3 py-2 text-xs text-amber-100" >
Prompt template is replayed on every heartbeat . Prefer small task framing and variables like < code > { "{{ context.* }}" } < / code > or < code > { "{{ run.* }}" } < / code > ; avoid repeating stable instructions here .
< / div >
< / >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
) }
2026-04-01 21:56:19 +01:00
{ /* Adapter-specific fields are rendered inside Permissions & Configuration */ }
2026-02-20 12:50:36 -06:00
< / div >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
2026-02-20 14:16:21 -06:00
< / div >
{ /* ---- Permissions & Configuration ---- */ }
{ isLocal && (
2026-02-23 14:41:21 -06:00
< div className = { cn ( ! cards && "border-b border-border" ) } >
{ cards
? < h3 className = "text-sm font-medium mb-3" > Permissions & amp ; Configuration < / h3 >
: < div className = "px-4 py-2 text-xs font-medium text-muted-foreground" > Permissions & amp ; Configuration < / div >
}
< div className = { cn ( cards ? "border border-border rounded-lg p-4 space-y-3" : "px-4 pb-3 space-y-3" ) } >
2026-02-20 12:50:36 -06:00
< Field label = "Command" hint = { help . localCommand } >
< DraftInput
value = {
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
isCreate
2026-02-20 12:50:36 -06:00
? val ! . command
: eff ( "adapterConfig" , "command" , String ( config . command ? ? "" ) )
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
}
2026-02-20 12:50:36 -06:00
onCommit = { ( v ) = >
isCreate
? set ! ( { command : v } )
2026-03-31 20:21:13 +01:00
: mark ( "adapterConfig" , "command" , v || null )
2026-02-20 12:50:36 -06:00
}
immediate
className = { inputClass }
2026-03-04 16:48:54 -06:00
placeholder = {
2026-03-31 20:21:13 +01:00
( {
claude_local : "claude" ,
codex_local : "codex" ,
gemini_local : "gemini" ,
pi_local : "pi" ,
cursor : "agent" ,
opencode_local : "opencode" ,
} as Record < string , string > ) [ adapterType ] ? ? adapterType . replace ( /_local$/ , "" )
2026-03-04 16:48:54 -06:00
}
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
/ >
2026-02-20 12:50:36 -06:00
< / Field >
< ModelDropdown
models = { models }
value = { currentModelId }
onChange = { ( v ) = >
isCreate
? set ! ( { model : v } )
: mark ( "adapterConfig" , "model" , v || undefined )
}
open = { modelOpen }
onOpenChange = { setModelOpen }
2026-03-31 20:21:13 +01:00
allowDefault = { adapterType !== "opencode_local" }
required = { adapterType === "opencode_local" }
2026-03-05 15:24:20 +01:00
groupByProvider = { adapterType === "opencode_local" }
2026-03-31 20:21:13 +01:00
creatable
detectedModel = { detectedModel }
detectedModelCandidates = { [ ] }
onDetectModel = { async ( ) = > {
const result = await refetchDetectedModel ( ) ;
return result . data ? . model ? ? null ;
} }
detectModelLabel = "Detect model"
emptyDetectHint = "No model detected. Select or enter one manually."
2026-02-20 12:50:36 -06:00
/ >
2026-03-05 15:24:20 +01:00
{ fetchedModelsError && (
< p className = "text-xs text-destructive" >
{ fetchedModelsError instanceof Error
? fetchedModelsError . message
: "Failed to load adapter models." }
< / p >
) }
2026-02-20 10:32:32 -06:00
2026-03-08 16:43:34 +05:30
{ showThinkingEffort && (
< >
< ThinkingEffortDropdown
value = { currentThinkingEffort }
options = { thinkingEffortOptions }
onChange = { ( v ) = >
isCreate
? set ! ( { thinkingEffort : v } )
: mark ( "adapterConfig" , thinkingEffortKey , v || undefined )
}
open = { thinkingEffortOpen }
onOpenChange = { setThinkingEffortOpen }
/ >
{ adapterType === "codex_local" &&
codexSearchEnabled &&
currentThinkingEffort === "minimal" && (
< p className = "text-xs text-amber-400" >
Codex may reject ` minimal ` thinking when search is enabled .
< / p >
) }
< / >
) }
2026-03-18 06:37:24 -05:00
{ ! isCreate && typeof config . bootstrapPromptTemplate === "string" && config . bootstrapPromptTemplate && (
< >
< Field label = "Bootstrap prompt (legacy)" hint = { help . bootstrapPrompt } >
< MarkdownEditor
value = { eff (
"adapterConfig" ,
"bootstrapPromptTemplate" ,
String ( config . bootstrapPromptTemplate ? ? "" ) ,
) }
onChange = { ( 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 = ` agents/ ${ props . agent . id } /bootstrap-prompt ` ;
const asset = await uploadMarkdownImage . mutateAsync ( { file , namespace } ) ;
return asset . contentPath ;
} }
/ >
< / Field >
< div className = "rounded-md border border-amber-500/25 bg-amber-500/10 px-3 py-2 text-xs text-amber-200" >
Bootstrap prompt is legacy and will be removed in a future release . Consider moving this content into the agent & apos ; s prompt template or instructions file instead .
< / div >
< / >
) }
2026-02-20 12:50:36 -06:00
{ adapterType === "claude_local" && (
< ClaudeLocalAdvancedFields { ...adapterFieldProps } / >
) }
2026-04-01 21:56:19 +01:00
< uiAdapter.ConfigFields { ...adapterFieldProps } / >
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
2026-02-20 12:50:36 -06:00
< Field label = "Extra args (comma-separated)" hint = { help . extraArgs } >
< DraftInput
value = {
isCreate
? val ! . extraArgs
: eff ( "adapterConfig" , "extraArgs" , formatArgList ( config . extraArgs ) )
}
onCommit = { ( v ) = >
isCreate
? set ! ( { extraArgs : v } )
2026-04-03 23:15:10 +09:00
: mark ( "adapterConfig" , "extraArgs" , v ? . trim ( ) ? parseCommaArgs ( v ) : null )
2026-02-20 12:50:36 -06:00
}
immediate
className = { inputClass }
placeholder = "e.g. --verbose, --foo=bar"
/ >
< / Field >
< Field label = "Environment variables" hint = { help . envVars } >
< EnvVarEditor
value = {
isCreate
2026-03-03 09:36:49 -06:00
? ( ( val ! . envBindings ? ? EMPTY_ENV ) as Record < string , EnvBinding > )
: ( ( eff ( "adapterConfig" , "env" , ( config . env ? ? EMPTY_ENV ) as Record < string , EnvBinding > ) )
2026-02-20 12:50:36 -06:00
)
}
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 )
}
/ >
< / Field >
{ /* Edit-only: timeout + grace period */ }
{ ! isCreate && (
< >
< Field label = "Timeout (sec)" hint = { help . timeoutSec } >
< DraftNumberInput
value = { eff (
"adapterConfig" ,
"timeoutSec" ,
Number ( config . timeoutSec ? ? 0 ) ,
) }
onCommit = { ( v ) = > mark ( "adapterConfig" , "timeoutSec" , v ) }
immediate
className = { inputClass }
/ >
< / Field >
< Field label = "Interrupt grace period (sec)" hint = { help . graceSec } >
< DraftNumberInput
value = { eff (
"adapterConfig" ,
"graceSec" ,
Number ( config . graceSec ? ? 15 ) ,
) }
onCommit = { ( v ) = > mark ( "adapterConfig" , "graceSec" , v ) }
immediate
className = { inputClass }
/ >
< / Field >
< / >
) }
2026-02-20 14:16:21 -06:00
< / div >
< / div >
) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
2026-02-20 14:11:30 -06:00
{ /* ---- Run Policy ---- */ }
2026-03-16 15:41:06 -05:00
{ isCreate && showCreateRunPolicySection ? (
2026-02-23 14:41:21 -06:00
< div className = { cn ( ! cards && "border-b border-border" ) } >
{ cards
? < h3 className = "text-sm font-medium flex items-center gap-2 mb-3" > < Heart className = "h-3 w-3" / > Run Policy < / h3 >
: < div className = "px-4 py-2 text-xs font-medium text-muted-foreground flex items-center gap-2" > < Heart className = "h-3 w-3" / > Run Policy < / div >
}
< div className = { cn ( cards ? "border border-border rounded-lg p-4 space-y-3" : "px-4 pb-3 space-y-3" ) } >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< ToggleWithNumber
label = "Heartbeat on interval"
hint = { help . heartbeatInterval }
checked = { val ! . heartbeatEnabled }
onCheckedChange = { ( v ) = > set ! ( { heartbeatEnabled : v } ) }
number = { val ! . intervalSec }
onNumberChange = { ( v ) = > set ! ( { intervalSec : v } ) }
numberLabel = "sec"
numberPrefix = "Run heartbeat every"
numberHint = { help . intervalSec }
showNumber = { val ! . heartbeatEnabled }
/ >
< / div >
2026-02-20 14:16:21 -06:00
< / div >
2026-03-16 15:41:06 -05:00
) : ! isCreate ? (
2026-02-23 14:41:21 -06:00
< div className = { cn ( ! cards && "border-b border-border" ) } >
{ cards
? < h3 className = "text-sm font-medium flex items-center gap-2 mb-3" > < Heart className = "h-3 w-3" / > Run Policy < / h3 >
: < div className = "px-4 py-2 text-xs font-medium text-muted-foreground flex items-center gap-2" > < Heart className = "h-3 w-3" / > Run Policy < / div >
}
< div className = { cn ( cards ? "border border-border rounded-lg overflow-hidden" : "" ) } >
< div className = { cn ( cards ? "p-4 space-y-3" : "px-4 pb-3 space-y-3" ) } >
< ToggleWithNumber
label = "Heartbeat on interval"
hint = { help . heartbeatInterval }
2026-04-08 07:26:34 -05:00
checked = { eff ( "heartbeat" , "enabled" , heartbeat . enabled === true ) }
2026-02-23 14:41:21 -06:00
onCheckedChange = { ( v ) = > mark ( "heartbeat" , "enabled" , v ) }
number = { eff ( "heartbeat" , "intervalSec" , Number ( heartbeat . intervalSec ? ? 300 ) ) }
onNumberChange = { ( v ) = > mark ( "heartbeat" , "intervalSec" , v ) }
numberLabel = "sec"
numberPrefix = "Run heartbeat every"
numberHint = { help . intervalSec }
2026-04-08 07:26:34 -05:00
showNumber = { eff ( "heartbeat" , "enabled" , heartbeat . enabled === true ) }
2026-02-23 14:41:21 -06:00
/ >
< / div >
< CollapsibleSection
title = "Advanced Run Policy"
bordered = { cards }
open = { runPolicyAdvancedOpen }
onToggle = { ( ) = > setRunPolicyAdvancedOpen ( ! runPolicyAdvancedOpen ) }
>
2026-02-20 14:11:30 -06:00
< div className = "space-y-3" >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< ToggleField
2026-02-18 16:46:29 -06:00
label = "Wake on demand"
hint = { help . wakeOnDemand }
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
checked = { eff (
"heartbeat" ,
2026-02-18 16:46:29 -06:00
"wakeOnDemand" ,
heartbeat . wakeOnDemand !== false ,
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
) }
2026-02-18 16:46:29 -06:00
onChange = { ( v ) = > mark ( "heartbeat" , "wakeOnDemand" , v ) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
/ >
< Field label = "Cooldown (sec)" hint = { help . cooldownSec } >
< DraftNumberInput
Polish UI components and rework AgentConfigForm
Major AgentConfigForm rework with improved adapter configuration
fields and layout. Refine sidebar, breadcrumbs, and card/tab
components for visual consistency. Clean up page layouts across
Activity, Agents, Approvals, Costs, Dashboard, Goals, Inbox,
Issues, Org, and Projects pages. Minor heartbeat-run CLI fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 10:43:25 -06:00
value = { eff (
"heartbeat" ,
"cooldownSec" ,
Number ( heartbeat . cooldownSec ? ? 10 ) ,
) }
onCommit = { ( v ) = > mark ( "heartbeat" , "cooldownSec" , v ) }
2026-02-18 13:02:23 -06:00
immediate
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
className = { inputClass }
/ >
< / Field >
2026-02-20 12:50:36 -06:00
< Field label = "Max concurrent runs" hint = { help . maxConcurrentRuns } >
< DraftNumberInput
value = { eff (
"heartbeat" ,
"maxConcurrentRuns" ,
Number ( heartbeat . maxConcurrentRuns ? ? 1 ) ,
) }
onCommit = { ( v ) = > mark ( "heartbeat" , "maxConcurrentRuns" , v ) }
immediate
className = { inputClass }
/ >
< / Field >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / div >
2026-02-20 14:11:30 -06:00
< / CollapsibleSection >
2026-02-23 14:41:21 -06:00
< / div >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / div >
2026-03-16 15:41:06 -05:00
) : null }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / div >
) ;
}
2026-02-20 12:28:42 -06:00
function AdapterEnvironmentResult ( { result } : { result : AdapterEnvironmentTestResult } ) {
const statusLabel =
result . status === "pass" ? "Passed" : result . status === "warn" ? "Warnings" : "Failed" ;
const statusClass =
result . status === "pass"
2026-02-26 16:33:48 -06:00
? "text-green-700 dark:text-green-300 border-green-300 dark:border-green-500/40 bg-green-50 dark:bg-green-500/10"
2026-02-20 12:28:42 -06:00
: result . status === "warn"
2026-02-26 16:33:48 -06:00
? "text-amber-700 dark:text-amber-300 border-amber-300 dark:border-amber-500/40 bg-amber-50 dark:bg-amber-500/10"
: "text-red-700 dark:text-red-300 border-red-300 dark:border-red-500/40 bg-red-50 dark:bg-red-500/10" ;
2026-02-20 12:28:42 -06:00
return (
< div className = { ` rounded-md border px-3 py-2 text-xs ${ statusClass } ` } >
< div className = "flex items-center justify-between gap-2" >
< span className = "font-medium" > { statusLabel } < / span >
< span className = "text-[11px] opacity-80" >
{ new Date ( result . testedAt ) . toLocaleTimeString ( ) }
< / span >
< / div >
< div className = "mt-2 space-y-1.5" >
{ result . checks . map ( ( check , idx ) = > (
2026-03-03 13:02:08 -06:00
< div key = { ` ${ check . code } - ${ idx } ` } className = "text-[11px] leading-relaxed break-words" >
2026-02-20 12:28:42 -06:00
< span className = "font-medium uppercase tracking-wide opacity-80" >
{ check . level }
< / span >
< span className = "mx-1 opacity-60" > · < / span >
< span > { check . message } < / span >
2026-03-03 13:02:08 -06:00
{ check . detail && < span className = "block opacity-75 break-all" > ( { check . detail } ) < / span > }
{ check . hint && < span className = "block opacity-90 break-words" > Hint : { check . hint } < / span > }
2026-02-20 12:28:42 -06:00
< / div >
) ) }
< / div >
< / div >
) ;
}
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
/* ---- Internal sub-components ---- */
function AdapterTypeDropdown ( {
value ,
onChange ,
2026-03-31 20:21:13 +01:00
disabledTypes ,
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
} : {
value : string ;
onChange : ( type : string ) = > void ;
2026-03-31 20:21:13 +01:00
disabledTypes : Set < string > ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
} ) {
2026-03-31 20:21:13 +01:00
const [ open , setOpen ] = useState ( false ) ;
const adapterList = useMemo (
( ) = >
listAdapterOptions ( ( type ) = > adapterLabels [ type ] ? ? getAdapterLabel ( type ) ) . filter (
( item ) = > ! disabledTypes . has ( item . value ) ,
) ,
[ disabledTypes ] ,
) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
return (
2026-03-31 20:21:13 +01:00
< Popover open = { open } onOpenChange = { setOpen } >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< PopoverTrigger asChild >
< button className = "inline-flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-sm hover:bg-accent/50 transition-colors w-full justify-between" >
2026-03-05 15:24:20 +01:00
< span className = "inline-flex items-center gap-1.5" >
{ value === "opencode_local" ? < OpenCodeLogoIcon className = "h-3.5 w-3.5" / > : null }
2026-03-31 20:21:13 +01:00
< span > { adapterLabels [ value ] ? ? getAdapterLabel ( value ) } < / span >
2026-03-05 15:24:20 +01:00
< / span >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< ChevronDown className = "h-3 w-3 text-muted-foreground" / >
< / button >
< / PopoverTrigger >
< PopoverContent className = "w-[var(--radix-popover-trigger-width)] p-1" align = "start" >
2026-03-31 20:21:13 +01:00
{ adapterList . map ( ( item ) = > (
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< button
2026-03-03 11:29:34 -06:00
key = { item . value }
disabled = { item . comingSoon }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
className = { cn (
2026-03-03 11:29:34 -06:00
"flex items-center justify-between w-full px-2 py-1.5 text-sm rounded" ,
item . comingSoon
? "opacity-40 cursor-not-allowed"
: "hover:bg-accent/50" ,
item . value === value && ! item . comingSoon && "bg-accent" ,
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
) }
2026-03-03 11:29:34 -06:00
onClick = { ( ) = > {
2026-03-31 20:21:13 +01:00
if ( ! item . comingSoon ) {
onChange ( item . value ) ;
setOpen ( false ) ;
}
2026-03-03 11:29:34 -06:00
} }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
>
2026-03-05 15:24:20 +01:00
< span className = "inline-flex items-center gap-1.5" >
{ item . value === "opencode_local" ? < OpenCodeLogoIcon className = "h-3.5 w-3.5" / > : null }
< span > { item . label } < / span >
< / span >
2026-03-03 11:29:34 -06:00
{ item . comingSoon && (
< span className = "text-[10px] text-muted-foreground" > Coming soon < / span >
) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / button >
) ) }
< / PopoverContent >
< / Popover >
) ;
}
function ModelDropdown ( {
models ,
value ,
onChange ,
open ,
onOpenChange ,
2026-03-05 15:24:20 +01:00
allowDefault ,
required ,
groupByProvider ,
2026-03-28 01:34:48 +01:00
creatable ,
detectedModel ,
2026-03-31 20:21:13 +01:00
detectedModelCandidates ,
2026-03-28 01:34:48 +01:00
onDetectModel ,
2026-03-28 11:35:58 +01:00
detectModelLabel ,
2026-03-31 20:21:13 +01:00
emptyDetectHint ,
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
} : {
models : AdapterModel [ ] ;
value : string ;
onChange : ( id : string ) = > void ;
open : boolean ;
onOpenChange : ( open : boolean ) = > void ;
2026-03-05 15:24:20 +01:00
allowDefault : boolean ;
required : boolean ;
groupByProvider : boolean ;
2026-03-28 01:34:48 +01:00
creatable? : boolean ;
detectedModel? : string | null ;
2026-03-31 20:21:13 +01:00
detectedModelCandidates? : string [ ] ;
2026-03-28 01:34:48 +01:00
onDetectModel ? : ( ) = > Promise < string | null > ;
2026-03-28 11:35:58 +01:00
detectModelLabel? : string ;
2026-03-31 20:21:13 +01:00
emptyDetectHint? : string ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
} ) {
2026-02-20 10:32:32 -06:00
const [ modelSearch , setModelSearch ] = useState ( "" ) ;
2026-03-28 01:34:48 +01:00
const [ detectingModel , setDetectingModel ] = useState ( false ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
const selected = models . find ( ( m ) = > m . id === value ) ;
2026-03-28 01:34:48 +01:00
const manualModel = modelSearch . trim ( ) ;
const canCreateManualModel = Boolean (
creatable &&
manualModel &&
! models . some ( ( m ) = > m . id . toLowerCase ( ) === manualModel . toLowerCase ( ) ) ,
) ;
2026-03-31 20:21:13 +01:00
// Model IDs already shown as detected/candidate badges — exclude from regular list
const promotedModelIds = useMemo ( ( ) = > {
const set = new Set < string > ( ) ;
if ( detectedModel ) set . add ( detectedModel ) ;
for ( const c of detectedModelCandidates ? ? [ ] ) {
if ( c ) set . add ( c ) ;
}
return set ;
} , [ detectedModel , detectedModelCandidates ] ) ;
2026-03-05 15:24:20 +01:00
const filteredModels = useMemo ( ( ) = > {
return models . filter ( ( m ) = > {
2026-03-31 20:21:13 +01:00
if ( promotedModelIds . has ( m . id ) ) return false ;
2026-03-05 15:24:20 +01:00
if ( ! modelSearch . trim ( ) ) return true ;
const q = modelSearch . toLowerCase ( ) ;
const provider = extractProviderId ( m . id ) ? ? "" ;
return (
m . id . toLowerCase ( ) . includes ( q ) ||
m . label . toLowerCase ( ) . includes ( q ) ||
provider . toLowerCase ( ) . includes ( q )
) ;
} ) ;
2026-03-31 20:21:13 +01:00
} , [ models , modelSearch , promotedModelIds ] ) ;
2026-03-05 15:24:20 +01:00
const groupedModels = useMemo ( ( ) = > {
if ( ! groupByProvider ) {
return [
{
provider : "models" ,
entries : [ . . . filteredModels ] . sort ( ( a , b ) = > a . id . localeCompare ( b . id ) ) ,
} ,
] ;
}
const map = new Map < string , AdapterModel [ ] > ( ) ;
for ( const model of filteredModels ) {
const provider = extractProviderId ( model . id ) ? ? "other" ;
const group = map . get ( provider ) ? ? [ ] ;
group . push ( model ) ;
map . set ( provider , group ) ;
}
return Array . from ( map . entries ( ) )
. sort ( ( [ a ] , [ b ] ) = > a . localeCompare ( b ) )
. map ( ( [ provider , entries ] ) = > ( {
provider ,
entries : [ . . . entries ] . sort ( ( a , b ) = > a . id . localeCompare ( b . id ) ) ,
} ) ) ;
} , [ filteredModels , groupByProvider ] ) ;
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
2026-03-28 01:34:48 +01:00
async function handleDetectModel() {
if ( ! onDetectModel ) return ;
setDetectingModel ( true ) ;
try {
const nextModel = await onDetectModel ( ) ;
if ( nextModel ) {
onChange ( nextModel ) ;
onOpenChange ( false ) ;
setModelSearch ( "" ) ;
}
} finally {
setDetectingModel ( false ) ;
}
}
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
return (
< Field label = "Model" hint = { help . model } >
2026-02-20 10:32:32 -06:00
< Popover
open = { open }
onOpenChange = { ( nextOpen ) = > {
onOpenChange ( nextOpen ) ;
if ( ! nextOpen ) setModelSearch ( "" ) ;
} }
>
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< PopoverTrigger asChild >
2026-03-28 01:34:48 +01:00
< button type = "button" className = "inline-flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-sm hover:bg-accent/50 transition-colors w-full justify-between" >
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< span className = { cn ( ! value && "text-muted-foreground" ) } >
2026-03-05 15:24:20 +01:00
{ selected
? selected . label
: value || ( allowDefault ? "Default" : required ? "Select model (required)" : "Select model" ) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / span >
< ChevronDown className = "h-3 w-3 text-muted-foreground" / >
< / button >
< / PopoverTrigger >
< PopoverContent className = "w-[var(--radix-popover-trigger-width)] p-1" align = "start" >
2026-03-28 01:34:48 +01:00
< div className = "relative mb-1" >
< input
className = "w-full px-2 py-1.5 pr-6 text-xs bg-transparent outline-none border-b border-border placeholder:text-muted-foreground/50"
placeholder = { creatable ? "Search models... (type to create)" : "Search models..." }
value = { modelSearch }
onChange = { ( e ) = > setModelSearch ( e . target . value ) }
2026-03-28 11:35:58 +01:00
autoFocus
2026-03-28 01:34:48 +01:00
/ >
{ modelSearch && (
< button
type = "button"
className = "absolute right-1.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
onClick = { ( ) = > setModelSearch ( "" ) }
>
< svg aria-hidden = "true" focusable = "false" className = "h-3 w-3" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" >
< line x1 = "18" y1 = "6" x2 = "6" y2 = "18" / >
< line x1 = "6" y1 = "6" x2 = "18" y2 = "18" / >
< / svg >
< / button >
) }
< / div >
2026-03-31 20:21:13 +01:00
{ onDetectModel && ! modelSearch . trim ( ) && (
2026-03-28 01:34:48 +01:00
< button
type = "button"
className = "flex items-center gap-1.5 w-full px-2 py-1.5 text-xs rounded hover:bg-accent/50 text-muted-foreground"
onClick = { ( ) = > {
void handleDetectModel ( ) ;
} }
disabled = { detectingModel }
>
< svg aria-hidden = "true" focusable = "false" className = "h-3 w-3" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" >
< path d = "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" / >
< path d = "M3 3v5h5" / >
< / svg >
2026-03-31 20:21:13 +01:00
{ detectingModel ? "Detecting..." : detectedModel ? ( detectModelLabel ? . replace ( /^Detect\b/ , "Re-detect" ) ? ? "Re-detect from config" ) : ( detectModelLabel ? ? "Detect from config" ) }
2026-03-28 01:34:48 +01:00
< / button >
) }
2026-03-31 20:21:13 +01:00
{ value && ( ! models . some ( ( m ) = > m . id === value ) || promotedModelIds . has ( value ) ) && (
2026-03-28 01:34:48 +01:00
< button
type = "button"
className = { cn (
"flex items-center w-full px-2 py-1.5 text-sm rounded bg-accent/50" ,
) }
onClick = { ( ) = > {
onOpenChange ( false ) ;
} }
>
< span className = "block w-full text-left truncate font-mono text-xs" title = { value } >
2026-03-31 20:21:13 +01:00
{ models . find ( ( m ) = > m . id === value ) ? . label ? ? value }
2026-03-28 01:34:48 +01:00
< / span >
< span className = "shrink-0 ml-auto text-[9px] font-medium px-1.5 py-0.5 rounded-full bg-green-500/15 text-green-400 border border-green-500/20" >
current
< / span >
< / button >
) }
{ detectedModel && detectedModel !== value && (
< button
type = "button"
className = { cn (
"flex items-center w-full px-2 py-1.5 text-sm rounded hover:bg-accent/50" ,
) }
onClick = { ( ) = > {
onChange ( detectedModel ) ;
onOpenChange ( false ) ;
} }
>
< span className = "block w-full text-left truncate font-mono text-xs" title = { detectedModel } >
2026-03-31 20:21:13 +01:00
{ models . find ( ( m ) = > m . id === detectedModel ) ? . label ? ? detectedModel }
2026-03-28 01:34:48 +01:00
< / span >
< span className = "shrink-0 ml-auto text-[9px] font-medium px-1.5 py-0.5 rounded-full bg-blue-500/15 text-blue-400 border border-blue-500/20" >
detected
< / span >
< / button >
) }
2026-03-31 20:21:13 +01:00
{ detectedModelCandidates
? . filter ( ( candidate ) = > candidate && candidate !== detectedModel && candidate !== value )
. map ( ( candidate ) = > {
const entry = models . find ( ( m ) = > m . id === candidate ) ;
return (
< button
key = { ` detected- ${ candidate } ` }
type = "button"
className = { cn (
"flex items-center w-full px-2 py-1.5 text-sm rounded hover:bg-accent/50" ,
) }
onClick = { ( ) = > {
onChange ( candidate ) ;
onOpenChange ( false ) ;
} }
>
< span className = "block w-full text-left truncate font-mono text-xs" title = { candidate } >
{ entry ? . label ? ? candidate }
< / span >
< span className = "shrink-0 ml-auto text-[9px] font-medium px-1.5 py-0.5 rounded-full bg-sky-500/15 text-sky-400 border border-sky-500/20" >
config
< / span >
< / button >
) ;
} ) }
2026-02-26 16:33:48 -06:00
< div className = "max-h-[240px] overflow-y-auto" >
2026-03-05 15:24:20 +01:00
{ allowDefault && (
2026-02-26 16:33:48 -06:00
< button
2026-03-28 01:34:48 +01:00
type = "button"
2026-02-26 16:33:48 -06:00
className = { cn (
2026-03-05 15:24:20 +01:00
"flex items-center gap-2 w-full px-2 py-1.5 text-sm rounded hover:bg-accent/50" ,
! value && "bg-accent" ,
2026-02-26 16:33:48 -06:00
) }
onClick = { ( ) = > {
2026-03-05 15:24:20 +01:00
onChange ( "" ) ;
2026-02-26 16:33:48 -06:00
onOpenChange ( false ) ;
} }
>
2026-03-05 15:24:20 +01:00
Default
2026-02-26 16:33:48 -06:00
< / button >
2026-03-05 15:24:20 +01:00
) }
2026-03-28 01:34:48 +01:00
{ canCreateManualModel && (
< button
type = "button"
className = "flex items-center justify-between gap-2 w-full px-2 py-1.5 text-sm rounded hover:bg-accent/50"
onClick = { ( ) = > {
onChange ( manualModel ) ;
onOpenChange ( false ) ;
setModelSearch ( "" ) ;
} }
>
< span > Use manual model < / span >
< span className = "text-xs font-mono text-muted-foreground" > { manualModel } < / span >
< / button >
) }
2026-03-05 15:24:20 +01:00
{ groupedModels . map ( ( group ) = > (
< div key = { group . provider } className = "mb-1 last:mb-0" >
{ groupByProvider && (
< div className = "px-2 py-1 text-[10px] uppercase tracking-wide text-muted-foreground" >
{ group . provider } ( { group . entries . length } )
< / div >
) }
{ group . entries . map ( ( m ) = > (
< button
2026-03-28 01:34:48 +01:00
type = "button"
2026-03-05 15:24:20 +01:00
key = { m . id }
className = { cn (
"flex items-center w-full px-2 py-1.5 text-sm rounded hover:bg-accent/50" ,
m . id === value && "bg-accent" ,
) }
onClick = { ( ) = > {
onChange ( m . id ) ;
onOpenChange ( false ) ;
} }
>
< span className = "block w-full text-left truncate" title = { m . id } >
{ groupByProvider ? extractModelName ( m . id ) : m . label }
< / span >
< / button >
) ) }
< / div >
2026-02-26 16:33:48 -06:00
) ) }
2026-03-31 20:21:13 +01:00
{ filteredModels . length === 0 && ! canCreateManualModel && promotedModelIds . size === 0 && (
2026-03-28 01:34:48 +01:00
< div className = "px-2 py-2 space-y-2" >
< p className = "text-xs text-muted-foreground" >
{ onDetectModel
2026-03-31 20:21:13 +01:00
? ( emptyDetectHint ? ? "No model detected yet. Enter a provider/model manually." )
2026-03-28 01:34:48 +01:00
: "No models found." }
< / p >
< / div >
2026-02-26 16:33:48 -06:00
) }
< / div >
2026-02-20 10:32:32 -06:00
< / PopoverContent >
< / Popover >
< / Field >
) ;
}
function ThinkingEffortDropdown ( {
value ,
options ,
onChange ,
open ,
onOpenChange ,
} : {
value : string ;
options : ReadonlyArray < { id : string ; label : string } > ;
onChange : ( id : string ) = > void ;
open : boolean ;
onOpenChange : ( open : boolean ) = > void ;
} ) {
const selected = options . find ( ( option ) = > option . id === value ) ? ? options [ 0 ] ;
return (
< Field label = "Thinking effort" hint = { help . thinkingEffort } >
< Popover open = { open } onOpenChange = { onOpenChange } >
< PopoverTrigger asChild >
< button className = "inline-flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-sm hover:bg-accent/50 transition-colors w-full justify-between" >
< span className = { cn ( ! value && "text-muted-foreground" ) } > { selected ? . label ? ? "Auto" } < / span >
< ChevronDown className = "h-3 w-3 text-muted-foreground" / >
< / button >
< / PopoverTrigger >
< PopoverContent className = "w-[var(--radix-popover-trigger-width)] p-1" align = "start" >
{ options . map ( ( option ) = > (
< button
key = { option . id || "auto" }
className = { cn (
"flex items-center justify-between w-full px-2 py-1.5 text-sm rounded hover:bg-accent/50" ,
option . id === value && "bg-accent" ,
) }
onClick = { ( ) = > {
onChange ( option . id ) ;
onOpenChange ( false ) ;
} }
>
< span > { option . label } < / span >
{ option . id ? < span className = "text-xs text-muted-foreground font-mono" > { option . id } < / span > : null }
< / button >
) ) }
Extract AgentConfigForm and agent-config-primitives components
Shared primitives (Field, ToggleField, ToggleWithNumber, CollapsibleSection,
DraftInput, DraftTextarea, DraftNumberInput, HintIcon, help text, adapterLabels,
roleLabels) extracted into agent-config-primitives.tsx.
AgentConfigForm is a dual-mode form supporting both create (controlled values)
and edit (save-on-blur per field) modes, used by NewAgentDialog and AgentDetail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:26 -06:00
< / PopoverContent >
< / Popover >
< / Field >
) ;
}