archetypes: prefill the create form from flake-declared agent archetypes
A flake declares agent archetypes in its `hyperhiveArchetypes` output,
`<name> = { module; meta; }`. The hyperhive flake ships `reviewer`
(default permissions without `execution`).
swarm-builder answers `$SWARM.builder.archetypes` with the `meta` of
every archetype its own hyperhive source declares. swarm-controller asks
once the queue connects and every 10 minutes, checks each archetype as
`POST /api/agents` checks its settings, and stores the result in the
`agent-archetypes` KV bucket when it changed. `GET /api/archetypes`
serves it, and the create form's archetype select prefills permissions,
resource caps and inference from it.
The agent created is an ordinary agent with its own config repo; the
archetype's module is not applied yet.
Refs #5386
This commit is contained in:
parent
eb92e83c95
commit
51035eac1d
22 changed files with 1244 additions and 30 deletions
|
|
@ -0,0 +1,67 @@
|
|||
// The create-agent form's archetype picker: what a pick puts in the form.
|
||||
// Run by `npm test` with Node's type stripping.
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { archetypeKey, prefill } from "../src/pages/CreateAgentArchetype.ts";
|
||||
|
||||
const defaults = ["messaging", "meta", "inbox", "execution"];
|
||||
|
||||
const empty = {
|
||||
permissions: defaults,
|
||||
cpu: "",
|
||||
memory: "",
|
||||
inference: { model: "", effort: "", subagents: "", maxSubagents: "" },
|
||||
};
|
||||
|
||||
test("no archetype is the default permissions and empty settings", () => {
|
||||
assert.deepEqual(prefill(undefined, defaults), empty);
|
||||
});
|
||||
|
||||
test("an archetype's settings fill the form", () => {
|
||||
const reviewer = {
|
||||
source: "hyperhive",
|
||||
name: "reviewer",
|
||||
description: "reviews",
|
||||
permissions: ["messaging", "meta", "inbox"],
|
||||
limits: { cpu_quota: "200%", memory_max: "4G" },
|
||||
inference: {
|
||||
model: "opus",
|
||||
effort: "high",
|
||||
subagent_models: ["haiku", "sonnet"],
|
||||
max_subagents: 0,
|
||||
},
|
||||
};
|
||||
assert.deepEqual(prefill(reviewer, defaults), {
|
||||
permissions: ["messaging", "meta", "inbox"],
|
||||
cpu: "200%",
|
||||
memory: "4G",
|
||||
inference: {
|
||||
model: "opus",
|
||||
effort: "high",
|
||||
subagents: "haiku, sonnet",
|
||||
maxSubagents: "0",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("an archetype that sets nothing leaves the form as no archetype does", () => {
|
||||
const bare = { source: "hyperhive", name: "bare", description: "d" };
|
||||
assert.deepEqual(prefill(bare, defaults), empty);
|
||||
});
|
||||
|
||||
test("an empty permission list is kept, not replaced by the default", () => {
|
||||
const none = {
|
||||
source: "hyperhive",
|
||||
name: "none",
|
||||
description: "d",
|
||||
permissions: [],
|
||||
};
|
||||
assert.deepEqual(prefill(none, defaults).permissions, []);
|
||||
});
|
||||
|
||||
test("the key tells sources apart", () => {
|
||||
assert.notEqual(
|
||||
archetypeKey({ source: "a", name: "x", description: "" }),
|
||||
archetypeKey({ source: "b", name: "x", description: "" }),
|
||||
);
|
||||
});
|
||||
Loading…
Reference in a new issue