pages/agents held the roster page, the terminal page and every component under them. It keeps the two pages; the components move to src/agent, by concern: roster (card, wanted menu, actions), detail (panel body, dialog, inference, linked accounts, link menu) and terminal (preview, input, subagents, stream hooks, favicon), with the shared row type and icon at the top. Moves and import rewrites only.
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
// <AgentInputForm> — text for one agent, under its swarm terminal.
|
|
// POSTs `/api/agents/{name}/input`: 202 once the agent's harness holds the
|
|
// message, 503 when it is not listening, problem+json otherwise. The agent
|
|
// sees it as an inbox turn from the logged-in user (the controller takes the
|
|
// sender from the gateway, not from this request).
|
|
import { useState } from "preact/hooks";
|
|
import { ApiErrorPanel } from "@hive/shared/api-error-panel.js";
|
|
import { readApiError, type ProblemDetails } from "@hive/shared/api-error.js";
|
|
import { TextField } from "../../ui/text-field/TextField.js";
|
|
import { Button } from "../../ui/button/Button.js";
|
|
import "./AgentInputForm.css";
|
|
|
|
type SubmitState =
|
|
| { status: "idle" }
|
|
| { status: "submitting" }
|
|
| { status: "sent" }
|
|
| { status: "error"; problem: ProblemDetails };
|
|
|
|
export function AgentInputForm({ agentName }: { agentName: string }) {
|
|
const [body, setBody] = useState("");
|
|
const [result, setResult] = useState<SubmitState>({ status: "idle" });
|
|
|
|
async function submit(e: Event) {
|
|
e.preventDefault();
|
|
setResult({ status: "submitting" });
|
|
try {
|
|
const r = await fetch(
|
|
`/api/agents/${encodeURIComponent(agentName)}/input`,
|
|
{
|
|
method: "POST",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify({ body }),
|
|
},
|
|
);
|
|
if (!r.ok) {
|
|
setResult({ status: "error", problem: await readApiError(r) });
|
|
return;
|
|
}
|
|
setResult({ status: "sent" });
|
|
setBody("");
|
|
} catch (err) {
|
|
setResult({ status: "error", problem: { detail: String(err) } });
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div class="ui-agent-input">
|
|
<form class="ui-agent-input-form" onSubmit={submit}>
|
|
<TextField
|
|
id={`agent-input-${agentName}`}
|
|
label={`message ${agentName}`}
|
|
value={body}
|
|
required
|
|
onInput={setBody}
|
|
/>
|
|
<Button
|
|
variant="primary"
|
|
type="submit"
|
|
disabled={result.status === "submitting"}
|
|
>
|
|
{result.status === "submitting" ? "sending…" : "send"}
|
|
</Button>
|
|
</form>
|
|
{result.status === "sent" && <p class="ui-agent-input-sent">sent</p>}
|
|
{result.status === "error" && (
|
|
<ApiErrorPanel context="failed to send" problem={result.problem} />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|