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}
57
58pub type AgentStream = Pin<Box<dyn Stream<Item = anyhow::Result<StreamChunk>> + Send>>;
60
61#[async_trait]
63pub trait AgentHandle: Send + Sync {
64 async fn describe(&self) -> AgentDescriptor;
65
66 async fn handle_message(
67 &self,
68 input: AgentMessage,
69 state: Arc<AgentStateSnapshot>,
70 ) -> anyhow::Result<AgentMessage>;
71
72 async fn handle_message_stream(
75 &self,
76 input: AgentMessage,
77 state: Arc<AgentStateSnapshot>,
78 ) -> anyhow::Result<AgentStream> {
79 let response = self.handle_message(input, state).await?;
81 Ok(Box::pin(futures::stream::once(async move {
82 Ok(StreamChunk::Done { message: response })
83 })))
84 }
85}
86
87