@@ -0,0 +1,65 @@
|
||||
"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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user