An agent's subagent daemon publishes each subagent's output as terminal
rows on `$SWARM.term.<agent>.sub.<subagent>`, as the agent, into a
per-agent stream it creates itself; swarm-controller lists an agent's
subagents from that stream's subjects and relays one subagent's rows as
SSE; the swarm UI lists them under the agent's terminal preview and
reuses AgentTermPreview, full-screen tab included, with no input.
- swarm-nats.nix: the agent token may also publish
`$SWARM.term.{agent}.sub.>` and `$JS.API.STREAM.CREATE|INFO` on
`term-sub-{agent}`, and nothing else of JetStream. A module-eval arm
pins the agent-token grant as an exact list.
- mcp.nix: hive-subagent-daemon loads the agent's store identity
(`hive-agent-bao-cert/-key/-server-ca`, the ones hive-agent loads)
whenever the agent has a store, not only on the opencode preset. The
agent's own queue secret lives in the store, so this is the credential
the harness connects with.
- hive-subagent-mcp: `swarm_term` reads the agent's queue secret under
that identity, connects with the agent token, opens or creates
`term-sub-<agent>` (max_age 24h), and publishes classified rows from
the sink every subagent line already passes through. The sink only
queues (bounded, drop-and-count); a missing store, refused credential,
failed stream create or failed publish is a log line.
- The stream-json classifier (`stream_enrich`) and the `TermMsg` row
types plus `fit` move from the hive-agent binary into hive-sh4re, so
the subagent daemon publishes the rows AgentTermPreview already
renders. hive-agent keeps its LiveEvent classifier on top.
- swarm-controller: `GET /api/agents/{name}/subagents` and
`GET /api/agents/{name}/subagents/{subagent}/term/stream`.
- docs/swarm: what the UI shows and what the queue carries.
Closes #4827
62 lines
3 KiB
TOML
62 lines
3 KiB
TOML
[package]
|
|
name = "swarm-queue-client"
|
|
version.workspace = true
|
|
readme = "README.md"
|
|
edition.workspace = true
|
|
|
|
[features]
|
|
# OFF by default, and that default is the point: the auth-callout responder
|
|
# consumes this crate for the connect alone and speaks neither `jetstream`
|
|
# nor `kv`. A consumer that needs the status bucket says so in its own
|
|
# Cargo.toml, so the requirement stays visible where it is incurred.
|
|
#
|
|
# What is behind the flag is deliberately narrow - the *name and shape* of
|
|
# one bucket two crates open from opposite ends (`src/status.rs`), not a
|
|
# general "KV support" surface. The crate's job still ends at a connected
|
|
# client; the exception exists because an agreement between two crates has
|
|
# to live in one of them, and neither end of that bucket is senior to the
|
|
# other.
|
|
kv = ["async-nats/kv"]
|
|
# 🩸 `jetstream` is NOT in async-nats's default feature set here — the
|
|
# workspace-level dependency turns default features off entirely (see
|
|
# root `Cargo.toml`: `server_2_14`/`nkeys`/`ring` only). `kv` above works
|
|
# standalone only because async-nats's own `kv` feature pulls `jetstream`
|
|
# in transitively; `notices.rs` uses `async_nats::jetstream` directly and
|
|
# needs the same request explicitly, or it only compiles by accident when
|
|
# something else in the same build happens to also enable `kv` (which is
|
|
# exactly how this went unnoticed: `cargo test` at the workspace level
|
|
# unifies features across every crate being built, so `hive-c0re`'s own
|
|
# `kv` request silently carried `notices.rs` until a single-crate
|
|
# `cargo check -p swarm-nats-auth` — no `kv` anywhere in that build —
|
|
# surfaced it as `cannot find jetstream in async_nats`).
|
|
notices = ["async-nats/jetstream"]
|
|
# `subagent_term::open_or_create`, for the one publisher that creates its own
|
|
# stream. Explicit for the same reason as `notices`.
|
|
subagent-term = ["async-nats/jetstream"]
|
|
|
|
[dependencies]
|
|
# Bare (no `kv`/`jetstream`) unless a consumer opts into the `kv` feature
|
|
# above - the connect itself needs none of them.
|
|
async-nats.workspace = true
|
|
# `blocking` on top of the workspace default (`form`/`json`/`rustls`) —
|
|
# `mint_token_for_blocking` needs `reqwest::blocking::Client` for a caller
|
|
# with no tokio reactor to `.await` an async request on (an OTLP exporter's
|
|
# `HttpClient` impl, see that function's doc). Declared here rather than
|
|
# left to arrive transitively from a consumer that happens to pull in
|
|
# `reqwest`'s blocking feature some other way — this crate already has a
|
|
# recorded case of exactly that kind of accidental compile (see the `kv`
|
|
# feature's comment above), and `cargo check -p swarm-queue-client` alone
|
|
# must not depend on what else is in the build.
|
|
reqwest = { workspace = true, features = ["blocking"] }
|
|
rustls.workspace = true
|
|
serde.workspace = true
|
|
serde_json.workspace = true
|
|
strum.workspace = true
|
|
# A library, so its errors are a matchable enum rather than an opaque
|
|
# `anyhow::Error`. The binaries that consume this keep anyhow; `?` converts.
|
|
thiserror.workspace = true
|
|
tokio.workspace = true
|
|
tracing.workspace = true
|
|
|
|
[lints]
|
|
workspace = true
|