use std::sync::Arc;
use super::catalog::builtin_tool_catalog;
use super::registry::BuiltinTool;
use super::types::*;
pub struct AgentSpawnTool {
spec: BuiltinToolSpec,
process_table: Arc<crate::process::ProcessTable>,
}
impl AgentSpawnTool {
pub fn new(process_table: Arc<crate::process::ProcessTable>) -> Self {
let catalog = builtin_tool_catalog();
let spec = catalog
.into_iter()
.find(|s| s.name == "agent.spawn")
.expect("agent.spawn must be in catalog");
Self {
spec,
process_table,
}
}
}
impl BuiltinTool for AgentSpawnTool {
fn name(&self) -> &str {
"agent.spawn"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
let agent_id = args
.get("agent_id")
.and_then(|v| v.as_str())
.ok_or_else(|| ToolError::InvalidArgs("missing 'agent_id' parameter".into()))?;
let backend = args
.get("backend")
.and_then(|v| v.as_str())
.unwrap_or("native");
if backend == "wasm" {
return Err(ToolError::ExecutionFailed(
"WASM backend not yet available for agent.spawn".into(),
));
}
let entry = crate::process::ProcessEntry {
pid: 0, agent_id: agent_id.to_string(),
state: crate::process::ProcessState::Running,
capabilities: crate::capability::AgentCapabilities::default(),
resource_usage: crate::process::ResourceUsage::default(),
cancel_token: crate::process::CancellationToken::new(),
parent_pid: None,
};
let pid = self
.process_table
.insert(entry)
.map_err(|e| ToolError::ExecutionFailed(format!("spawn failed: {e}")))?;
Ok(serde_json::json!({
"pid": pid,
"agent_id": agent_id,
"state": "running",
}))
}
}
pub struct AgentStopTool {
spec: BuiltinToolSpec,
process_table: Arc<crate::process::ProcessTable>,
}
impl AgentStopTool {
pub fn new(process_table: Arc<crate::process::ProcessTable>) -> Self {
let spec = builtin_tool_catalog()
.into_iter()
.find(|s| s.name == "agent.stop")
.unwrap();
Self {
spec,
process_table,
}
}
}
impl BuiltinTool for AgentStopTool {
fn name(&self) -> &str {
"agent.stop"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
let pid = args
.get("pid")
.and_then(|v| v.as_u64())
.ok_or_else(|| ToolError::InvalidArgs("missing 'pid'".into()))?;
let entry = self
.process_table
.get(pid)
.ok_or_else(|| ToolError::NotFound(format!("pid {pid}")))?;
entry.cancel_token.cancel();
self.process_table
.update_state(pid, crate::process::ProcessState::Stopping)
.map_err(|e| ToolError::ExecutionFailed(e.to_string()))?;
Ok(serde_json::json!({"stopped": pid, "agent_id": entry.agent_id}))
}
}
pub struct AgentListTool {
spec: BuiltinToolSpec,
process_table: Arc<crate::process::ProcessTable>,
}
impl AgentListTool {
pub fn new(process_table: Arc<crate::process::ProcessTable>) -> Self {
let spec = builtin_tool_catalog()
.into_iter()
.find(|s| s.name == "agent.list")
.unwrap();
Self {
spec,
process_table,
}
}
}
impl BuiltinTool for AgentListTool {
fn name(&self) -> &str {
"agent.list"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, _args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
let list = self.process_table.list();
let entries: Vec<serde_json::Value> = list
.iter()
.map(|e| {
serde_json::json!({
"pid": e.pid,
"agent_id": e.agent_id,
"state": format!("{:?}", e.state),
})
})
.collect();
Ok(serde_json::json!({"agents": entries, "count": entries.len()}))
}
}
pub struct AgentInspectTool {
spec: BuiltinToolSpec,
process_table: Arc<crate::process::ProcessTable>,
}
impl AgentInspectTool {
pub fn new(process_table: Arc<crate::process::ProcessTable>) -> Self {
let spec = builtin_tool_catalog()
.into_iter()
.find(|s| s.name == "agent.inspect")
.unwrap();
Self {
spec,
process_table,
}
}
}
impl BuiltinTool for AgentInspectTool {
fn name(&self) -> &str {
"agent.inspect"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
let pid = args
.get("pid")
.and_then(|v| v.as_u64())
.ok_or_else(|| ToolError::InvalidArgs("missing 'pid'".into()))?;
let entry = self
.process_table
.get(pid)
.ok_or_else(|| ToolError::NotFound(format!("pid {pid}")))?;
Ok(serde_json::json!({
"pid": entry.pid,
"agent_id": entry.agent_id,
"state": format!("{:?}", entry.state),
"parent_pid": entry.parent_pid,
"resource_usage": {
"messages_sent": entry.resource_usage.messages_sent,
"tool_calls": entry.resource_usage.tool_calls,
"cpu_time_ms": entry.resource_usage.cpu_time_ms,
},
"capabilities": {
"can_spawn": entry.capabilities.can_spawn,
"can_ipc": entry.capabilities.can_ipc,
"can_exec_tools": entry.capabilities.can_exec_tools,
"can_network": entry.capabilities.can_network,
},
}))
}
}
#[cfg(feature = "native")]
pub struct AgentSendTool {
spec: BuiltinToolSpec,
process_table: Arc<crate::process::ProcessTable>,
a2a: Arc<crate::a2a::A2ARouter>,
}
#[cfg(feature = "native")]
impl AgentSendTool {
pub fn new(
process_table: Arc<crate::process::ProcessTable>,
a2a: Arc<crate::a2a::A2ARouter>,
) -> Self {
let spec = builtin_tool_catalog()
.into_iter()
.find(|s| s.name == "agent.send")
.unwrap();
Self {
spec,
process_table,
a2a,
}
}
}
#[cfg(feature = "native")]
impl BuiltinTool for AgentSendTool {
fn name(&self) -> &str {
"agent.send"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
let pid = args
.get("pid")
.and_then(|v| v.as_u64())
.ok_or_else(|| ToolError::InvalidArgs("missing 'pid'".into()))?;
let message = args
.get("message")
.cloned()
.ok_or_else(|| ToolError::InvalidArgs("missing 'message'".into()))?;
let _ = self
.process_table
.get(pid)
.ok_or_else(|| ToolError::NotFound(format!("pid {pid}")))?;
let msg = crate::ipc::KernelMessage::new(
0, crate::ipc::MessageTarget::Process(pid),
crate::ipc::MessagePayload::Json(message),
);
let msg_id = msg.id.clone();
let a2a = self.a2a.clone();
std::thread::spawn(move || {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(async { a2a.send(msg).await })
})
.join()
.map_err(|_| ToolError::ExecutionFailed("send thread panicked".into()))?
.map_err(|e| ToolError::ExecutionFailed(e.to_string()))?;
Ok(serde_json::json!({"sent": true, "pid": pid, "msg_id": msg_id}))
}
}
pub struct AgentSuspendTool {
spec: BuiltinToolSpec,
process_table: Arc<crate::process::ProcessTable>,
}
impl AgentSuspendTool {
pub fn new(process_table: Arc<crate::process::ProcessTable>) -> Self {
let spec = builtin_tool_catalog()
.into_iter()
.find(|s| s.name == "agent.suspend")
.unwrap();
Self {
spec,
process_table,
}
}
}
impl BuiltinTool for AgentSuspendTool {
fn name(&self) -> &str {
"agent.suspend"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
let pid = args
.get("pid")
.and_then(|v| v.as_u64())
.ok_or_else(|| ToolError::InvalidArgs("missing 'pid'".into()))?;
self.process_table
.update_state(pid, crate::process::ProcessState::Suspended)
.map_err(|e| ToolError::ExecutionFailed(e.to_string()))?;
Ok(serde_json::json!({"suspended": pid}))
}
}
pub struct AgentResumeTool {
spec: BuiltinToolSpec,
process_table: Arc<crate::process::ProcessTable>,
}
impl AgentResumeTool {
pub fn new(process_table: Arc<crate::process::ProcessTable>) -> Self {
let spec = builtin_tool_catalog()
.into_iter()
.find(|s| s.name == "agent.resume")
.unwrap();
Self {
spec,
process_table,
}
}
}
impl BuiltinTool for AgentResumeTool {
fn name(&self) -> &str {
"agent.resume"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
let pid = args
.get("pid")
.and_then(|v| v.as_u64())
.ok_or_else(|| ToolError::InvalidArgs("missing 'pid'".into()))?;
self.process_table
.update_state(pid, crate::process::ProcessState::Running)
.map_err(|e| ToolError::ExecutionFailed(e.to_string()))?;
Ok(serde_json::json!({"resumed": pid}))
}
}
pub struct IpcSendTool {
spec: BuiltinToolSpec,
}
impl Default for IpcSendTool {
fn default() -> Self {
Self::new()
}
}
impl IpcSendTool {
pub fn new() -> Self {
let catalog = builtin_tool_catalog();
let spec = catalog
.into_iter()
.find(|s| s.name == "ipc.send")
.expect("ipc.send must be in catalog");
Self { spec }
}
}
impl BuiltinTool for IpcSendTool {
fn name(&self) -> &str {
"ipc.send"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, _args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
Err(ToolError::ExecutionFailed(
"ipc.send requires async kernel context".into(),
))
}
}
pub struct IpcSubscribeTool {
spec: BuiltinToolSpec,
}
impl Default for IpcSubscribeTool {
fn default() -> Self {
Self::new()
}
}
impl IpcSubscribeTool {
pub fn new() -> Self {
let catalog = builtin_tool_catalog();
let spec = catalog
.into_iter()
.find(|s| s.name == "ipc.subscribe")
.expect("ipc.subscribe must be in catalog");
Self { spec }
}
}
impl BuiltinTool for IpcSubscribeTool {
fn name(&self) -> &str {
"ipc.subscribe"
}
fn spec(&self) -> &BuiltinToolSpec {
&self.spec
}
fn execute(&self, _args: serde_json::Value) -> Result<serde_json::Value, ToolError> {
Err(ToolError::ExecutionFailed(
"ipc.subscribe requires async kernel context".into(),
))
}
}