Export template source from a4fa7159a34eb66df039421e3c0fbf0a177905cd:quixos-instance/packages/agent-presentation

This commit is contained in:
Quixos Template Publisher
2000-01-01 00:00:00 +00:00
commit 2603d5101a
17 changed files with 1816 additions and 0 deletions
+606
View File
@@ -0,0 +1,606 @@
import React, { useEffect, useRef, useState, useSyncExternalStore } from "react";
import {
type Item,
type Request,
type Question,
type ThreadController,
type Profiles,
itemKey,
terminal,
} from "./protocol.js";
import { LocalInput, LocalTextArea, LocalSelect, Markdown } from "@quixos/camino-react/ui";
import { draftKey } from "./http.js";
const labels: Record<string, string> = {
queued: "Queued",
blocked: "Waiting to start",
running: "Working",
waiting_input: "Needs your answer",
recovering: "Checking execution status",
recording: "Recording result",
pending_graph: "Awaiting graph recording",
awaiting_graph: "Awaiting graph recording",
completed: "Completed",
failed: "Failed",
cancelled: "Cancelled",
uncertain: "Outcome uncertain",
parked: "Needs your answer",
};
function ResultValue({ value }: { value: unknown }) {
if (Array.isArray(value))
return (
<ol>
{value.map((entry, index) => (
<li key={index}>
<ResultValue value={entry} />
</li>
))}
</ol>
);
if (value && typeof value === "object")
return (
<dl>
{Object.entries(value).map(([key, entry]) => (
<React.Fragment key={key}>
<dt>{key}</dt>
<dd>
<ResultValue value={entry} />
</dd>
</React.Fragment>
))}
</dl>
);
return <span>{value === null ? "null" : String(value)}</span>;
}
export function StructuredResult({ value }: { value: string }) {
let parsed: unknown;
try {
parsed = JSON.parse(value);
} catch {
return <pre>{value}</pre>;
}
return (
<div className="agent-result" aria-label="Structured result">
<ResultValue value={parsed} />
<details>
<summary>Raw JSON</summary>
<pre>{value}</pre>
<button onClick={() => void navigator.clipboard.writeText(value)}>Copy JSON</button>
</details>
</div>
);
}
function QuestionForm({
question,
request,
controller,
}: {
question: Question;
request: Request;
controller: ThreadController;
}) {
const [answer, setAnswer] = useState(""),
[busy, setBusy] = useState(false),
[error, setError] = useState("");
let options: string[] = [];
try {
options = JSON.parse(question.data.options);
} catch {}
const open =
question.data.status === "open" &&
!terminal.has(request.progress.status) &&
!request.progress.cancelRequested &&
Date.parse(question.data.expiresAt) > Date.now();
return (
<form
className="agent-question"
onSubmit={(event) => {
event.preventDefault();
if (!open || !answer.trim() || busy) return;
setBusy(true);
setError("");
void controller
.control({
kind: "answer",
question: question._camino.ref.object,
attempt: question.data.attempt,
generation: question.data.generation,
answer,
})
.catch((error) => setError(String(error)))
.finally(() => setBusy(false));
}}
>
<fieldset disabled={!open || busy}>
<legend>{question.data.title}</legend>
{options.map((option) => (
<label key={option}>
<LocalInput
type="radio"
name={question._camino.ref.object}
value={option}
checked={answer === option}
onChange={() => setAnswer(option)}
/>
{option}
</label>
))}
<label>
Your answer
<LocalInput aria-label="Your answer" value={answer} onChange={(event) => setAnswer(event.target.value)} />
</label>
<button disabled={!answer.trim()}>{busy ? "Sending answer…" : "Answer"}</button>
</fieldset>
{!open && (
<p>
{question.data.answer
? `Answered: ${question.data.answer}`
: question.data.status === "open"
? "This question is no longer accepting answers."
: question.data.status}
</p>
)}
{error && <p role="alert">{error}</p>}
</form>
);
}
function Activity({ item }: { item: Item }) {
let value: any;
try {
value = JSON.parse(item.data.activity ?? "null");
} catch {}
const title = value?.command ?? value?.label ?? item.data.text ?? "Activity";
return (
<details className="agent-activity-card">
<summary>{String(title).slice(0, 300)}</summary>
<pre>{value?.aggregatedOutput ?? value?.output ?? value?.detail ?? item.data.text}</pre>
{value?.exitCode !== undefined && <p>Exit code: {value.exitCode}</p>}
</details>
);
}
function RequestCard({
request,
controller,
inspection,
}: {
request: Request;
controller: ThreadController;
inspection: boolean;
}) {
const [busy, setBusy] = useState(false),
[error, setError] = useState(""),
[details, setDetails] = useState<unknown>();
const p = request.progress,
cancel = () => {
setBusy(true);
setError("");
const action =
request.pendingGraph && request.repair
? import("./http.js").then(({ api }) =>
api("/repair-control", {
operationId: crypto.randomUUID(),
repair: request.repair,
attempt: p.attempt,
generation: p.generation,
kind: "cancel",
}),
)
: controller.control({ kind: "cancel", request: request._camino.ref.object });
void action.catch((error) => setError(String(error))).finally(() => setBusy(false));
};
return (
<footer className={`agent-request-card agent-request-${p.status}`} data-request={request._camino.ref.object}>
<div>
{(inspection || p.status !== "completed") && <strong>{labels[p.status] ?? p.status}</strong>}
{request.pendingGraph && <span> · Awaiting graph recording</span>}
{p.cancelRequested && !terminal.has(p.status) && <span> · Stop requested</span>}
{!terminal.has(p.status) && (
<button disabled={busy || p.cancelRequested || (request.pendingGraph && !p.attempt)} onClick={cancel}>
Stop request
</button>
)}
{!request.pendingGraph && (inspection || p.status !== "completed") && (
<button
onClick={() => {
void controller
.details(request._camino.ref.object)
.then(setDetails)
.catch((error) => setError(String(error)));
}}
>
Request details
</button>
)}
</div>
{p.reason && <p>{p.reason}</p>}
{p.status === "uncertain" && <p>Execution may have occurred. Check activity before starting another request.</p>}
{p.status === "completed" && request.admission?.responseKind === "json" && p.result && (
<StructuredResult value={p.result} />
)}
{p.status === "completed" && request.admission?.responseKind === "unit" && <p>Actions completed.</p>}
{["failed", "cancelled", "uncertain"].includes(p.status) && request.admission?.text && (
<button
onClick={() => {
setBusy(true);
void controller
.submit(request.admission!.text!, { retryOf: request._camino.ref.object })
.catch((error) => setError(String(error)))
.finally(() => setBusy(false));
}}
disabled={busy}
>
Try again with current settings
</button>
)}
{p.status === "failed" && p.rawOutput && (
<details>
<summary>Returned output</summary>
<pre>{p.rawOutput}</pre>
</details>
)}
{details !== undefined && (
<details open>
<summary>Captured request and execution</summary>
<pre>{JSON.stringify(details, null, 2)}</pre>
</details>
)}
{error && <p role="alert">{error}</p>}
</footer>
);
}
export function ThreadView({
controller,
thread,
profiles = {},
workspace = false,
defaultProfile = "balanced",
allowRepair = false,
renderWidget,
renderItem,
}: {
controller: ThreadController;
thread: string;
profiles?: Profiles;
workspace?: boolean;
defaultProfile?: string;
allowRepair?: boolean;
renderWidget?(item: Item): React.ReactNode;
/** Return undefined for normal rendering; null hides an item. */
renderItem?(item: Item, request: Request): React.ReactNode | undefined;
}) {
const state = useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot),
[draft, setDraft] = useState(() => sessionStorage.getItem(draftKey(thread)) ?? ""),
[busy, setBusy] = useState(false),
[error, setError] = useState(""),
[profile, setProfile] = useState(() => sessionStorage.getItem(`${draftKey(thread)}:profile`) ?? ""),
[response, setResponse] = useState(""),
[repair, setRepair] = useState(false),
[latest, setLatest] = useState(true),
[now, setNow] = useState(Date.now()),
scroll = useRef<HTMLDivElement>(null),
previousSize = useRef(0);
useEffect(() => {
const timer = setInterval(() => setNow(Date.now()), 1000);
return () => clearInterval(timer);
}, []);
useEffect(() => {
sessionStorage.setItem(draftKey(thread), draft);
}, [thread, draft]);
useEffect(() => {
if (latest && scroll.current) scroll.current.scrollTop = scroll.current.scrollHeight;
}, [state.items, latest]);
const active =
(state.thread?.active &&
state.requests.find(
(request) =>
request._camino.ref.object === state.thread!.active!._camino.ref.object &&
!terminal.has(request.progress.status),
)) ??
state.requests.find((request) =>
["running", "waiting_input", "stopping", "parked"].includes(request.progress.status),
),
pending = state.requests.filter((request) => !terminal.has(request.progress.status)),
archived = state.thread?.data.archived;
const run = async (steer = false) => {
if (!draft.trim() || busy) return;
setBusy(true);
setError("");
const text = draft;
try {
if (steer && active)
await controller.control({
kind: "steer",
request: active._camino.ref.object,
attempt: active.progress.attempt,
generation: active.progress.generation,
text,
});
else
await controller.submit(text, {
...(profile ? { profile } : {}),
...(response ? { response: { kind: response } } : {}),
repair: state.maintenance && repair,
});
setDraft((current) => (current === text ? "" : current));
} catch (error) {
setError(String(error));
} finally {
setBusy(false);
}
};
const selected = profile || defaultProfile;
const route = profiles[selected];
const standard = route?.standardProfile ?? selected;
const changeProfile = async (next: string) => {
setProfile(next);
sessionStorage.setItem(`${draftKey(thread)}:profile`, next);
if (active?.progress.status !== "running" || state.maintenance) return;
setBusy(true);
setError("");
try {
await controller.control({
kind: "steer",
request: active._camino.ref.object,
attempt: active.progress.attempt,
generation: active.progress.generation,
text: "",
profile: next,
});
} catch (error) {
setError(String(error));
} finally {
setBusy(false);
}
};
const grouped = new Map<string, { request: Request; items: Item[] }>();
for (const item of state.items) {
const key = item.request._camino.ref.object,
group = grouped.get(key) ?? { request: item.request, items: [] };
group.items.push(item);
group.request = item.request;
grouped.set(key, group);
}
for (const request of pending)
if (!grouped.has(request._camino.ref.object)) grouped.set(request._camino.ref.object, { request, items: [] });
return (
<section className="agent-thread" aria-label="Agent conversation">
<div className="agent-thread-status" role="status">
{state.loading
? "Loading thread…"
: state.maintenance
? "Workspace graph unavailable. Known activity remains visible."
: state.connected
? "Connected"
: "Reconnecting…"}
{active?.progress.startedAt && (
<span> · Working for {Math.max(0, Math.floor((now - Date.parse(active.progress.startedAt)) / 1000))}s</span>
)}
</div>
<div
className="agent-thread-history"
ref={scroll}
onScroll={() => {
const element = scroll.current!;
setLatest(element.scrollHeight - element.scrollTop - element.clientHeight < 80);
}}
>
{state.pageInfo?.hasNextPage && (
<button
onClick={() => {
const element = scroll.current!,
height = element.scrollHeight;
previousSize.current = height;
setLatest(false);
void controller
.refresh(true)
.then(() =>
requestAnimationFrame(() => {
element.scrollTop += element.scrollHeight - previousSize.current;
}),
)
.catch((error) => setError(String(error)));
}}
>
Load earlier messages
</button>
)}
{grouped.size === 0 && !state.loading && (
<div className="agent-empty">
<h2>A new conversation</h2>
<p>Send a message or a task to this Agent.</p>
</div>
)}
{[...grouped.values()].map(({ request, items }) => (
<article className="agent-request" key={request._camino.ref.object}>
<div className="agent-request-source">
{request.admission?.sourceLabel ?? "Agent request"} ·{" "}
{request.admission?.createdAt && (
<time dateTime={request.admission.createdAt}>
{new Date(request.admission.createdAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
</time>
)}
</div>
{items.map((item) => {
const custom = renderItem?.(item, request);
return (
<React.Fragment key={itemKey(item)}>
{custom !== undefined ? (
custom
) : item.data.kind === "steering" && item.data.activity ? (
<aside className="agent-routing-change" role="status">
Model profile · {JSON.parse(item.data.activity).profile} ·{" "}
{item.data.control?.status === "accepted"
? "Applied to subsequent inference"
: item.data.control?.status === "rejected"
? "Change rejected by Codex"
: item.data.control?.status === "uncertain"
? "Change outcome uncertain"
: "Changing…"}
{item.data.control?.reason && <p>{item.data.control.reason}</p>}
{item.data.text && <p>{item.data.text}</p>}
</aside>
) : item.data.kind === "activity" ? (
<Activity item={item} />
) : item.data.kind === "widget" ? (
<div className="agent-widget">
{renderWidget ? (
renderWidget(item)
) : (
<p>
Widget unavailable in this view.{" "}
<a href={`/entity/${encodeURIComponent(item.subject?._camino.ref.object ?? "")}`}>
Open object
</a>
</p>
)}
</div>
) : item.data.kind === "status" ? (
<aside className="agent-status-card">
{item.data.text}
<Activity item={item} />
</aside>
) : item.data.phase === "commentary" ? (
<details className="agent-commentary">
<summary>Agent commentary</summary>
<Markdown text={item.data.text} />
</details>
) : request.admission?.responseKind === "json" && item.data.kind === "assistant" ? null : (
<div className={`agent-message agent-message-${item.data.kind}`}>
{item.data.kind === "assistant" ? <Markdown text={item.data.text} /> : item.data.text}
</div>
)}
</React.Fragment>
);
})}
{(request.questions?.entries ?? []).map(({ node }) => (
<QuestionForm key={node._camino.ref.object} question={node} request={request} controller={controller} />
))}
<RequestCard request={request} controller={controller} inspection={!workspace} />
</article>
))}
</div>
{!latest && (
<button
className="agent-jump"
onClick={() => {
setLatest(true);
if (scroll.current) scroll.current.scrollTop = scroll.current.scrollHeight;
}}
>
Jump to latest
</button>
)}
<form
className="agent-thread-composer"
onSubmit={(event) => {
event.preventDefault();
void run();
}}
>
{state.maintenance && allowRepair && (
<label>
<LocalInput type="checkbox" checked={repair} onChange={(event) => setRepair(event.target.checked)} />
Source repair in the Workspace thread
</label>
)}
<label className="agent-compose-label">
Message
<LocalTextArea
aria-label="Message"
rows={3}
value={draft}
disabled={archived || busy}
onChange={(event) => setDraft(event.target.value)}
onKeyDown={(event) => {
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
event.preventDefault();
void run();
}
}}
/>
</label>
<div className="agent-compose-actions">
{workspace && Object.keys(profiles).length > 0 && (
<div className="agent-model-controls">
<label>
Model
<LocalSelect
aria-label="Model"
disabled={busy}
value={standard}
onChange={(event) => {
const name = event.target.value;
void changeProfile(
route?.standardProfile && profiles[name]?.fastProfile ? profiles[name].fastProfile! : name,
);
}}
>
{Object.entries(profiles)
.filter(([, p]) => !p.standardProfile)
.map(([name, p]) => (
<option key={name} value={name} disabled={p.available === false}>
{p.description ?? p.model ?? name}
</option>
))}
</LocalSelect>
</label>
<label>
<LocalInput
type="checkbox"
aria-label="Fast mode"
checked={!!route?.standardProfile}
disabled={busy || !(route?.fastProfile || route?.standardProfile)}
onChange={(event) =>
void changeProfile(event.target.checked ? route!.fastProfile! : route!.standardProfile!)
}
/>
Fast
</label>
{active?.progress.status === "running" && <small>Changes apply between inference steps.</small>}
</div>
)}
<details>
<summary>Next request options</summary>
<label>
Profile
<LocalSelect aria-label="Profile" value={profile} onChange={(event) => setProfile(event.target.value)}>
<option value="">Agent default</option>
{Object.keys(profiles).map((value) => (
<option key={value} disabled={profiles[value].available === false}>
{value}
</option>
))}
</LocalSelect>
</label>
<label>
Response
<LocalSelect aria-label="Response" value={response} onChange={(event) => setResponse(event.target.value)}>
<option value="">Agent default</option>
<option value="text">Text follow-up</option>
<option value="unit">Actions only</option>
</LocalSelect>
</label>
</details>
<span>{pending.length ? `${pending.length} outstanding request${pending.length === 1 ? "" : "s"}` : ""}</span>
{active?.progress.status === "running" && !state.maintenance && (
<button type="button" disabled={!draft.trim() || busy} onClick={() => void run(true)}>
Steer current
</button>
)}
<button disabled={!draft.trim() || busy || archived || (state.maintenance && !(allowRepair && repair))}>
{busy ? "Sending…" : state.maintenance ? "Submit source repair" : pending.length ? "Send to queue" : "Send"}
</button>
</div>
{archived && <p>This thread is archived. Reopen it to send a message.</p>}
{(error || state.error) && (
<p role="alert">
{error || state.error}{" "}
<button type="button" onClick={() => void run()}>
Retry retained submission
</button>
</p>
)}
</form>
</section>
);
}