swarm-ui: let the create-agent form set the new agent's initial AGENTS.md
The form gets a collapsed "instructions" section with a plain text box. Its text goes in the optional agents_md field of the create request, and is left out while the box is empty or only whitespace. The controller's size refusal shows under the box instead of in the form's general error panel. The text box empties after a successful create. The send and refusal logic sits in its own module with tests, and docs/swarm/ui.md describes the field.
This commit is contained in:
parent
456cf9a7cb
commit
30ba34f411
5 changed files with 112 additions and 3 deletions
|
|
@ -38,6 +38,7 @@ import {
|
|||
SelectField,
|
||||
type SelectOption,
|
||||
} from "../ui/select-field/SelectField.js";
|
||||
import { TextAreaField } from "../ui/text-area-field/TextAreaField.js";
|
||||
import { Button } from "../ui/button/Button.js";
|
||||
import { capsBody, LimitsFields } from "../agent/detail/AgentLimits.js";
|
||||
import {
|
||||
|
|
@ -60,6 +61,7 @@ import {
|
|||
requestArchetype,
|
||||
type ArchetypeList,
|
||||
} from "./CreateAgentArchetype.js";
|
||||
import { agentsMdBody, agentsMdRefusal } from "./CreateAgentAgentsMd.js";
|
||||
import "./CreateAgentForm.css";
|
||||
|
||||
// Mirrors swarm-controller's `HiveEntry` — same shape `HivesPage`
|
||||
|
|
@ -144,6 +146,8 @@ export function CreateAgentForm({
|
|||
null,
|
||||
);
|
||||
const [archetype, setArchetype] = useState("");
|
||||
// The text the agent's `AGENTS.md` starts with; empty sends none.
|
||||
const [agentsMd, setAgentsMd] = useState("");
|
||||
const picked = archetypes?.archetypes.find(
|
||||
(a) => archetypeKey(a) === archetype,
|
||||
);
|
||||
|
|
@ -211,6 +215,9 @@ export function CreateAgentForm({
|
|||
label: h.name,
|
||||
}));
|
||||
const hivesReady = hives !== null && hives.length > 0;
|
||||
// The controller's size refusal of the AGENTS.md text, shown by its box.
|
||||
const refusal =
|
||||
result.status === "error" ? agentsMdRefusal(result.problem) : null;
|
||||
|
||||
async function submit(e: Event) {
|
||||
e.preventDefault();
|
||||
|
|
@ -232,6 +239,7 @@ export function CreateAgentForm({
|
|||
? requestPermissions(selected, catalogue.default)
|
||||
: undefined,
|
||||
archetype: requestArchetype(picked),
|
||||
...agentsMdBody(agentsMd),
|
||||
}),
|
||||
});
|
||||
if (!r.ok) {
|
||||
|
|
@ -241,6 +249,7 @@ export function CreateAgentForm({
|
|||
const data = (await r.json()) as CreateAgentResponse;
|
||||
setResult({ status: "done", nodeId: data.node_id });
|
||||
setName("");
|
||||
setAgentsMd("");
|
||||
pickArchetype("");
|
||||
if (catalogue)
|
||||
setSelected(
|
||||
|
|
@ -258,8 +267,8 @@ export function CreateAgentForm({
|
|||
<p class="create-agent-intro">
|
||||
Create a new agent's swarm-level identity. This only queues the job
|
||||
— check <Link href="/jobs">jobs</Link> to watch it settle. Resource
|
||||
caps and inference are optional; leave them empty to set nothing. A
|
||||
name set up before keeps the settings stored for it.
|
||||
caps, inference and instructions are optional; leave them empty to
|
||||
set nothing. A name set up before keeps the settings stored for it.
|
||||
</p>
|
||||
{hivesError && (
|
||||
<ApiErrorPanel
|
||||
|
|
@ -365,6 +374,22 @@ export function CreateAgentForm({
|
|||
/>
|
||||
</div>
|
||||
</details>
|
||||
<details class="create-agent-section">
|
||||
<summary>instructions</summary>
|
||||
<div class="create-agent-section-body">
|
||||
<TextAreaField
|
||||
id="agent-agents-md"
|
||||
label="AGENTS.md"
|
||||
value={agentsMd}
|
||||
rows={8}
|
||||
placeholder="the text the agent's AGENTS.md starts with; leave empty for none"
|
||||
onInput={setAgentsMd}
|
||||
/>
|
||||
{refusal !== null && (
|
||||
<p class="create-agent-field-error">{refusal}</p>
|
||||
)}
|
||||
</div>
|
||||
</details>
|
||||
<Button
|
||||
variant="primary"
|
||||
type="submit"
|
||||
|
|
@ -384,7 +409,7 @@ export function CreateAgentForm({
|
|||
<Link href="/jobs">watch it in jobs</Link>
|
||||
</p>
|
||||
)}
|
||||
{result.status === "error" && (
|
||||
{result.status === "error" && refusal === null && (
|
||||
<ApiErrorPanel context="failed to queue" problem={result.problem} />
|
||||
)}
|
||||
</Panel>
|
||||
|
|
|
|||
Loading…
Reference in a new issue