swarm UI: send a message to an agent, without its hive
The agent view in the swarm UI gets a message box. The text reaches the
agent's harness straight from swarm-controller over the swarm queue and
becomes an inbox turn from the operator's authelia username. hive-c0re is
not in the path.
- gateway: `/api/` forwards authelia's `Remote-User`, replacing any the
client sent.
- swarm-controller: `POST /api/agents/{name}/input` takes that header as
the sender (401 without it) and sends `{from, body}` as a NATS request
on `$SWARM.input.<agent>`. No subscriber is a 503.
- swarm-nats-auth: the controller is granted publish on `$SWARM.input.*`;
no hive or agent grant names the family, so the harness can trust
`from`.
- hive-agent: a task subscribes to the agent's own input subject and
pushes each message into the serve loop's existing reminder channel,
renamed `local_msg_*` since it now carries both.
The harness does not reply to the request: no agent grant covers a reply
subject. The controller therefore answers 202 once the request times out
(2s) and 503 on the server's no-responders status.
Closes #4828
This commit is contained in:
parent
5971b51e65
commit
48ac4ac423
13 changed files with 664 additions and 24 deletions
|
|
@ -251,6 +251,36 @@ pub struct DeployRequest {
|
|||
pub rev: Option<String>,
|
||||
}
|
||||
|
||||
/// The subject the swarm controller sends an operator's input for `agent`
|
||||
/// on. That agent's harness subscribes to its own and turns each message into
|
||||
/// an inbox turn.
|
||||
///
|
||||
/// Its own family rather than a leaf under `$SWARM.term.`: every agent on a
|
||||
/// hive's shared credential may publish under `$SWARM.term.<hive>.>`, and the
|
||||
/// harness trusts [`AgentInput::from`] only because the controller is the one
|
||||
/// client granted publish here.
|
||||
#[must_use]
|
||||
pub fn agent_input_subject(agent: &str) -> String {
|
||||
format!("{AGENT_INPUT_SUBJECT_PREFIX}.{agent}")
|
||||
}
|
||||
|
||||
/// The publish grant covering every [`agent_input_subject`], for the one
|
||||
/// client that may send them. A wildcard for the same no-roster reason as
|
||||
/// [`DEPLOY_SUBJECT_WILDCARD`].
|
||||
pub const AGENT_INPUT_SUBJECT_WILDCARD: &str = "$SWARM.input.*";
|
||||
|
||||
/// Shared by [`agent_input_subject`] and [`AGENT_INPUT_SUBJECT_WILDCARD`].
|
||||
const AGENT_INPUT_SUBJECT_PREFIX: &str = "$SWARM.input";
|
||||
|
||||
/// What an [`agent_input_subject`] message carries.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct AgentInput {
|
||||
/// The operator's authelia username, as the swarm gateway reported it.
|
||||
pub from: String,
|
||||
/// The text, verbatim.
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
/// The hive-notices stream, shared by the hive that publishes and
|
||||
/// whatever eventually consumes it. Behind the `notices` feature, same
|
||||
/// reason `status` is behind `kv` — see the module doc.
|
||||
|
|
|
|||
Loading…
Reference in a new issue