Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/hive-agent-mcp/src/mcp/args.rs
atlas 80e8361da9 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.
2026-10-12 08:50:06 +02:00

125 lines
5.3 KiB
Rust

//! Argument structs for the MCP tools: `serde::Deserialize` +
//! `schemars::JsonSchema` derives whose field doc-comments become the
//! parameter descriptions claude sees in each tool's input schema.
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
/// if you have it.
pub to: String,
/// Message body. Plain text; the broker doesn't parse it.
pub body: String,
/// Optional broker row-id of the message this is a reply to. Lets
/// the dashboard render conversation threads. Pass the `id` from the
/// `DeliveredMessage` you're responding to; omit for new threads.
/// Silently ignored if the id is unknown or out of retention.
#[serde(default)]
pub in_reply_to: Option<i64>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct RecvArgs {
/// Maximum number of messages to pop in this round-trip. Default
/// (None) is 1 (single-message behaviour — exactly what you want
/// when you're called to drive a turn off the first wake). Pass
/// a higher value (capped at 5 server-side) when you've been
/// told the inbox has more queued (the wake prompt mentions
/// pending count) and want to drain everything in one tool call.
#[serde(default)]
pub max: Option<u32>,
}
/// MCP tool args for `ack_until`.
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct AckUntilArgs {
/// Highest broker message id to mark handled: every inbox message
/// with `id <= up_to` (ids show as `[msg #<id>]` in recv output)
/// is acked in one sweep. Pass the highest id you've actually
/// seen/triaged — anything above it stays queued for later turns.
pub up_to: i64,
}
/// MCP tool args for `mark_todos_done`.
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct MarkTodosDoneArgs {
/// Todo ids to clear (from `get_loose_ends`'s `todo #N` lines). Only
/// these ids are acked — not a range. Unknown/already-acked ids are
/// silently skipped.
pub ids: Vec<i64>,
}
/// MCP tool args for `remind`. Exactly one of `delay_seconds` or
/// `at_unix_timestamp` must be set; both / neither is a tool-side error.
/// Hides the tagged `ReminderTiming` enum behind a flatter schema so the
/// model picks one field instead of building `{"timing_type": "in_seconds",
/// "seconds": 60}` shaped objects.
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct RemindArgs {
/// Body that lands in your inbox when the reminder fires (sender
/// will appear as `reminder`). Soft cap at 4 KiB inline — anything
/// larger gets auto-persisted to a file under
/// `/agents/<you>/state/reminders/auto-<ts>.md` and the inbox
/// message becomes a short pointer. Pass `file_path` if you want
/// to control the destination yourself.
pub message: String,
/// Fire `delay_seconds` from now (relative). Set this OR
/// `at_unix_timestamp`, not both.
#[serde(default)]
pub delay_seconds: Option<u64>,
/// Fire at this absolute unix timestamp (seconds since epoch). Set
/// this OR `delay_seconds`, not both.
#[serde(default)]
pub at_unix_timestamp: Option<i64>,
/// Optional path to a file the scheduler should reference instead of
/// inlining a long `message`. Use this for large payloads (research
/// notes, file lists, intermediate state). Path must be reachable from
/// the agent's container — typically under `/agents/<you>/state/`.
#[serde(default)]
pub file_path: Option<String>,
}
/// MCP tool args for `compact`.
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct CompactArgs {
/// Optional wake-up prompt. When set and the compact actually runs
/// (gated on context usage — see the tool description), the harness
/// drives one synthetic follow-up turn with this string as its body
/// as soon as compaction finishes, so you don't have to wait for the
/// next external event to continue. Omit for a fire-and-forget compact
/// with no follow-up.
#[serde(default)]
pub wake_prompt: Option<String>,
}
// -----------------------------------------------------------------------------
// Privileged tool arg types (lifecycle)
// -----------------------------------------------------------------------------
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct SetStatusArgs {
/// Status text to display on the dashboard card. Pass an empty string to clear.
pub text: String,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct GetAgentMetaArgs {
/// Logical name of the agent to query (e.g. `"iris"`, `"manager"`).
/// Omit to query your own identity + status — replaces the
/// previous `whoami` self-introspection tool.
#[serde(default)]
pub name: Option<String>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct CancelLooseEndArgs {
/// Which kind of thread to cancel — `"reminder"` for a scheduled
/// `remind` that hasn't fired yet, or `"todo"` for a loose-ends-v2 todo
/// (bash/matrix/forge). Use the `kind` field straight off the
/// `get_loose_ends` row.
pub kind: String,
/// Row id from the matching `get_loose_ends` entry.
pub id: i64,
}