use std::sync::Arc;
use entelix_core::ir::Message;
use entelix_core::{ExecutionContext, Result};
use entelix_graph::{CompiledGraph, StateGraph};
use entelix_runnable::{Runnable, RunnableLambda};
use crate::agent::Agent;
use crate::state::ChatState;
pub fn build_chat_graph<M>(model: M, system: impl Into<String>) -> Result<CompiledGraph<ChatState>>
where
M: Runnable<Vec<Message>, Message> + 'static,
{
let model = Arc::new(model);
let system_text = system.into();
let node = RunnableLambda::new(move |mut state: ChatState, ctx: ExecutionContext| {
let model = model.clone();
let system = system_text.clone();
async move {
let mut prompt = Vec::with_capacity(state.messages.len().saturating_add(1));
if !system.is_empty() {
prompt.push(Message::system(system));
}
prompt.extend(state.messages.iter().cloned());
let reply = model.invoke(prompt, &ctx).await?;
state.messages.push(reply);
Ok::<_, _>(state)
}
});
StateGraph::<ChatState>::new()
.add_node("chat", node)
.set_entry_point("chat")
.add_finish_point("chat")
.compile()
}
pub fn create_chat_agent<M>(model: M, system: impl Into<String>) -> Result<Agent<ChatState>>
where
M: Runnable<Vec<Message>, Message> + 'static,
{
let graph = build_chat_graph(model, system)?;
Agent::<ChatState>::builder()
.with_name("chat")
.with_runnable(graph)
.build()
}