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-03-03 08:45:26 -06:00
|
|
|
import { AGENT_ADAPTER_TYPES } from "@paperclipai/shared";
|
2026-03-16 19:35:11 -05:00
|
|
|
import {
|
|
|
|
|
hasSessionCompactionThresholds,
|
|
|
|
|
resolveSessionCompactionPolicy,
|
|
|
|
|
type ResolvedSessionCompactionPolicy,
|
|
|
|
|
} from "@paperclipai/adapter-utils";
|
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";
|
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-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" },
|
|
|
|
|
] 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" },
|
|
|
|
|
{ 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-02-19 15:44:05 -06:00
|
|
|
const { selectedCompanyId } = useCompany();
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
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-02-26 16:33:48 -06:00
|
|
|
// When adapter type changes, send only the new config — don't merge
|
|
|
|
|
// with old config since old adapter fields are meaningless for the new type
|
|
|
|
|
patch.adapterConfig = overlay.adapterConfig;
|
|
|
|
|
} 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-04 16:48:54 -06:00
|
|
|
const isLocal =
|
|
|
|
|
adapterType === "claude_local" ||
|
|
|
|
|
adapterType === "codex_local" ||
|
2026-03-08 16:43:34 +05:30
|
|
|
adapterType === "gemini_local" ||
|
2026-03-05 06:31:22 -06:00
|
|
|
adapterType === "opencode_local" ||
|
|
|
|
|
adapterType === "cursor";
|
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-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,
|
|
|
|
|
};
|
|
|
|
|
|
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]);
|
|
|
|
|
const sessionCompaction = useMemo(
|
|
|
|
|
() => resolveSessionCompactionPolicy(adapterType, effectiveRuntimeConfig),
|
|
|
|
|
[adapterType, effectiveRuntimeConfig],
|
|
|
|
|
);
|
|
|
|
|
const showSessionCompactionCard = Boolean(sessionCompaction.adapterSessionManagement);
|
2026-02-20 10:32:32 -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
|
|
|
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>
|
|
|
|
|
<Field label="Capabilities" hint={help.capabilities}>
|
2026-02-20 12:28:42 -06:00
|
|
|
<MarkdownEditor
|
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", "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-02-20 14:11:30 -06:00
|
|
|
{isLocal && (
|
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-02-20 12:28:42 -06:00
|
|
|
<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-02-20 14:11:30 -06:00
|
|
|
<Field label="Adapter type" hint={help.adapterType}>
|
|
|
|
|
<AdapterTypeDropdown
|
|
|
|
|
value={adapterType}
|
|
|
|
|
onChange={(t) => {
|
|
|
|
|
if (isCreate) {
|
2026-02-26 16:33:48 -06:00
|
|
|
// Reset all adapter-specific fields to defaults when switching adapter type
|
|
|
|
|
const { adapterType: _at, ...defaults } = defaultCreateValues;
|
2026-03-03 12:41:50 -06:00
|
|
|
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;
|
2026-03-08 16:43:34 +05:30
|
|
|
} else if (t === "gemini_local") {
|
|
|
|
|
nextValues.model = DEFAULT_GEMINI_LOCAL_MODEL;
|
2026-03-05 06:31:22 -06:00
|
|
|
} else if (t === "cursor") {
|
|
|
|
|
nextValues.model = DEFAULT_CURSOR_LOCAL_MODEL;
|
2026-03-04 16:48:54 -06:00
|
|
|
} else if (t === "opencode_local") {
|
2026-03-06 15:30:13 +00:00
|
|
|
nextValues.model = "";
|
2026-03-03 12:41:50 -06:00
|
|
|
}
|
|
|
|
|
set!(nextValues);
|
2026-02-20 14:11:30 -06:00
|
|
|
} else {
|
2026-03-05 06:31:22 -06:00
|
|
|
// Clear all adapter config and explicitly blank out model + effort/mode keys
|
2026-02-26 16:33:48 -06:00
|
|
|
// so the old adapter's values don't bleed through via eff()
|
2026-02-20 14:11:30 -06:00
|
|
|
setOverlay((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
adapterType: t,
|
2026-02-26 16:33:48 -06:00
|
|
|
adapterConfig: {
|
2026-03-04 16:48:54 -06:00
|
|
|
model:
|
|
|
|
|
t === "codex_local"
|
|
|
|
|
? DEFAULT_CODEX_LOCAL_MODEL
|
2026-03-08 16:43:34 +05:30
|
|
|
: t === "gemini_local"
|
|
|
|
|
? DEFAULT_GEMINI_LOCAL_MODEL
|
2026-03-05 06:31:22 -06:00
|
|
|
: t === "cursor"
|
|
|
|
|
? DEFAULT_CURSOR_LOCAL_MODEL
|
2026-03-06 15:30:13 +00:00
|
|
|
: "",
|
2026-02-26 16:33:48 -06:00
|
|
|
effort: "",
|
|
|
|
|
modelReasoningEffort: "",
|
2026-03-04 16:48:54 -06:00
|
|
|
variant: "",
|
2026-03-05 06:31:22 -06:00
|
|
|
mode: "",
|
2026-03-03 12:41:50 -06:00
|
|
|
...(t === "codex_local"
|
|
|
|
|
? {
|
|
|
|
|
dangerouslyBypassApprovalsAndSandbox:
|
|
|
|
|
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
|
|
|
|
|
}
|
|
|
|
|
: {}),
|
2026-02-26 16:33:48 -06:00
|
|
|
},
|
2026-02-20 14:11:30 -06:00
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Field>
|
|
|
|
|
|
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 */}
|
|
|
|
|
{isLocal && (
|
|
|
|
|
<Field label="Working directory" hint={help.cwd}>
|
|
|
|
|
<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-02-18 13:53:03 -06:00
|
|
|
{/* Adapter-specific fields */}
|
|
|
|
|
<uiAdapter.ConfigFields {...adapterFieldProps} />
|
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 & Configuration</h3>
|
|
|
|
|
: <div className="px-4 py-2 text-xs font-medium text-muted-foreground">Permissions & 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 })
|
|
|
|
|
: mark("adapterConfig", "command", v || undefined)
|
|
|
|
|
}
|
|
|
|
|
immediate
|
|
|
|
|
className={inputClass}
|
2026-03-04 16:48:54 -06:00
|
|
|
placeholder={
|
|
|
|
|
adapterType === "codex_local"
|
|
|
|
|
? "codex"
|
2026-03-08 16:43:34 +05:30
|
|
|
: adapterType === "gemini_local"
|
|
|
|
|
? "gemini"
|
2026-03-05 06:31:22 -06:00
|
|
|
: adapterType === "cursor"
|
|
|
|
|
? "agent"
|
2026-03-06 15:23:55 +00:00
|
|
|
: adapterType === "opencode_local"
|
|
|
|
|
? "opencode"
|
|
|
|
|
: "claude"
|
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-05 15:24:20 +01:00
|
|
|
allowDefault={adapterType !== "opencode_local"}
|
|
|
|
|
required={adapterType === "opencode_local"}
|
|
|
|
|
groupByProvider={adapterType === "opencode_local"}
|
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-02-20 12:50:36 -06:00
|
|
|
<Field label="Bootstrap prompt (first run)" hint={help.bootstrapPrompt}>
|
|
|
|
|
<MarkdownEditor
|
|
|
|
|
value={
|
|
|
|
|
isCreate
|
|
|
|
|
? val!.bootstrapPrompt
|
|
|
|
|
: eff(
|
|
|
|
|
"adapterConfig",
|
|
|
|
|
"bootstrapPromptTemplate",
|
|
|
|
|
String(config.bootstrapPromptTemplate ?? ""),
|
|
|
|
|
)
|
|
|
|
|
}
|
2026-02-20 10:32:32 -06:00
|
|
|
onChange={(v) =>
|
|
|
|
|
isCreate
|
2026-02-20 12:50:36 -06:00
|
|
|
? set!({ bootstrapPrompt: v })
|
|
|
|
|
: mark("adapterConfig", "bootstrapPromptTemplate", v || undefined)
|
2026-02-20 10:32:32 -06:00
|
|
|
}
|
2026-02-20 12:50:36 -06:00
|
|
|
placeholder="Optional initial setup prompt for the first run"
|
|
|
|
|
contentClassName="min-h-[44px] text-sm font-mono"
|
|
|
|
|
imageUploadHandler={async (file) => {
|
|
|
|
|
const namespace = isCreate
|
|
|
|
|
? "agents/drafts/bootstrap-prompt"
|
|
|
|
|
: `agents/${props.agent.id}/bootstrap-prompt`;
|
|
|
|
|
const asset = await uploadMarkdownImage.mutateAsync({ file, namespace });
|
|
|
|
|
return asset.contentPath;
|
|
|
|
|
}}
|
2026-02-20 10:32:32 -06:00
|
|
|
/>
|
2026-02-20 12:50:36 -06:00
|
|
|
</Field>
|
2026-03-13 08:49:11 -05:00
|
|
|
<div className="rounded-md border border-sky-500/25 bg-sky-500/10 px-3 py-2 text-xs text-sky-100">
|
|
|
|
|
Bootstrap prompt is only sent for fresh sessions. Put stable setup, habits, and longer reusable guidance here. Frequent changes reduce the value of session reuse because new sessions must replay it.
|
|
|
|
|
</div>
|
2026-02-20 12:50:36 -06:00
|
|
|
{adapterType === "claude_local" && (
|
|
|
|
|
<ClaudeLocalAdvancedFields {...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 })
|
|
|
|
|
: mark("adapterConfig", "extraArgs", v ? parseCommaArgs(v) : undefined)
|
|
|
|
|
}
|
|
|
|
|
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 ---- */}
|
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
|
|
|
{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 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}
|
|
|
|
|
/>
|
2026-03-16 19:35:11 -05:00
|
|
|
{showSessionCompactionCard && (
|
|
|
|
|
<SessionCompactionPolicyCard
|
|
|
|
|
adapterType={adapterType}
|
|
|
|
|
resolution={sessionCompaction}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
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:16: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
|
|
|
) : (
|
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}
|
|
|
|
|
checked={eff("heartbeat", "enabled", heartbeat.enabled !== false)}
|
|
|
|
|
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}
|
|
|
|
|
showNumber={eff("heartbeat", "enabled", heartbeat.enabled !== false)}
|
|
|
|
|
/>
|
2026-03-16 19:35:11 -05:00
|
|
|
{showSessionCompactionCard && (
|
|
|
|
|
<SessionCompactionPolicyCard
|
|
|
|
|
adapterType={adapterType}
|
|
|
|
|
resolution={sessionCompaction}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
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>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
</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>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 19:35:11 -05:00
|
|
|
function formatSessionThreshold(value: number, suffix: string) {
|
|
|
|
|
if (value <= 0) return "Off";
|
|
|
|
|
return `${value.toLocaleString("en-US")} ${suffix}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function SessionCompactionPolicyCard({
|
|
|
|
|
adapterType,
|
|
|
|
|
resolution,
|
|
|
|
|
}: {
|
|
|
|
|
adapterType: string;
|
|
|
|
|
resolution: ResolvedSessionCompactionPolicy;
|
|
|
|
|
}) {
|
|
|
|
|
const { adapterSessionManagement, policy, source } = resolution;
|
|
|
|
|
if (!adapterSessionManagement) return null;
|
|
|
|
|
|
|
|
|
|
const adapterLabel = adapterLabels[adapterType] ?? adapterType;
|
|
|
|
|
const sourceLabel = source === "agent_override" ? "Agent override" : "Adapter default";
|
|
|
|
|
const rotationDisabled = !policy.enabled || !hasSessionCompactionThresholds(policy);
|
|
|
|
|
const nativeSummary =
|
|
|
|
|
adapterSessionManagement.nativeContextManagement === "confirmed"
|
|
|
|
|
? `${adapterLabel} is treated as natively managing long context, so Paperclip fresh-session rotation defaults to off.`
|
|
|
|
|
: adapterSessionManagement.nativeContextManagement === "likely"
|
|
|
|
|
? `${adapterLabel} likely manages long context itself, but Paperclip still keeps conservative rotation defaults for now.`
|
|
|
|
|
: `${adapterLabel} does not have verified native compaction behavior, so Paperclip keeps conservative rotation defaults.`;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="rounded-md border border-sky-500/25 bg-sky-500/10 px-3 py-3 space-y-2">
|
|
|
|
|
<div className="flex items-center justify-between gap-3">
|
|
|
|
|
<div className="text-xs font-medium text-sky-50">Session compaction</div>
|
|
|
|
|
<span className="rounded-full border border-sky-400/30 px-2 py-0.5 text-[11px] text-sky-100">
|
|
|
|
|
{sourceLabel}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-xs text-sky-100/90">
|
|
|
|
|
{nativeSummary}
|
|
|
|
|
</p>
|
|
|
|
|
<p className="text-xs text-sky-100/80">
|
|
|
|
|
{rotationDisabled
|
|
|
|
|
? "No Paperclip-managed fresh-session thresholds are active for this adapter."
|
|
|
|
|
: "Paperclip will start a fresh session when one of these thresholds is reached."}
|
|
|
|
|
</p>
|
|
|
|
|
<div className="grid grid-cols-3 gap-2 text-[11px] text-sky-100/85 tabular-nums">
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-sky-100/60">Runs</div>
|
|
|
|
|
<div>{formatSessionThreshold(policy.maxSessionRuns, "runs")}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-sky-100/60">Raw input</div>
|
|
|
|
|
<div>{formatSessionThreshold(policy.maxRawInputTokens, "tokens")}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div className="text-sky-100/60">Age</div>
|
|
|
|
|
<div>{formatSessionThreshold(policy.maxSessionAgeHours, "hours")}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-[11px] text-sky-100/75">
|
|
|
|
|
A large cumulative raw token total does not mean the full session is resent on every heartbeat.
|
|
|
|
|
{source === "agent_override" && " This agent has an explicit runtimeConfig session compaction override."}
|
|
|
|
|
</p>
|
|
|
|
|
</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 ---- */
|
|
|
|
|
|
2026-03-08 16:43:34 +05:30
|
|
|
const ENABLED_ADAPTER_TYPES = new Set(["claude_local", "codex_local", "gemini_local", "opencode_local", "cursor"]);
|
2026-03-03 11:29:34 -06:00
|
|
|
|
|
|
|
|
/** Display list includes all real adapter types plus UI-only coming-soon entries. */
|
|
|
|
|
const ADAPTER_DISPLAY_LIST: { value: string; label: string; comingSoon: boolean }[] = [
|
|
|
|
|
...AGENT_ADAPTER_TYPES.map((t) => ({
|
|
|
|
|
value: t,
|
|
|
|
|
label: adapterLabels[t] ?? t,
|
|
|
|
|
comingSoon: !ENABLED_ADAPTER_TYPES.has(t),
|
|
|
|
|
})),
|
|
|
|
|
];
|
|
|
|
|
|
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
|
|
|
function AdapterTypeDropdown({
|
|
|
|
|
value,
|
|
|
|
|
onChange,
|
|
|
|
|
}: {
|
|
|
|
|
value: string;
|
|
|
|
|
onChange: (type: string) => void;
|
|
|
|
|
}) {
|
|
|
|
|
return (
|
|
|
|
|
<Popover>
|
|
|
|
|
<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}
|
|
|
|
|
<span>{adapterLabels[value] ?? value}</span>
|
|
|
|
|
</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-03 11:29:34 -06:00
|
|
|
{ADAPTER_DISPLAY_LIST.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={() => {
|
|
|
|
|
if (!item.comingSoon) onChange(item.value);
|
|
|
|
|
}}
|
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>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
function EnvVarEditor({
|
|
|
|
|
value,
|
2026-02-19 15:44:05 -06:00
|
|
|
secrets,
|
|
|
|
|
onCreateSecret,
|
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
|
|
|
onChange,
|
|
|
|
|
}: {
|
2026-02-19 15:44:05 -06:00
|
|
|
value: Record<string, EnvBinding>;
|
|
|
|
|
secrets: CompanySecret[];
|
|
|
|
|
onCreateSecret: (name: string, value: string) => Promise<CompanySecret>;
|
|
|
|
|
onChange: (env: Record<string, EnvBinding> | undefined) => void;
|
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
|
|
|
}) {
|
2026-02-19 15:44:05 -06:00
|
|
|
type Row = {
|
|
|
|
|
key: string;
|
|
|
|
|
source: "plain" | "secret";
|
|
|
|
|
plainValue: string;
|
|
|
|
|
secretId: string;
|
|
|
|
|
};
|
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
|
|
|
|
2026-02-19 15:44:05 -06:00
|
|
|
function toRows(rec: Record<string, EnvBinding> | null | undefined): Row[] {
|
|
|
|
|
if (!rec || typeof rec !== "object") {
|
|
|
|
|
return [{ key: "", source: "plain", plainValue: "", secretId: "" }];
|
|
|
|
|
}
|
|
|
|
|
const entries = Object.entries(rec).map(([k, binding]) => {
|
|
|
|
|
if (typeof binding === "string") {
|
|
|
|
|
return {
|
|
|
|
|
key: k,
|
|
|
|
|
source: "plain" as const,
|
|
|
|
|
plainValue: binding,
|
|
|
|
|
secretId: "",
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
typeof binding === "object" &&
|
|
|
|
|
binding !== null &&
|
|
|
|
|
"type" in binding &&
|
|
|
|
|
(binding as { type?: unknown }).type === "secret_ref"
|
|
|
|
|
) {
|
|
|
|
|
const recBinding = binding as { secretId?: unknown };
|
|
|
|
|
return {
|
|
|
|
|
key: k,
|
|
|
|
|
source: "secret" as const,
|
|
|
|
|
plainValue: "",
|
|
|
|
|
secretId: typeof recBinding.secretId === "string" ? recBinding.secretId : "",
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
typeof binding === "object" &&
|
|
|
|
|
binding !== null &&
|
|
|
|
|
"type" in binding &&
|
|
|
|
|
(binding as { type?: unknown }).type === "plain"
|
|
|
|
|
) {
|
|
|
|
|
const recBinding = binding as { value?: unknown };
|
|
|
|
|
return {
|
|
|
|
|
key: k,
|
|
|
|
|
source: "plain" as const,
|
|
|
|
|
plainValue: typeof recBinding.value === "string" ? recBinding.value : "",
|
|
|
|
|
secretId: "",
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
key: k,
|
|
|
|
|
source: "plain" as const,
|
|
|
|
|
plainValue: "",
|
|
|
|
|
secretId: "",
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
return [...entries, { key: "", source: "plain", plainValue: "", secretId: "" }];
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const [rows, setRows] = useState<Row[]>(() => toRows(value));
|
2026-02-19 15:44:05 -06:00
|
|
|
const [sealError, setSealError] = useState<string | null>(null);
|
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
|
|
|
const valueRef = useRef(value);
|
|
|
|
|
|
|
|
|
|
// Sync when value identity changes (overlay reset after save)
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (value !== valueRef.current) {
|
|
|
|
|
valueRef.current = value;
|
|
|
|
|
setRows(toRows(value));
|
|
|
|
|
}
|
|
|
|
|
}, [value]);
|
|
|
|
|
|
|
|
|
|
function emit(nextRows: Row[]) {
|
2026-02-19 15:44:05 -06:00
|
|
|
const rec: Record<string, EnvBinding> = {};
|
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
|
|
|
for (const row of nextRows) {
|
|
|
|
|
const k = row.key.trim();
|
2026-02-19 15:44:05 -06:00
|
|
|
if (!k) continue;
|
|
|
|
|
if (row.source === "secret") {
|
|
|
|
|
if (!row.secretId) continue;
|
|
|
|
|
rec[k] = { type: "secret_ref", secretId: row.secretId, version: "latest" };
|
|
|
|
|
} else {
|
|
|
|
|
rec[k] = { type: "plain", value: row.plainValue };
|
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
onChange(Object.keys(rec).length > 0 ? rec : undefined);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 15:44:05 -06:00
|
|
|
function updateRow(i: number, patch: Partial<Row>) {
|
|
|
|
|
const withPatch = rows.map((r, idx) => (idx === i ? { ...r, ...patch } : r));
|
|
|
|
|
if (
|
|
|
|
|
withPatch[withPatch.length - 1].key ||
|
|
|
|
|
withPatch[withPatch.length - 1].plainValue ||
|
|
|
|
|
withPatch[withPatch.length - 1].secretId
|
|
|
|
|
) {
|
|
|
|
|
withPatch.push({ key: "", source: "plain", plainValue: "", secretId: "" });
|
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
|
|
|
}
|
2026-02-19 15:44:05 -06:00
|
|
|
setRows(withPatch);
|
|
|
|
|
emit(withPatch);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeRow(i: number) {
|
|
|
|
|
const next = rows.filter((_, idx) => idx !== i);
|
2026-02-19 15:44:05 -06:00
|
|
|
if (
|
|
|
|
|
next.length === 0 ||
|
|
|
|
|
next[next.length - 1].key ||
|
|
|
|
|
next[next.length - 1].plainValue ||
|
|
|
|
|
next[next.length - 1].secretId
|
|
|
|
|
) {
|
|
|
|
|
next.push({ key: "", source: "plain", plainValue: "", secretId: "" });
|
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
|
|
|
}
|
|
|
|
|
setRows(next);
|
|
|
|
|
emit(next);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-19 15:44:05 -06:00
|
|
|
function defaultSecretName(key: string): string {
|
|
|
|
|
return key
|
|
|
|
|
.trim()
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
.replace(/[^a-z0-9_]+/g, "_")
|
|
|
|
|
.replace(/^_+|_+$/g, "")
|
|
|
|
|
.slice(0, 64);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function sealRow(i: number) {
|
|
|
|
|
const row = rows[i];
|
|
|
|
|
if (!row) return;
|
|
|
|
|
const key = row.key.trim();
|
|
|
|
|
const plain = row.plainValue;
|
|
|
|
|
if (!key || plain.length === 0) return;
|
|
|
|
|
|
|
|
|
|
const suggested = defaultSecretName(key) || "secret";
|
|
|
|
|
const name = window.prompt("Secret name", suggested)?.trim();
|
|
|
|
|
if (!name) return;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
setSealError(null);
|
|
|
|
|
const created = await onCreateSecret(name, plain);
|
|
|
|
|
updateRow(i, {
|
|
|
|
|
source: "secret",
|
|
|
|
|
secretId: created.id,
|
|
|
|
|
});
|
|
|
|
|
} catch (err) {
|
|
|
|
|
setSealError(err instanceof Error ? err.message : "Failed to create secret");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
return (
|
|
|
|
|
<div className="space-y-1.5">
|
|
|
|
|
{rows.map((row, i) => {
|
2026-02-19 15:44:05 -06:00
|
|
|
const isTrailing =
|
|
|
|
|
i === rows.length - 1 &&
|
|
|
|
|
!row.key &&
|
|
|
|
|
!row.plainValue &&
|
|
|
|
|
!row.secretId;
|
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
|
|
|
return (
|
|
|
|
|
<div key={i} className="flex items-center gap-1.5">
|
|
|
|
|
<input
|
|
|
|
|
className={cn(inputClass, "flex-[2]")}
|
|
|
|
|
placeholder="KEY"
|
|
|
|
|
value={row.key}
|
2026-02-19 15:44:05 -06:00
|
|
|
onChange={(e) => updateRow(i, { key: e.target.value })}
|
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
|
|
|
/>
|
2026-02-19 15:44:05 -06:00
|
|
|
<select
|
|
|
|
|
className={cn(inputClass, "flex-[1] bg-background")}
|
|
|
|
|
value={row.source}
|
|
|
|
|
onChange={(e) =>
|
|
|
|
|
updateRow(i, {
|
|
|
|
|
source: e.target.value === "secret" ? "secret" : "plain",
|
|
|
|
|
...(e.target.value === "plain" ? { secretId: "" } : {}),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<option value="plain">Plain</option>
|
|
|
|
|
<option value="secret">Secret</option>
|
|
|
|
|
</select>
|
|
|
|
|
{row.source === "secret" ? (
|
|
|
|
|
<>
|
|
|
|
|
<select
|
|
|
|
|
className={cn(inputClass, "flex-[3] bg-background")}
|
|
|
|
|
value={row.secretId}
|
|
|
|
|
onChange={(e) => updateRow(i, { secretId: e.target.value })}
|
|
|
|
|
>
|
|
|
|
|
<option value="">Select secret...</option>
|
|
|
|
|
{secrets.map((secret) => (
|
|
|
|
|
<option key={secret.id} value={secret.id}>
|
|
|
|
|
{secret.name}
|
|
|
|
|
</option>
|
|
|
|
|
))}
|
|
|
|
|
</select>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="inline-flex items-center rounded-md border border-border px-2 py-0.5 text-xs text-muted-foreground hover:bg-accent/50 transition-colors shrink-0"
|
|
|
|
|
onClick={() => sealRow(i)}
|
|
|
|
|
disabled={!row.key.trim() || !row.plainValue}
|
|
|
|
|
title="Create secret from current plain value"
|
|
|
|
|
>
|
|
|
|
|
New
|
|
|
|
|
</button>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<input
|
|
|
|
|
className={cn(inputClass, "flex-[3]")}
|
|
|
|
|
placeholder="value"
|
|
|
|
|
value={row.plainValue}
|
|
|
|
|
onChange={(e) => updateRow(i, { plainValue: e.target.value })}
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="inline-flex items-center rounded-md border border-border px-2 py-0.5 text-xs text-muted-foreground hover:bg-accent/50 transition-colors shrink-0"
|
|
|
|
|
onClick={() => sealRow(i)}
|
|
|
|
|
disabled={!row.key.trim() || !row.plainValue}
|
|
|
|
|
title="Store value as secret and replace with reference"
|
|
|
|
|
>
|
|
|
|
|
Seal
|
|
|
|
|
</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
|
|
|
{!isTrailing ? (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="shrink-0 p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-colors"
|
|
|
|
|
onClick={() => removeRow(i)}
|
|
|
|
|
>
|
|
|
|
|
<X className="h-3.5 w-3.5" />
|
|
|
|
|
</button>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="w-[26px] shrink-0" />
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
2026-02-19 15:44:05 -06:00
|
|
|
{sealError && <p className="text-[11px] text-destructive">{sealError}</p>}
|
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
|
|
|
<p className="text-[11px] text-muted-foreground/60">
|
|
|
|
|
PAPERCLIP_* variables are injected automatically at runtime.
|
|
|
|
|
</p>
|
|
|
|
|
</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
|
|
|
function ModelDropdown({
|
|
|
|
|
models,
|
|
|
|
|
value,
|
|
|
|
|
onChange,
|
|
|
|
|
open,
|
|
|
|
|
onOpenChange,
|
2026-03-05 15:24:20 +01:00
|
|
|
allowDefault,
|
|
|
|
|
required,
|
|
|
|
|
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
|
|
|
}: {
|
|
|
|
|
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;
|
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("");
|
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-05 15:24:20 +01:00
|
|
|
const filteredModels = useMemo(() => {
|
|
|
|
|
return models.filter((m) => {
|
|
|
|
|
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)
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}, [models, modelSearch]);
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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>
|
|
|
|
|
<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")}>
|
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-02-20 10:32:32 -06:00
|
|
|
<input
|
|
|
|
|
className="w-full px-2 py-1.5 text-xs bg-transparent outline-none border-b border-border mb-1 placeholder:text-muted-foreground/50"
|
|
|
|
|
placeholder="Search models..."
|
|
|
|
|
value={modelSearch}
|
|
|
|
|
onChange={(e) => setModelSearch(e.target.value)}
|
|
|
|
|
autoFocus
|
|
|
|
|
/>
|
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
|
|
|
|
|
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
|
|
|
)}
|
|
|
|
|
{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
|
|
|
|
|
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
|
|
|
))}
|
|
|
|
|
{filteredModels.length === 0 && (
|
|
|
|
|
<p className="px-2 py-1.5 text-xs text-muted-foreground">No models found.</p>
|
|
|
|
|
)}
|
|
|
|
|
</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>
|
|
|
|
|
);
|
|
|
|
|
}
|