66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
"use client"
|
|
|
|
// Starting a run: the goal and the plan as JSON. The plan is what the run will do, shown to the
|
|
// person before they start it, and admitted by the server against the hard ceilings. The start resolves
|
|
// once the live stream has seen the new run, so the page's live run list already shows it.
|
|
|
|
import type { ProjectSlugs } from "@conusai-kit/ui"
|
|
import { useWrite } from "@conusai-kit/ui/data"
|
|
import { FormLayout, PageSection, TextField } from "@conusai-kit/ui/patterns"
|
|
import type { ReactElement } from "react"
|
|
|
|
export interface StartFormLabels {
|
|
readonly heading: string
|
|
readonly goalLabel: string
|
|
readonly goalHint: string
|
|
readonly planLabel: string
|
|
readonly planHint: string
|
|
readonly submit: string
|
|
readonly starting: string
|
|
readonly failed: string
|
|
}
|
|
|
|
const EXAMPLE = JSON.stringify([
|
|
{ key: "read", label: "Read the document", tool: "documents.read", args: { fileId: "…" } },
|
|
])
|
|
|
|
const parses = (text: string): boolean => {
|
|
try {
|
|
JSON.parse(text)
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
export function StartForm({ slugs, labels }: { slugs: ProjectSlugs; labels: StartFormLabels }): ReactElement {
|
|
const startRun = useWrite<ProjectSlugs & { goal: string; plan: unknown }, unknown>("agent.run.start", {
|
|
org: slugs.org,
|
|
})
|
|
return (
|
|
<PageSection title={labels.heading} variant="card">
|
|
<FormLayout
|
|
submitLabel={labels.submit}
|
|
busyLabel={labels.starting}
|
|
validate={({ plan = "" }) =>
|
|
parses(plan) ? undefined : { plan: labels.failed.replace("{detail}", "invalid JSON") }
|
|
}
|
|
onSubmit={async ({ goal = "", plan = "" }) => {
|
|
await startRun.mutate({ ...slugs, goal, plan: JSON.parse(plan) })
|
|
}}
|
|
>
|
|
<TextField name="goal" label={labels.goalLabel} description={labels.goalHint} required maxLength={2_000} />
|
|
<TextField
|
|
multiline
|
|
name="plan"
|
|
label={labels.planLabel}
|
|
description={labels.planHint.replace("{example}", EXAMPLE)}
|
|
required
|
|
rows={6}
|
|
defaultValue={EXAMPLE}
|
|
/>
|
|
</FormLayout>
|
|
</PageSection>
|
|
)
|
|
}
|