bamboo_engine/runtime/managers/adapters/
llm.rs1use std::sync::Arc;
2
3use async_trait::async_trait;
4use bamboo_agent_core::tools::ToolSchema;
5use bamboo_agent_core::{AgentError, AgentEvent, Session};
6use bamboo_llm::LLMProvider;
7use tokio::sync::mpsc;
8use tokio_util::sync::CancellationToken;
9
10use crate::runtime::config::AgentLoopConfig;
11use crate::runtime::managers::llm::{LlmManager, LlmRoundOutput};
12
13pub struct DefaultLlmManager {
15 llm: Arc<dyn LLMProvider>,
16}
17
18impl DefaultLlmManager {
19 pub fn new(llm: Arc<dyn LLMProvider>) -> Self {
20 Self { llm }
21 }
22}
23
24#[async_trait]
25impl LlmManager for DefaultLlmManager {
26 #[allow(clippy::too_many_arguments)]
27 async fn execute_round(
28 &self,
29 session: &mut Session,
30 config: &AgentLoopConfig,
31 event_tx: &mpsc::Sender<AgentEvent>,
32 cancel_token: &CancellationToken,
33 session_id: &str,
34 model_name: &str,
35 tool_schemas: &[ToolSchema],
36 ) -> Result<LlmRoundOutput, AgentError> {
37 let result = crate::runtime::runner::round_lifecycle::execute_llm_round(
38 session,
39 config,
40 &self.llm,
41 event_tx,
42 cancel_token,
43 session_id,
44 model_name,
45 tool_schemas,
46 None,
47 None,
52 )
53 .await?;
54
55 if let Some(error) = result.terminal_validation_error {
56 return Err(error);
57 }
58
59 let (content, reasoning_content, tool_calls) = {
60 let stream = &result.stream_output;
61 (
62 stream.content.clone(),
63 stream.reasoning_content.clone(),
64 stream.tool_calls.clone(),
65 )
66 };
67
68 Ok(LlmRoundOutput {
69 content,
70 reasoning_content,
71 tool_calls,
72 prompt_tokens: result.prompt_tokens,
73 completion_tokens: result.completion_tokens,
74 response_id: None,
75 round_usage: result.attempt_usage,
76 })
77 }
78
79 async fn attempt_overflow_recovery(
80 &self,
81 session: &mut Session,
82 config: &AgentLoopConfig,
83 session_id: &str,
84 tool_schemas: &[ToolSchema],
85 event_tx: &mpsc::Sender<AgentEvent>,
86 ) -> Result<bool, AgentError> {
87 let model_name = config.model_name.as_deref().unwrap_or("unknown");
88 let request_tool_schemas =
89 crate::runtime::runner::round_lifecycle::request_tool_schemas_for_session(
90 session,
91 &self.llm,
92 model_name,
93 tool_schemas,
94 )
95 .await;
96
97 crate::runtime::runner::round_lifecycle::force_overflow_context_recovery(
98 session,
99 config,
100 model_name,
101 session_id,
102 request_tool_schemas.as_ref(),
103 &self.llm,
104 Some(event_tx),
105 )
106 .await
107 }
108}