Watch
0
0
Fork
You've already forked hyperhive
0

agents: the send(operator) refusal also covers agents without matrix

An agent with no matrix account has no `mcp__matrix__*` tools, so a
refusal that only says "use the matrix MCP tools" points it at something
it cannot call. `OPERATOR_SEND_REFUSAL` now names matrix for an agent
that has it, and tells one without it that there is no direct channel:
the operator reads its `set_status` line, its turn output on the
dashboard, and its logs. The allow-list refusal, the `send` tool
description, the MCP server instructions and the system prompt say
"over matrix if you have it" to match, and the helper-event bullets go
back to "ask the operator" without naming a channel.
This commit is contained in:
atlas 2026-10-12 02:56:19 +02:00 • committed by mara
commit 80e8361da9
7 changed files with 25 additions and 17 deletions

View file

@ -7,7 +7,8 @@ use rmcp::schemars;
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct SendArgs {
/// Logical agent name to deliver the message to (e.g. `"manager"`,
/// `"alice"`). `"operator"` is refused: reach the operator over matrix.
/// `"alice"`). `"operator"` is refused: reach the operator over matrix
/// if you have it.
pub to: String,
/// Message body. Plain text; the broker doesn't parse it.
pub body: String,

View file

@ -142,7 +142,7 @@ impl AgentServer {
impl AgentServer {
#[tool(
description = "Send a message to another hyperhive agent on this hive. \
Not for the operator: reach them over matrix with the matrix MCP tools."
Not for the operator: reach them over matrix if you have the matrix MCP tools."
)]
async fn send(&self, Parameters(args): Parameters<SendArgs>) -> String {
let log = format!("{args:?}");
@ -500,7 +500,7 @@ impl AgentServer {
#[tool_handler(
instructions = "You are a hyperhive agent. Use `send` to talk to peers (by their logical \
name); reach the operator over matrix. Use `recv` to drain your inbox one \
name); reach the operator over matrix if you have it. Use `recv` to drain your inbox one \
message at a time. Use `remind` to schedule a future wake-up message for yourself."
)]
impl ServerHandler for AgentServer {}

View file

@ -44,7 +44,7 @@ pub fn check_send_allowed(to: &str) -> Result<(), String> {
Err(format!(
"send refused: recipient '{to}' not in services.hyperhive.agent.allowedRecipients \
(configured in agent.nix). Allowed: {allow:?}. To reach the operator, use \
the matrix MCP tools."
the matrix MCP tools if you have them."
))
}
@ -53,9 +53,10 @@ mod tests {
use super::check_send_allowed;
#[test]
fn operator_is_refused_with_the_matrix_pointer() {
fn operator_is_refused_naming_matrix_and_the_no_matrix_fallback() {
let refusal = check_send_allowed(hive_sh4re::manager::OPERATOR_RECIPIENT)
.expect_err("operator must be refused");
assert!(refusal.contains("mcp__matrix__"), "{refusal}");
assert!(refusal.contains("set_status"), "{refusal}");
}
}