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
This commit is contained in:
parent
e7ed28b382
commit
fefc565794
11 changed files with 558 additions and 69 deletions
|
|
@ -8,10 +8,11 @@
|
|||
//! refused rather than sent anonymously.
|
||||
//!
|
||||
//! **Sent as a NATS request** so that an agent with no subscriber is a 503
|
||||
//! instead of text that silently goes nowhere. The agent does not reply: no
|
||||
//! agent grant covers a reply subject. A request that times out therefore
|
||||
//! means a subscriber held the message, and that is all "sent" means. Core
|
||||
//! NATS, no stream: an agent that restarts before its turn loses the text.
|
||||
//! instead of text that silently goes nowhere. The agent does not reply to
|
||||
//! input (it does to a command, see [`crate::agent_control`]). A request that
|
||||
//! times out therefore means a subscriber held the message, and that is all
|
||||
//! "sent" means. Core NATS, no stream: an agent that restarts before its turn
|
||||
//! loses the text.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
@ -119,6 +120,22 @@ pub(crate) async fn post_agent_input(
|
|||
send(&client, &agent, &input).await
|
||||
}
|
||||
|
||||
/// Who the gateway says is asking, or the 401 for a request that did not come
|
||||
/// through it. Shared with [`crate::agent_control`].
|
||||
pub(crate) fn sender(headers: &HeaderMap) -> Result<String, (StatusCode, &'static str)> {
|
||||
headers
|
||||
.get(SENDER_HEADER)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(str::to_owned)
|
||||
.ok_or((
|
||||
StatusCode::UNAUTHORIZED,
|
||||
"no Remote-User header: the gateway names the sender, and this request \
|
||||
did not come through it",
|
||||
))
|
||||
}
|
||||
|
||||
/// The agent and the message, or the refusal. Everything decided before the
|
||||
/// queue is touched.
|
||||
fn message(
|
||||
|
|
@ -126,17 +143,7 @@ fn message(
|
|||
agent: &str,
|
||||
body: String,
|
||||
) -> Result<(String, AgentInput), (StatusCode, &'static str)> {
|
||||
let from = headers
|
||||
.get(SENDER_HEADER)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.map(str::trim)
|
||||
.filter(|s| !s.is_empty())
|
||||
.ok_or((
|
||||
StatusCode::UNAUTHORIZED,
|
||||
"no Remote-User header: the gateway names the sender, and this request \
|
||||
did not come through it",
|
||||
))?
|
||||
.to_owned();
|
||||
let from = sender(headers)?;
|
||||
let agent = hive_types::Ident::parse(agent)
|
||||
.map_err(|reason| (StatusCode::BAD_REQUEST, reason))?
|
||||
.into_string();
|
||||
|
|
|
|||
Loading…
Reference in a new issue