remove flavor from AgentServer — dumb dispatcher, tool groups gate access
This commit is contained in:
parent
3c5abd3c85
commit
7261992fda
1 changed files with 14 additions and 60 deletions
|
|
@ -8,13 +8,11 @@
|
|||
//! broker-routed protocol. Unaffected by this module.
|
||||
//! - **MCP stdio** owned by this module — what claude actually speaks.
|
||||
//!
|
||||
//! One `AgentServer { socket, flavor }` struct handles both flavors:
|
||||
//! - `Flavor::Agent` — restricted send allow-list, no manager-only tools.
|
||||
//! - `Flavor::Manager` — manager-only tools unlocked via `require_manager()`.
|
||||
//! One `AgentServer { socket }` struct shared by agent and manager roles.
|
||||
//! `ManagerServer` is a backward-compat type alias for `AgentServer`.
|
||||
//!
|
||||
//! All tools live in one `#[tool_router] impl AgentServer`. Both flavors go
|
||||
//! through the same `run_tool_envelope` helper so logging stays uniform.
|
||||
//! Tool access is gated upstream by `--allowedTools` (derived from the
|
||||
//! agent's `ToolGroup` config); the server itself is a dumb dispatcher.
|
||||
//! All tools go through the same `run_tool_envelope` helper.
|
||||
|
||||
use std::future::Future;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -578,12 +576,9 @@ pub struct RemindArgs {
|
|||
/// `dispatch` call covers both sockets — the only real difference is which
|
||||
/// socket path is used and which tools the flavor enables.
|
||||
///
|
||||
/// Manager-only tools return a clear error when called from an agent context.
|
||||
/// In practice the `--allowedTools` gate prevents that — this is belt-and-suspenders.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AgentServer {
|
||||
socket: PathBuf,
|
||||
flavor: Flavor,
|
||||
}
|
||||
|
||||
/// Backward-compat alias — callers that reference `ManagerServer` by name still compile.
|
||||
|
|
@ -591,8 +586,8 @@ pub type ManagerServer = AgentServer;
|
|||
|
||||
impl AgentServer {
|
||||
#[must_use]
|
||||
pub fn new(socket: PathBuf, flavor: Flavor) -> Self {
|
||||
Self { socket, flavor }
|
||||
pub fn new(socket: PathBuf) -> Self {
|
||||
Self { socket }
|
||||
}
|
||||
|
||||
/// Issue any `Request` through the retry-aware client and pull
|
||||
|
|
@ -610,16 +605,6 @@ impl AgentServer {
|
|||
Err(e) => (Err(e), 0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an error string when called from a non-manager flavor.
|
||||
/// Manager-only tool methods call this first and early-return on Some.
|
||||
fn require_manager(&self) -> Option<String> {
|
||||
if !matches!(self.flavor, Flavor::Manager) {
|
||||
Some("error: this tool is only available to manager agents".to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IMPORTANT: when adding a new `#[tool]` fn to this impl, also add
|
||||
|
|
@ -635,12 +620,10 @@ impl AgentServer {
|
|||
async fn send(&self, Parameters(args): Parameters<SendArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
let to = args.to.clone();
|
||||
// Agent flavor: check per-agent allow-list (hyperhive.allowedRecipients).
|
||||
// Manager flavor: unrestricted send.
|
||||
if matches!(self.flavor, Flavor::Agent) {
|
||||
if let Err(refusal) = check_send_allowed(&to) {
|
||||
return run_tool_envelope("send", log, async move { refusal }).await;
|
||||
}
|
||||
// Check per-agent allow-list (hyperhive.allowedRecipients). When no
|
||||
// policy file is present (e.g. manager containers) the check is a no-op.
|
||||
if let Err(refusal) = check_send_allowed(&to) {
|
||||
return run_tool_envelope("send", log, async move { refusal }).await;
|
||||
}
|
||||
run_tool_envelope("send", log, async move {
|
||||
let (resp, retries) = self
|
||||
|
|
@ -1214,11 +1197,6 @@ impl AgentServer {
|
|||
.await
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Manager-only tools — guarded by require_manager(). The `--allowedTools`
|
||||
// gate prevents agents from ever calling these in practice; the guard is
|
||||
// belt-and-suspenders in case the gate is misconfigured.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
#[tool(
|
||||
description = "Fetch recent journal log lines for a sub-agent container. Useful \
|
||||
|
|
@ -1228,9 +1206,6 @@ impl AgentServer {
|
|||
`lines` defaults to 50 (max capped at 500 on the host side)."
|
||||
)]
|
||||
async fn get_logs(&self, Parameters(args): Parameters<GetLogsArgs>) -> String {
|
||||
if let Some(e) = self.require_manager() {
|
||||
return e;
|
||||
}
|
||||
let log = format!("{args:?}");
|
||||
let agent = args.agent.clone();
|
||||
run_tool_envelope("get_logs", log, async move {
|
||||
|
|
@ -1270,9 +1245,6 @@ impl AgentServer {
|
|||
&self,
|
||||
Parameters(args): Parameters<UpdateMetaInputsArgs>,
|
||||
) -> String {
|
||||
if let Some(e) = self.require_manager() {
|
||||
return e;
|
||||
}
|
||||
let log = format!("{args:?}");
|
||||
run_tool_envelope("request_update_meta_inputs", log, async move {
|
||||
let label = if args.inputs.is_empty() {
|
||||
|
|
@ -1316,9 +1288,6 @@ impl AgentServer {
|
|||
&self,
|
||||
Parameters(args): Parameters<RequestSchedulePromptArgs>,
|
||||
) -> String {
|
||||
if let Some(e) = self.require_manager() {
|
||||
return e;
|
||||
}
|
||||
let log = format!("{args:?}");
|
||||
run_tool_envelope("request_schedule_prompt", log, async move {
|
||||
let target_count = args.targets.len();
|
||||
|
|
@ -1355,9 +1324,6 @@ impl AgentServer {
|
|||
owned by a sub-agent in your subtree per topology.json."
|
||||
)]
|
||||
async fn fire_schedule_now(&self, Parameters(args): Parameters<FireScheduleNowArgs>) -> String {
|
||||
if let Some(e) = self.require_manager() {
|
||||
return e;
|
||||
}
|
||||
let log = format!("{args:?}");
|
||||
run_tool_envelope("fire_schedule_now", log, async move {
|
||||
let id = args.id;
|
||||
|
|
@ -1381,9 +1347,6 @@ impl AgentServer {
|
|||
owner is one of its sub-agents per topology.json. Other owners are refused."
|
||||
)]
|
||||
async fn cancel_schedule(&self, Parameters(args): Parameters<CancelScheduleArgs>) -> String {
|
||||
if let Some(e) = self.require_manager() {
|
||||
return e;
|
||||
}
|
||||
let log = format!("{args:?}");
|
||||
run_tool_envelope("cancel_schedule", log, async move {
|
||||
let id = args.id;
|
||||
|
|
@ -1416,9 +1379,6 @@ impl AgentServer {
|
|||
Refuses cancelled schedules (the row's terminal — submit a fresh one)."
|
||||
)]
|
||||
async fn edit_schedule(&self, Parameters(args): Parameters<EditScheduleArgs>) -> String {
|
||||
if let Some(e) = self.require_manager() {
|
||||
return e;
|
||||
}
|
||||
let log = format!("{args:?}");
|
||||
run_tool_envelope("edit_schedule", log, async move {
|
||||
let id = args.id;
|
||||
|
|
@ -1449,9 +1409,6 @@ impl AgentServer {
|
|||
the swarm is going to be woken up about next."
|
||||
)]
|
||||
async fn list_schedules(&self) -> String {
|
||||
if let Some(e) = self.require_manager() {
|
||||
return e;
|
||||
}
|
||||
run_tool_envelope("list_schedules", String::new(), async move {
|
||||
let (resp, retries) = self
|
||||
.dispatch(hive_sh4re::Request::ListSchedules)
|
||||
|
|
@ -1482,8 +1439,8 @@ impl ServerHandler for AgentServer {}
|
|||
///
|
||||
/// Returns an error if the MCP server fails to initialize or the transport
|
||||
/// encounters a fatal error.
|
||||
pub async fn serve_stdio(socket: PathBuf, flavor: Flavor) -> Result<()> {
|
||||
let server = AgentServer::new(socket, flavor);
|
||||
pub async fn serve_stdio(socket: PathBuf) -> Result<()> {
|
||||
let server = AgentServer::new(socket);
|
||||
let service = server.serve(stdio()).await?;
|
||||
service.waiting().await?;
|
||||
Ok(())
|
||||
|
|
@ -1491,15 +1448,12 @@ pub async fn serve_stdio(socket: PathBuf, flavor: Flavor) -> Result<()> {
|
|||
|
||||
/// Convenience wrapper: run the agent MCP server over stdio.
|
||||
pub async fn serve_agent_stdio(socket: PathBuf) -> Result<()> {
|
||||
serve_stdio(socket, Flavor::Agent).await
|
||||
serve_stdio(socket).await
|
||||
}
|
||||
|
||||
/// Convenience wrapper: run the manager MCP server over stdio.
|
||||
pub async fn serve_manager_stdio(socket: PathBuf) -> Result<()> {
|
||||
let server = AgentServer::new(socket, Flavor::Manager);
|
||||
let service = server.serve(stdio()).await?;
|
||||
service.waiting().await?;
|
||||
Ok(())
|
||||
serve_stdio(socket).await
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue