1use async_trait::async_trait;
2use futures::stream::Stream;
3use serde::{Deserialize, Serialize};
4use std::pin::Pin;
5use std::sync::Arc;
6
7use crate::llm::StreamChunk;
8use crate::messaging::AgentMessage;
9use crate::state::AgentStateSnapshot;
10
11#[async_trait]
13pub trait PlannerHandle: Send + Sync + std::any::Any {
14 async fn plan(
15 &self,
16 context: PlannerContext,
17 state: Arc<AgentStateSnapshot>,
18 ) -> anyhow::Result<PlannerDecision>;
19
20 fn as_any(&self) -> &dyn std::any::Any;
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct AgentDescriptor {
27 pub name: String,
28 pub version: String,
29 pub description: Option<String>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct PlannerDecision {
35 pub next_action: PlannerAction,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub enum PlannerAction {
41 CallTool {
42 tool_name: String,
43 payload: serde_json::Value,
44 },
45 Respond {
46 message: AgentMessage,
47 },
48 Terminate,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct PlannerContext {
54 pub history: Vec<AgentMessage>,
55 pub system_prompt: String,
56 #[serde(default)]
57 pub tools: Vec<crate::tools::ToolSchema>,
58}
59
60pub type AgentStream = Pin<Box<dyn Stream<Item = anyhow::Result<StreamChunk>> + Send>>;
62
63#[async_trait]
65pub trait AgentHandle: Send + Sync {
66 async fn describe(&self) -> AgentDescriptor;
67
68 async fn handle_message(
69 &self,
70 input: AgentMessage,
71 state: Arc<AgentStateSnapshot>,
72 ) -> anyhow::Result<AgentMessage>;
73
74 async fn handle_message_stream(
77 &self,
78 input: AgentMessage,
79 state: Arc<AgentStateSnapshot>,
80 ) -> anyhow::Result<AgentStream> {
81 let response = self.handle_message(input, state).await?;
83 Ok(Box::pin(futures::stream::once(async move {
84 Ok(StreamChunk::Done { message: response })
85 })))
86 }
87
88 async fn current_interrupt(&self) -> anyhow::Result<Option<crate::hitl::AgentInterrupt>> {
91 Ok(None)
93 }
94
95 async fn resume_with_approval(
103 &self,
104 _action: crate::hitl::HitlAction,
105 ) -> anyhow::Result<AgentMessage> {
106 anyhow::bail!("resume_with_approval not implemented for this agent")
108 }
109}
110
111