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 + +