diff --git a/ui/index.html b/ui/index.html index 8b5d8752..8f0a47e3 100644 --- a/ui/index.html +++ b/ui/index.html @@ -3,7 +3,14 @@
+{cwdPickerNotice}
+ )} )} @@ -347,6 +435,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) { onCommit={(v) => mark("adapterConfig", "promptTemplate", v || undefined) } + immediate placeholder="You are agent {{ agent.name }}. Your role is {{ agent.role }}..." minRows={4} /> @@ -429,7 +518,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) { ? set!({ command: v }) : mark("adapterConfig", "command", v || undefined) } - immediate={isCreate} + immediate className={inputClass} placeholder="e.g. node, python" /> @@ -439,7 +528,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) { value={ isCreate ? val!.args - : eff("adapterConfig", "args", String(config.args ?? "")) + : eff("adapterConfig", "args", formatArgList(config.args)) } onCommit={(v) => isCreate @@ -447,15 +536,10 @@ export function AgentConfigForm(props: AgentConfigFormProps) { : mark( "adapterConfig", "args", - v - ? v - .split(",") - .map((a) => a.trim()) - .filter(Boolean) - : undefined, + v ? parseCommaArgs(v) : undefined, ) } - immediate={isCreate} + immediate className={inputClass} placeholder="e.g. script.js, --flag" /> @@ -477,7 +561,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) { ? set!({ url: v }) : mark("adapterConfig", "url", v || undefined) } - immediate={isCreate} + immediate className={inputClass} placeholder="https://..." /> @@ -492,6 +576,24 @@ export function AgentConfigForm(props: AgentConfigFormProps) { onToggle={() => setAdapterAdvancedOpen(!adapterAdvancedOpen)} >{cwdPickerNotice}
+ )}{actionError}
} -No runs yet.
; @@ -450,61 +696,75 @@ function RunsTab({ runs, companyId }: { runs: HeartbeatRun[]; companyId: string (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ); - return ( -{run.stderrExcerpt}
+ {run.stdoutExcerpt}
+ Loading events...
; + // Poll shell log for running runs + useEffect(() => { + if (!isLive || !run.logRef) return; + const interval = setInterval(async () => { + try { + const result = await heartbeatsApi.log(run.id, logOffset, 256_000); + if (result.content) { + appendLogContent(result.content, result.nextOffset === undefined); + } + if (result.nextOffset !== undefined) { + setLogOffset(result.nextOffset); + } else if (result.content.length > 0) { + setLogOffset((prev) => prev + result.content.length); + } + } catch { + // ignore polling errors + } + }, 2000); + return () => clearInterval(interval); + }, [run.id, run.logRef, isLive, logOffset]); + + const adapterInvokePayload = useMemo(() => { + const evt = events.find((e) => e.eventType === "adapter.invoke"); + return asRecord(evt?.payload ?? null); + }, [events]); + + const transcript = useMemo(() => buildTranscript(logLines), [logLines]); + + if (loading && logLoading) { + returnLoading run logs...
; } - if (events.length === 0) { + if (events.length === 0 && logLines.length === 0 && !logError) { returnNo log events.
; } @@ -697,9 +1099,62 @@ function LogViewer({ runId, status }: { runId: string; status: string }) { }; return ( -
+ {typeof adapterInvokePayload.prompt === "string"
+ ? adapterInvokePayload.prompt
+ : JSON.stringify(adapterInvokePayload.prompt, null, 2)}
+
+
+ {JSON.stringify(adapterInvokePayload.context, null, 2)}
+
+
+ {JSON.stringify(adapterInvokePayload.env, null, 2)}
+
+
+ {JSON.stringify(entry.input, null, 2)}
+
+