Watch
0
0
Fork
You've already forked hyperhive
0
Commit graph hyperhive/docs/swarm/ui.md
Author SHA1 Message Date
iris
30ba34f411 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.
2026-10-18 15:59:19 +02:00
iris
f0a6d6c042 swarm-ui: add a button to the alerts page that shows the pending, no-data and error instances
The page opens on the firing ones. The button lists every instance again,
with the state filter and the tones back, so the table's filtering is
visible. The saved-filters key goes back to its original name, since the
state column is a filter again.
2026-10-18 13:29:52 +02:00
iris
842b37dc33 swarm-ui: show only firing alerts on the alerts page and link to Grafana's list
The page listed every non-normal instance. It now keeps the ones in the
Alerting state and links to Grafana's alert-groups view for the pending,
no-data and error ones.
2026-10-18 13:29:52 +02:00
iris
b5d2e310ba swarm-ui: an editor for an agent's AGENTS.md that saves as a diff
The instructions row of the agent detail panel gets an edit button that
opens the agent's AGENTS.md, as the harness last published it, in a text
box. Save sends a unified diff against the revision that was loaded; when
the agent changed the file meanwhile the editor keeps the operator's text,
shows the agent's version and offers to save over it or take it. An unsaved
edit survives closing the dialog.

The diff is built in the browser (LCS over lines, three lines of context,
git's no-newline marker) and was checked against git apply on 600 random
before/after pairs.
2026-10-18 13:17:52 +02:00
atlas
d9c586ef94 swarm-controller: replay a subagent's newest rows before its live tail
A subagent's terminal opened directly showed nothing until the subagent
published again: the relay was a core subscription, though its rows sit
in term-sub-<agent> for 24 hours. It now goes through the agent route's
replay-then-tail, so it opens with the subagent's newest 100 rows and
resumes after Last-Event-ID.

- term_stream.rs: the replay takes a stream name and a filter subject
  instead of an agent, and `replay_or_live` (replay, else the live core
  subscription) is the one fn both routes call. When the filter is one of
  several subjects in the stream, a fresh reader's consumer starts at the
  oldest row and drops all but the newest REPLAY_ROWS it counts as
  pending, since the stream's newest sequences may belong to sibling
  subagents. A single-subject stream (term-main-<agent>) picks its start
  with replay_start exactly as before. Tests for both subagent cases.
- subagent_term.rs: the relay calls replay_or_live on the subagent's
  subject in term-sub-<agent> and reads Last-Event-ID; module doc and
  OpenAPI text no longer say "live only".
- main.rs: the handler test passes the new headers argument.
- swarm-queue-client agent_term.rs: replay_consumer_config takes the
  filter subject instead of the agent.
- swarm-queue-client subagent_term.rs: consumer_create_grant, the
  extended CONSUMER.CREATE form with a subagent subject as filter.
- swarm-nats-auth policy.rs: the controller holds that grant; the agent
  grant's `$SWARM.term.*` filter is two tokens short of a subagent
  subject, and the test that refused it now admits it.
- docs/swarm/ui.md, README.md: a subagent terminal opens with its newest
  rows.

Fixes #5527
2026-10-18 03:00:08 +02:00
iris
f65364759f swarm-ui: retrying a broadcast shows the agents that failed, even ones the filter hides 2026-10-18 02:40:10 +02:00
iris
89b20a5a50 swarm-ui: a broadcast page that sends one message to several agents
Pick agents from a grid of their icons (running or all), type the text, send.
The page posts the names and the text to the controller and shows what
happened to each agent, with a retry that selects just the ones that failed.
The selection rules and the controller's answer are read by plain functions
with tests.
2026-10-18 02:40:10 +02:00
atlas
484a9fd4c1 swarm-controller: send one operator message to several agents
The swarm UI's broadcast page (#5524) needs the controller to do the
fan-out, so POST /api/agents/broadcast takes {agents, body} and answers
200 with {results: [{agent, sent, reason?}]} in request order.

- agent_input.rs: the single-agent send is now send_one, which both
  routes call; the single route maps its outcome to the same statuses
  and texts as before. The broadcast validates the whole request first
  (sender, empty body, empty or duplicated agents, more than 64, a name
  outside the roster), then sends up to 16 at once with the single
  route's no-responders window.
- main.rs: wires the route.
- docs/swarm/ui.md: describes the route next to the single-agent one.
2026-10-18 01:49:03 +02:00
iris
664409c87f swarm-ui: a running-subagents menu in the full-screen terminal header
An N running subagents badge opens a list of the agent's subagents, each a
link to its terminal, so you can switch without going back to the agents page.
A subagent counts as running when it published a row in the last 15 minutes;
the quiet ones are listed below it, dimmed. The list under the preview and the
menu now share one fetch hook and one definition of running.
2026-10-18 01:46:49 +02:00
iris
0e77d61a9f swarm-ui: a builds page for the swarm builder's runs, and the status links to it
/builds lists the builder's recent builds newest first, one card each with how
it ended, and opens a failed build's nix tail. /builds?run=<id> opens that
build's card and scrolls to it. The swarm-builder commit status now links
there instead of to the raw JSON record.
2026-10-18 01:26:45 +02:00
atlas
51035eac1d 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
2026-10-17 12:57:20 +02:00
atlas
8e09f8360a drop option renames and removals older than two weeks
Refs #5379
2026-10-16 22:04:57 +02:00
atlas
1302288474 swarm-ui: package option moves to deploy.swarm-controller.ui.package
The swarm UI has no switch of its own since it runs wherever the
controller runs; its package option follows it under
deploy.swarm-controller.ui. deploy.swarm-ui.package and
swarm.ui.package stay as renames and warn at evaluation. The flake's
default, the vhost root and the module-eval stub use the new path.
2026-10-16 00:35:16 +02:00
damocles
8bf53f7ed9 swarm-ui: start page setup assistant offers to create ruth 2026-10-15 20:20:05 +02:00
atlas
f0844f6da3 agent permissions: one set, tool groups included, set at agent creation
mara on #5170: "dont split caps and perms. its all perms. / dont include
the now empty tool groups / nothing set -> default / also add perms to
agent creation screen".

- hive-sh4re: one `Permission` enum (messaging, meta, inbox, execution,
  web_tools, manage_root_agent) replaces `ToolGroup` and `Capability`;
  `lifecycle`/`forge` are gone. `Permission::default_for` is the default
  for an agent the swarm sets nothing for.
- The record is `{ "permissions": [...] }`. Missing key, unset field or
  no successful read yet = default; `[]` = none; a failed read after a
  good one keeps the last value.
- hive-agent reads its own key every 10s and builds each turn's --tools,
  --allowedTools and MCP config (rewritten before every turn) from it;
  the subagent daemon reads it on each start/continue. Agents get a
  read-only grant on their own key.
- hive-c0re restarts an agent only when its manage_root_agent changes.
  The import now merges meta/capabilities.json and meta/tool-groups.json
  into one list per agent and deletes both; the "import pending, don't
  read" decision is `ImportOutcome::read_allowed`, table-tested.
- swarm-controller: `GET /api/permissions` (names + default) and an
  optional `permissions` on `POST /api/agents`, stored before the job is
  queued. swarm-ui's create-agent form gets a permissions field.
- Deleted: HIVE_TOOL_GROUPS and its forward to the subagent daemon,
  tool_groups.rs, ruth's tool-group seed, the permissions rebuild job
  (PermPayload/WritePermFile/perm_change), the dashboard permissions tab
  and its stale-entries panel.

Part of #5170.
2026-10-15 18:01:40 +02:00
atlas
7d09776742 swarm UI: an alerts page, read by the controller with a Viewer Grafana token from bao
swarm-bao-grafana-controller-token, on the host that runs Grafana, logs in
to Grafana's API over its socket as the built-in admin (the password
swarm-bao-grafana-admin minted, #5138) and keeps a `swarm-controller`
service account that is an enabled Viewer. It mints a token for that
account and writes it to bao at
swarm/controller/swarm-controller/grafana/token under Grafana's leaf. A
ten-minute timer runs it again. The unit keeps a stored token Grafana
accepts. If Grafana refuses the stored token with 401, or bao holds
none, the unit deletes every token of the account and mints a new one.
Grafana's grant gains create/read/update on that leaf, and the
controller's gains read.

swarm-controller serves GET /api/alerts from Grafana's
/api/prometheus/grafana/api/v1/alerts. It reads the token from bao,
keeps it in memory, and re-reads bao once on a 401. The HTTP client has
5s connect and 15s request timeouts. Any failure is a 503 that names its
cause. swarm-ui gets an /alerts page listing them, built the same way as
the hives page.

This is option (c) on #5129, the operator's choice.
2026-10-15 15:16:21 +02:00
iris
37c91eb916 Roll back stored settings when a creation fails, and keep form ids unique
create_agent puts back the caps and inference settings it replaced if a
later store or the job insert fails, so a refused creation leaves nothing
behind for the name. The shared field components take an id prefix so the
create dialog and an open editor never share a DOM id. The queue check now
follows the hive roster check, the 422 is documented, and the copy says
empty rather than closed and that destroy keeps stored settings.
2026-10-15 13:47:14 +02:00
iris
e36a15de91 Set resource caps and inference when creating an agent
POST /api/agents takes optional limits and inference objects, checked by
the same rules as the two PUT routes before anything is queued and stored
ahead of the job graph. The create form gets collapsed sections for both,
reusing the fields of the detail-panel editors.
2026-10-15 13:47:14 +02:00
atlas
d5de1e4943 swarm UI: log an agent into claude from its card; the credentials go to bao and the agent picks them up
A new swarm service, `swarm-claude-login`, in its own container on the host
that sets `deploy.claude-login.enable` (defaulted on by `allSwarmServices`
where the host has the minter's store leaf, like the review classifier).

- swarm-ui: an agent card showing "login needed" gets a "log in" button.
  Its dialog starts the login, shows the URL claude printed, and takes the
  pasted code.
- swarm-controller: `POST/DELETE /api/agents/{name}/claude-login` and
  `POST /api/agents/{name}/claude-login/code`, behind the swarm UI's
  authelia-gated `/api/`, relay the steps to the minter as requests on
  `$SWARM.claude-login.request`.
- swarm-claude-login: runs `claude auth login` over piped stdio with HOME
  and CLAUDE_CONFIG_DIR in a per-login scratch dir, scrapes the first
  https URL, writes the code to stdin, and stores the `.credentials.json`
  at `swarm/agents/<agent>/claude-credentials` with a KV v2 write, a new
  version over any earlier one. The scratch dir goes on every exit path; a
  login waits 15 minutes for its code.
- hive-agent: while parked in `wait_for_login`, reads that leaf every 30 s
  under the agent's own cert and installs it only when its KV version is
  newer than the one recorded in `<harness>/claude-credentials-version`.
  An equal or older version is never put back, because claude rotates the
  refresh token and the stored copy is stale after the first refresh.
- swarm-secret-client: `claude_login` paths and `SecretStore::read_versioned`.
- Credentials: a `claude-login` store leaf minted by glue-bao-tls, a
  `swarm-claude-login` policy (create/update on
  `swarm/agents/+/claude-credentials`, read on its own queue client
  secret), an authelia machine client, and a `--claude-login-client`
  grant in the queue's auth-callout responder. The unit runs as a static
  system user.

The hive's own web-UI login is unchanged.

Refs #5268
2026-10-15 13:26:29 +02:00
damocles
fefc565794 swarm: cancel an agent's turn from the swarm queue
A separate $SWARM.control.<agent> subject carries commands, apart from
the text subject. swarm-controller exposes POST /api/agents/{name}/cancel
as a NATS request; the harness answers whether a turn was actually
stopped, through the same cancel path as the dashboard button. The agent
credential gets subscribe on its control subject and allow_responses to
answer; only the controller may publish there.

Refs #3803
2026-10-15 08:26:46 +02:00
atlas
3931a40e30 docs: the try-out page lists a row's fields, the posted review folds them into four; the README names the 350-character ask 2026-10-15 08:26:26 +02:00
iris
5b49e0e539 swarm ui: a contraction in the review section of the UI doc 2026-10-15 03:38:48 +02:00
iris
a68d73fa74 swarm ui: one review page
The two review tabs, runs and try-out, are one: /review. It is a column of
three sections: try a classification and the classifier settings, each a
folded bar (the settings' bar says what they are now), then the recent runs,
always open. The settings had been pinned under the try-out form; they are now
a section of their own. A new Disclosure primitive is the folding bar, a
native details wearing the Panel's classes, so the folded and open sections
read as the same surface.

/review-runs and /review-tryout are gone, with no redirect.
2026-10-15 03:38:48 +02:00
atlas
4a9acd1d0c authelia: a user outside a rule's group is denied instead of falling through to one_factor
authelia takes the first matching rule, and a rule with a `subject` does
not match a subject outside it. The swarm domain's and the bao UI's
`group:admins` rules had nothing after them, so an account in no group
skipped them and landed on `default_policy = one_factor`: any
authenticated account reached the swarm UI, its `/api/` (by cookie or by
bearer) and the bao UI.

Each of the two group rules is now an `operatorsOnly` pair: the group
allow, then a subject-less `deny` for the same domain, the shape
`collectorOnly` already gives the collector's metrics rules.
`default_policy` stays `one_factor`, which the forge and chat rely on.

module-eval-swarm-otel-identity gains two cases on `allLocal`: an
account in no group is refused the swarm domain (four paths) and the bao
UI while `group:admins` passes and the forge stays open; and a
predicate, `autheliaSubjectRulesClosed` in lib.nix, holds over the
rendered list: every subject-scoped allow is closed by a later
subject-less `deny` on its domain with no subject-less allow in between,
and nothing follows a domain-wide `deny` on its domain.

Fixes #5120
2026-10-14 23:41:13 +02:00
atlas
afeb0f9794 swarm UI: an agent that needs a Claude login shows it on its card
The agent's turn-state header ($SWARM.agent-state.<agent>) gains
`needs_login`, set by hive-agent from its own LoginState, so the flag
reaches the swarm without hive-c0re (mara on #5268: "id prefer the agent
container sending the info it needs login without hive").

- swarm-queue-client: `agent_login::Login`, the shared wire type, beside
  `agent_inference::Effective`. `needs_login: Option<bool>` with
  `#[serde(default)]`: a header from an older agent decodes as `None`
  (unknown), never as "needs login" or "logged in".
- hive-agent: the header publisher reads the shared LoginState cell.
  Every writer of that cell emits a status on the bus afterwards, so a
  login change goes out on the next rebuild, not the 60 s refresh.
- swarm-controller: `agent_login::Reported` follows every agent's header
  and keeps the latest flag; `GET /api/agents/status` merges it into each
  row as `needs_login` (null when unknown).
- swarm-ui: AgentCard shows a warning-tone "login needed" badge when the
  row's `needs_login` is true.

Refs #5268
2026-10-14 20:07:46 +02:00
iris
417125b33c swarm-ui: a start page at / and the hive directory at /hives
/ is now the swarm's name over the digital-rain backdrop the hive
dashboard's home has, and the swarm name in the header links to it. The
hive directory moves to /hives, where the nav's hives tab points. The
swarm name is read once per page load by a shared hook, the header and
the start page both use it. Closes #5252
2026-10-14 18:36:52 +02:00
atlas
49b15e7775 review try-out: open a PR with the classifications on the page
The try-out page gets an "open a PR" button. It posts the page's
classifications to the new POST /api/review-classifier/open-pr, which
merges them by name into the repo's rules file on the default branch
and has the review-classifier forge account commit the result on a new
branch, review-classifier/<user>-<8 hex>, through the contents API. The
commit's author is the forge account named like the session's
Remote-User, read with the controller's admin token. The answer links
to the forge's compare page, where the user opens the PR as themselves.

The push uses the account's existing token from the store
(swarm/services/review-classifier/forge/token, scope write:repository),
so the account needs write access to the repo; a refused push answers
403 naming that. In a YAML rules file, the entries the merge leaves
alone keep their text, as long as the result reads back as the merged
list; otherwise the file is written out whole.

DefaultBranchFiles now carries each file's blob sha, which the forge
needs to replace a file, and the repo's web URL for the link.

Fixes #5259
Refs #5096
2026-10-14 18:36:36 +02:00
iris
a04096ea19 swarm-ui: choose the review classifier's runtime on the settings page
The classifier settings page showed model and effort only, so the API-key
or ACP runtime could be switched only through a raw API call. It now has a
runtime select, and under ACP the provider's URL, model and prices. A PUT
carries the provider only on the ACP runtime, so the stored record stays
for a switch back. Closes #5249
2026-10-14 16:20:37 +02:00
atlas
9a71d1e094 swarm-ui: per-agent cap on concurrently running subagents
Nothing capped how many subagents an agent runs at once; the operator
wants to set that per agent from swarm-ui (#5234, shape (b)).

AgentInference gains `max_subagents: Option<u32>`. An absent field
decodes as None, so every stored value still parses and means "no cap",
which is today's behaviour.

swarm-controller accepts 1..=32 on PUT. 0 would refuse every start; 32
is far more concurrent claude sessions than one agent container has
memory for, so anything above it is a typo, not a cap.

The subagent daemon already read the agent's agent-inference key for
subagent_models; it now reads it on every start and continue (not only
those naming a model) and refuses a new run once the cap's worth of
names is tracked, counted under the same lock as the name reservation.
Every tracked slot counts: running, starting, a goal run between turns,
and an interrupted one still exiting. A goal re-prompt never goes
through the reservation, so it is never refused. A failed read applies
no cap, as it falls back for models.

swarmctl's `inference set` does GET, merge, PUT; its mirror type now
carries the field so a set from the CLI keeps a cap set in swarm-ui
instead of dropping it, and `get` prints it.
2026-10-14 10:13:29 +02:00
atlas
44346d8c6c nix: warn on the ignored swarm-ui switches instead of failing eval
deploy.swarm-ui.enable and swarm.ui.enable are declared again as
nullOr bool, default null, and do nothing. Setting either adds an eval
warning that swarm-ui now runs wherever swarm-controller runs.
2026-10-13 20:05:19 +02:00
atlas
f9954b91b4 nix: run swarm-ui wherever swarm-controller runs
Remove deploy.swarm-ui.enable. Every reader (the swarm-ui vhost, the
authelia operator rule for the swarm apex, hive-network's
anyServiceEnabled) now reads deploy.swarm-controller.enable, and the
controller's webhook public URL is gated on the swarm domain alone,
since the vhost it names exists wherever the daemon does.

Both spellings of the old switch (deploy.swarm-ui.enable and the
already-renamed swarm.ui.enable) become mkRemovedOptionModule entries,
so a host that still sets either fails evaluation with a message
naming the controller toggle instead of silently changing.

Ruling (mara, #3742): "swarm-ui always runs wherever controller runs".

Part of #3742
2026-10-13 20:05:19 +02:00
iris
baf282131f swarm-ui: the review try-out page shows and changes the review classifier's settings
A classifier settings panel under the try-out form reads and saves the model,
effort and how many requested reviews run at once through the settings route.
A save replaces all three; a refused one shows the route's reason and leaves
the form as typed. There is no API key field.
2026-10-13 12:24:47 +02:00
iris
57407cb437 swarm-ui: the resource caps dialog says when a change takes effect
The hive reads the caps about every 30 seconds and a running agent takes a
changed cap at its next spawn or rebuild, so the dialog and the ui doc no
longer say the hive applies a change within seconds.
2026-10-13 09:01:31 +02:00
iris
a376714116 swarm-ui: an agent's detail shows its resource caps and edits them
A resource caps row in the agent details reads GET /api/agents/{name}/limits
and shows the cpu quota and memory max, each reading as the hive deciding
when the swarm sets none. An edit dialog PUTs the filled fields, which
replaces the stored value whole, and a clear action DELETEs it. A refusal,
such as a percentage with a leading zero, shows as the route's reason under
the fields and leaves them as typed.
2026-10-13 09:01:31 +02:00
iris
5193a101a6 swarm-ui: a review runs page lists the review classifier's recent runs
One card per run, newest first, from GET /api/review-classifier/runs: repo,
PR, head commit, trigger, when, how long, how many classifications and the
outcome as a badge. A card opens to the try-out's result table, the overall
verdict, the reason and the posted review's link. TryOutResult takes the
answer it shows rather than a whole try-out result, and its styles move to
their own file.
2026-10-12 23:21:38 +02:00
iris
be6036b216 swarm-ui: a hide debug output toggle in the header's settings menu
The row moves from the per-agent page into @hive/shared so both pages mount
the same one. The terminal's debug rows now follow the preference as it
changes, so rows already on screen hide or show at once instead of only the
rows that arrive after the toggle.
2026-10-12 21:41:23 +02:00
iris
9a4059e130 swarm-ui, swarm-controller: the review try-out's repo and PR fields offer the repos and PRs to pick
Two read-only routes feed them: GET /api/pulls/repos lists the repos with an
open pull request, and GET /api/pulls?repo=owner/name lists a repo's open
pull requests, highest number first. The page offers the lists through the
browser's own suggestion list and keeps both fields free text, since a run
also works on a merged or closed PR.
2026-10-12 19:05:37 +02:00
iris
cf4c4cde87 swarm-ui: load a repo's rules into the review try-out
A button beside the repo field reads the repo's rules from its default branch into the classification rows, names the file and the commit it read, asks before replacing rows the operator wrote, and shows the route's error without touching the rows.
2026-10-12 15:01:23 +02:00
iris
c5b66dc5a0 swarm-ui: match the try-out page to the backend's limits
The repo check takes the endpoint's own character set and refuses . and .. parts. The running and expired messages say a run can last up to half an hour and that a controller restart drops the result.
2026-10-12 14:51:38 +02:00
iris
a4a4381cf6 swarm-ui: try-out rows keyed by position, distinct names, and accurate storage wording
Two classifications sharing a name made the result table's row key collide, so the form now refuses duplicate names and the table keys rows by position anyway. The page said it stores nothing in the browser, but the result table remembers its column filters like every table does; the header comment and the docs now say that. The row cap's comment says to keep it in step with the endpoint's own cap.
2026-10-12 14:51:38 +02:00
iris
b67517e41b swarm-ui: a review try-out page
A page to try a review classification against a real PR: repo, PR number and one or more classifications (name, description, polarity, threshold). Run posts to the controller's try-out endpoint and polls until the run is done or failed, saying it is running meanwhile, then shows the review's table, the overall verdict and the head commit. A row that could not run shows its error in place of a reason, and a failed run shows its error. The inputs stay so the run can be edited and repeated. Nothing is stored and nothing is posted to the forge. Route, nav entry and a section in docs/swarm/ui.md.
2026-10-12 14:51:38 +02:00
iris
afa9d861ba docs: swarm UI popover wording without the input-specific verb 2026-10-12 00:19:33 +02:00
iris
f957e19d0d swarm-ui: show an agent's details in a popover, not a modal dialog
The details open under the agent badge without dimming or blocking the page; a click outside or Escape closes it. New ui/popover primitive (anchored, portal, no backdrop) with a sample on the components page. A confirm or link dialog opened from inside it stays modal, and the popover ignores clicks and Escape that belong to that dialog. AgentDetailDialog becomes AgentDetailPopover.
2026-10-12 00:19:33 +02:00
iris
103c842890 swarm-ui: open an agent's details in a dialog from its terminal tab
The terminal page gets an agent badge (icon and name) that opens the agent's detail panel in a dialog over the terminal, without the terminal preview. The panel body and the actions on an agent (declare a wanted state, link an account, with their confirm and form dialogs) move out of the agent roster page into AgentDetail and useAgentActions, so the roster and the dialog share them. AgentIcon moves to its own file for the same reason.
2026-10-12 00:19:33 +02:00
iris
9761ffa24a swarm-ui: a terminal tab takes its agent's icon as the browser-tab icon
The agent terminal page swaps the page's favicon for the agent's icon while it is mounted, so tabs of different agents tell apart. A subagent terminal shows its agent's icon. An agent with no icon, or an unreachable controller, keeps the hyperhive mark; leaving the page restores the page's own icon.
2026-10-12 00:18:10 +02:00
atlas
f08a9cadb6 swarm-controller: end a dead replay, clamp stale resume ids, test on a real server
A replay consumer now has a 5s idle heartbeat, and the row stream ends at
the first consumer error instead of skipping it. When the server drops the
consumer, as on a restart, two missed heartbeats end the SSE response and
the browser reconnects with Last-Event-ID. Before, the response stayed
open and delivered nothing.

A Last-Event-ID above the stream's newest sequence now replays as a fresh
reader. The server accepts a start past the end and delivers nothing
until the stream reaches it, so a stale id stalled the replay.

swarm-controller's stream tests run against a real nats-server on
loopback (`test_nats`, binary from HIVE_NATS_SERVER, exported by
checks.nix and devshell.nix). They cover: ensuring the stream twice, an
existing stream with other limits being opened as it is, the replay
arriving before live rows, a reconnect getting every later row exactly
once, and a dropped consumer ending the row stream.

The limits test now compares against the subagent stream's own config.
Two comments that described the agent's terminal route as live-only are
corrected.
2026-10-11 23:26:24 +02:00
atlas
ae9ca4331e swarm: keep an agent's terminal rows and replay them on attach
swarm-controller now creates `term-main-<agent>` for every live agent, in
the same one-minute pass and with the same config style as
`term-sub-<agent>` (#4897): subjects `$SWARM.term.<agent>` only, max_age
24h, max_bytes 64 MiB, discard Old, max_message_size from the queue's
max_payload. An existing stream is opened as it is. The agent keeps its
plain publish on `$SWARM.term.<agent>` and gets no JetStream subject.

`GET /api/agents/{name}/term/stream` creates an ephemeral push consumer on
that stream starting 100 rows back, so a swarm-ui terminal opens with
recent history and then follows new rows, in order, from one
subscription. Each SSE event carries the row's stream sequence as its id,
and a reconnect's Last-Event-ID resumes after it. Without the stream the
route falls back to the live core subscription it used before.

The stream is `term-main-<agent>`, not `term-<agent>`: an agent may be
named `sub-x`, whose `term-<agent>` would be agent `x`'s subagent stream.
Its one literal subject cannot match `$SWARM.term.<agent>.sub.>`, which
needs more tokens, so the two streams never overlap.

The reader gains `$JS.API.CONSUMER.CREATE.*.*.$SWARM.term.*`, the
extended create form whose last tokens are the consumer's filter. Checked
against nats-server 2.14.4, the trailing `*` also admits a literal `*` or
`>` filter, so a consumer under it reaches any terminal row, main or
subagent; those are rows the reader already subscribes to and reads with
`STREAM.MSG.GET.*`.

Closes #4826
2026-10-11 12:35:31 +02:00
iris
87aeed32a7 docs: swarm UI inference section in active voice 2026-10-10 18:51:55 +02:00
iris
0d04bd7295 swarm-ui: per-agent inference panel and editor on the agents page
The agent detail panel shows the model and effort an agent runs on with
where each comes from, plus the swarm's subagent model list. An edit
dialog sets the swarm value (PUT) and a clear action removes it (DELETE).
Reads the configured/effective view, and shows the stored values alone
until an agent has reported what it runs on.
2026-10-10 18:51:55 +02:00
atlas
235bc481b3 hive-agent: the swarm queue connection is required; retry, then exit
An agent's harness connects to the swarm queue with the agent's own
credential or not at all. The first connect retries after 5s, doubling
(7 attempts, about five minutes), with a warning per failed attempt;
when every attempt fails the harness logs an error and exits 1. Missing
coordinates (HIVE_AGENT_NATS_URL, or the secret store's BAO_ADDR /
HIVE_AGENT_NAME / certificate) fail the boot outright.

Previously the first connect's outcome was memoized for the life of the
process: a store 403 or queue refusal at boot left the agent on the
hive's shared client, or disconnected, until someone restarted it, and
an agent with no queue coordinates ran on without one. Both paths are
gone, with the hive-scoped subjects that only the shared client used.

The harness unit now restarts after 30s instead of 2s, so a swarm-wide
outage doesn't restart every agent every 2s, and has no start limit, so
it keeps coming back however long the outage lasts.

The hive's shared client credential is still imported into the harness
unit for swarm-logs; the two HIVE_AGENT_OIDC_*_FILE variables that
pointed the harness at it are dropped, as is the unset
HIVE_AGENT_OIDC_CA_FILE override.

With the fallback gone, the pieces #4944 added only for it go too:
swarm_input's skip-on-shared-client branch and swarm-queue-client's
connect_with_inbox_prefix. swarm-nats-auth's grant for the hive's shared
agent client is unchanged.

Closes #4909
2026-10-04 22:24:51 +02:00