From 4a71bb3f912600840fddcdf36d38f5fe10d2a296 Mon Sep 17 00:00:00 2001 From: Declan Brady Date: Mon, 4 May 2026 11:00:16 -0400 Subject: [PATCH] Add custom UI --- agentex-ui/app/custom/page.tsx | 30 +++ agentex-ui/components/custom/config-panel.tsx | 214 ++++++++++++++++++ .../components/custom/custom-chat-panel.tsx | 75 ++++++ .../components/custom/custom-page-root.tsx | 118 ++++++++++ .../components/custom/custom-prompt-input.tsx | 153 +++++++++++++ agentex-ui/components/custom/tag-input.tsx | 90 ++++++++ 6 files changed, 680 insertions(+) create mode 100644 agentex-ui/app/custom/page.tsx create mode 100644 agentex-ui/components/custom/config-panel.tsx create mode 100644 agentex-ui/components/custom/custom-chat-panel.tsx create mode 100644 agentex-ui/components/custom/custom-page-root.tsx create mode 100644 agentex-ui/components/custom/custom-prompt-input.tsx create mode 100644 agentex-ui/components/custom/tag-input.tsx diff --git a/agentex-ui/app/custom/page.tsx b/agentex-ui/app/custom/page.tsx new file mode 100644 index 0000000..87840be --- /dev/null +++ b/agentex-ui/app/custom/page.tsx @@ -0,0 +1,30 @@ +import { connection } from 'next/server'; + +import { CustomPageRoot } from '@/components/custom/custom-page-root'; +import { AgentexProvider } from '@/components/providers'; + +export default async function CustomPage() { + await connection(); + + const sgpAppURL = process.env.NEXT_PUBLIC_SGP_APP_URL ?? ''; + const agentexAPIBaseURL = + process.env.NEXT_PUBLIC_AGENTEX_API_BASE_URL ?? 'http://localhost:5003'; + + if (!agentexAPIBaseURL) { + return ( +
+

Missing some configs

+
{JSON.stringify({ sgpAppURL, agentexAPIBaseURL }, null, 2)}
+
+ ); + } + + return ( + + + + ); +} diff --git a/agentex-ui/components/custom/config-panel.tsx b/agentex-ui/components/custom/config-panel.tsx new file mode 100644 index 0000000..0b8f50a --- /dev/null +++ b/agentex-ui/components/custom/config-panel.tsx @@ -0,0 +1,214 @@ +'use client'; + +import { useCallback, useEffect } from 'react'; + +import { RotateCcw } from 'lucide-react'; +import { useForm } from 'react-hook-form'; + +import { TagInput } from '@/components/custom/tag-input'; +import { Button } from '@/components/ui/button'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, +} from '@/components/ui/form'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { Textarea } from '@/components/ui/textarea'; + +export type GoldenAgentConfig = { + harness: string; + model: string; + system_prompt: string; + allowed_tools: string[]; +}; + +const SUPPORTED_HARNESSES = [ + 'sandbox-claude', + 'claude-code', + 'codex', + 'agentex', +] as const; + +const DEFAULT_MODEL_BY_HARNESS: Record = { + 'sandbox-claude': 'claude-opus-4-6', + 'claude-code': 'claude-opus-4-6', + codex: 'gpt-5.4', + agentex: 'gpt-5.4', +}; + +export const DEFAULT_CONFIG: GoldenAgentConfig = { + harness: 'sandbox-claude', + model: 'claude-opus-4-6', + system_prompt: + "You are a developer for Scale AI's SGP team. Your primary sources of truth are scaleapi/packages/egp-api-backend and scaleapi/packages/egp-annotation. Use these packages to do the development you need to do. Make sure to read the READMEs and CLAUDE.mds in those directories to get the context you need to address any issues. Your main goal is to take in the information from the prompt, use your sources of truth to come up with a course of action to address it, and then make a PR with the solution.", + allowed_tools: [ + 'Read', + 'Write', + 'Edit', + 'Glob', + 'Grep', + 'Bash', + 'WebSearch', + 'WebFetch', + 'List', + ], +}; + +type ConfigPanelProps = { + disabled: boolean; + onConfigChange: (config: GoldenAgentConfig) => void; + onReset: () => void; +}; + +export function ConfigPanel({ + disabled, + onConfigChange, + onReset, +}: ConfigPanelProps) { + const form = useForm({ + defaultValues: DEFAULT_CONFIG, + }); + + const harness = form.watch('harness'); + + useEffect(() => { + const subscription = form.watch(values => { + onConfigChange(values as GoldenAgentConfig); + }); + return () => subscription.unsubscribe(); + }, [form, onConfigChange]); + + const handleHarnessChange = useCallback( + (value: string) => { + form.setValue('harness', value); + form.setValue('model', DEFAULT_MODEL_BY_HARNESS[value] ?? ''); + }, + [form] + ); + + const handleReset = useCallback(() => { + form.reset(DEFAULT_CONFIG); + onReset(); + }, [form, onReset]); + + return ( +
+
+
+

Configuration

+ {disabled && ( + + )} +
+

golden-agent

+
+ +
+ + ( + + Harness + + + )} + /> + + ( + + Model + + + + + )} + /> + + ( + + System Prompt + +