Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- Create docs/brainstorming/ with 5 discussion records (Mar 16 - Apr 7) - Archive ~30 outdated audit reports (V5-V11) to docs/archive/old-audits/ - Archive superseded analysis docs to docs/archive/old-analysis/ - Archive completed session plans to docs/archive/old-plans/ - Archive old test reports/validations to respective archive folders - Remove empty directories left after moves - Keep current docs: TRUTH.md, feature docs, deployment, knowledge-base, superpowers
188 lines
6.2 KiB
Rust
188 lines
6.2 KiB
Rust
//! A2A (Agent-to-Agent) commands — gated behind `multi-agent` feature
|
|
|
|
use serde_json;
|
|
use tauri::State;
|
|
use zclaw_types::AgentId;
|
|
|
|
use super::KernelState;
|
|
|
|
// ============================================================
|
|
// A2A (Agent-to-Agent) Commands — gated behind multi-agent feature
|
|
// ============================================================
|
|
|
|
#[cfg(feature = "multi-agent")]
|
|
/// Send a direct A2A message from one agent to another
|
|
// @connected
|
|
#[tauri::command]
|
|
pub async fn agent_a2a_send(
|
|
state: State<'_, KernelState>,
|
|
from: String,
|
|
to: String,
|
|
payload: serde_json::Value,
|
|
message_type: Option<String>,
|
|
) -> Result<(), String> {
|
|
let kernel_lock = state.lock().await;
|
|
let kernel = kernel_lock.as_ref()
|
|
.ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?;
|
|
|
|
let from_id: AgentId = from.parse()
|
|
.map_err(|_| format!("Invalid from agent ID: {}", from))?;
|
|
let to_id: AgentId = to.parse()
|
|
.map_err(|_| format!("Invalid to agent ID: {}", to))?;
|
|
|
|
let msg_type = message_type.map(|mt| match mt.as_str() {
|
|
"request" => zclaw_kernel::A2aMessageType::Request,
|
|
"notification" => zclaw_kernel::A2aMessageType::Notification,
|
|
"task" => zclaw_kernel::A2aMessageType::Task,
|
|
_ => zclaw_kernel::A2aMessageType::Notification,
|
|
});
|
|
|
|
kernel.a2a_send(&from_id, &to_id, payload, msg_type).await
|
|
.map_err(|e| format!("A2A send failed: {}", e))?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Broadcast a message from one agent to all other agents
|
|
#[cfg(feature = "multi-agent")]
|
|
// @connected
|
|
#[tauri::command]
|
|
pub async fn agent_a2a_broadcast(
|
|
state: State<'_, KernelState>,
|
|
from: String,
|
|
payload: serde_json::Value,
|
|
) -> Result<(), String> {
|
|
let kernel_lock = state.lock().await;
|
|
let kernel = kernel_lock.as_ref()
|
|
.ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?;
|
|
|
|
let from_id: AgentId = from.parse()
|
|
.map_err(|_| format!("Invalid from agent ID: {}", from))?;
|
|
|
|
kernel.a2a_broadcast(&from_id, payload).await
|
|
.map_err(|e| format!("A2A broadcast failed: {}", e))?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Discover agents with a specific capability
|
|
#[cfg(feature = "multi-agent")]
|
|
// @connected
|
|
#[tauri::command]
|
|
pub async fn agent_a2a_discover(
|
|
state: State<'_, KernelState>,
|
|
capability: String,
|
|
) -> Result<Vec<serde_json::Value>, String> {
|
|
let kernel_lock = state.lock().await;
|
|
let kernel = kernel_lock.as_ref()
|
|
.ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?;
|
|
|
|
let profiles = kernel.a2a_discover(&capability).await
|
|
.map_err(|e| format!("A2A discover failed: {}", e))?;
|
|
|
|
let result: Vec<serde_json::Value> = profiles.iter()
|
|
.filter_map(|p| serde_json::to_value(p).ok())
|
|
.collect();
|
|
|
|
Ok(result)
|
|
}
|
|
|
|
/// Delegate a task to another agent and wait for response
|
|
#[cfg(feature = "multi-agent")]
|
|
// @connected
|
|
#[tauri::command]
|
|
pub async fn agent_a2a_delegate_task(
|
|
state: State<'_, KernelState>,
|
|
from: String,
|
|
to: String,
|
|
task: String,
|
|
timeout_ms: Option<u64>,
|
|
) -> Result<serde_json::Value, String> {
|
|
let kernel_lock = state.lock().await;
|
|
let kernel = kernel_lock.as_ref()
|
|
.ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?;
|
|
|
|
let from_id: AgentId = from.parse()
|
|
.map_err(|_| format!("Invalid from agent ID: {}", from))?;
|
|
let to_id: AgentId = to.parse()
|
|
.map_err(|_| format!("Invalid to agent ID: {}", to))?;
|
|
|
|
let timeout = timeout_ms.unwrap_or(30_000);
|
|
|
|
let response = kernel.a2a_delegate_task(&from_id, &to_id, task, timeout).await
|
|
.map_err(|e| format!("A2A task delegation failed: {}", e))?;
|
|
|
|
Ok(response)
|
|
}
|
|
|
|
// ============================================================
|
|
// Butler Delegation Command — multi-agent feature
|
|
// ============================================================
|
|
|
|
/// Butler delegates a user request to expert agents via the Director.
|
|
#[cfg(feature = "multi-agent")]
|
|
// @connected
|
|
#[tauri::command]
|
|
pub async fn butler_delegate_task(
|
|
state: State<'_, KernelState>,
|
|
request: String,
|
|
) -> Result<serde_json::Value, String> {
|
|
use zclaw_kernel::director::{Director, DirectorConfig, DirectorAgent, AgentRole};
|
|
|
|
let kernel_lock = state.lock().await;
|
|
let kernel = kernel_lock.as_ref()
|
|
.ok_or_else(|| "Kernel not initialized. Call kernel_init first.".to_string())?;
|
|
|
|
// Create a Director for this delegation
|
|
let director = Director::new(DirectorConfig::default());
|
|
|
|
// Register active agents from kernel as experts
|
|
let agents = kernel.list_agents();
|
|
for agent in agents {
|
|
let persona = agent.system_prompt.clone()
|
|
.or(agent.soul.clone())
|
|
.unwrap_or_default();
|
|
let director_agent = DirectorAgent::new(
|
|
agent.id.clone(),
|
|
agent.name.clone(),
|
|
AgentRole::Expert,
|
|
persona,
|
|
);
|
|
director.register_agent(director_agent).await;
|
|
}
|
|
|
|
drop(kernel_lock);
|
|
|
|
let result = director.butler_delegate(&request).await
|
|
.map_err(|e| format!("Butler delegation failed: {}", e))?;
|
|
|
|
// Convert to JSON-serializable response
|
|
let tasks: Vec<serde_json::Value> = result.tasks.iter().map(|t| {
|
|
serde_json::json!({
|
|
"id": t.id,
|
|
"description": t.description,
|
|
"category": t.category,
|
|
"priority": t.priority,
|
|
"status": match t.status {
|
|
zclaw_kernel::director::ExpertTaskStatus::Pending => "pending",
|
|
zclaw_kernel::director::ExpertTaskStatus::Assigned => "assigned",
|
|
zclaw_kernel::director::ExpertTaskStatus::InProgress => "in_progress",
|
|
zclaw_kernel::director::ExpertTaskStatus::Completed => "completed",
|
|
zclaw_kernel::director::ExpertTaskStatus::Failed => "failed",
|
|
},
|
|
"assigned_expert": t.assigned_expert.as_ref().map(|e| serde_json::json!({
|
|
"id": e.id.to_string(),
|
|
"name": e.name,
|
|
"role": e.role.as_str(),
|
|
})),
|
|
})
|
|
}).collect();
|
|
|
|
Ok(serde_json::json!({
|
|
"request": result.request,
|
|
"tasks": tasks,
|
|
"success": result.success,
|
|
"summary": result.summary,
|
|
}))
|
|
}
|