Skip to main content

bamboo_engine/runtime/
runner.rs

1//! Agent loop runner implementation.
2//!
3//! This module provides the core agent execution loop that orchestrates LLM interactions,
4//! tool execution, and event streaming for conversational AI agents.
5
6use bamboo_agent_core::TokenUsage;
7use bamboo_agent_core::{AgentError, Session};
8
9pub(crate) mod auxiliary_budget;
10pub mod image_fallback;
11mod logging;
12mod loop_execution;
13mod metrics_lifecycle;
14pub(crate) mod prompt_context;
15pub(crate) mod round_frame;
16pub(crate) mod round_lifecycle;
17pub(crate) mod round_prelude;
18pub(crate) mod session_finalize;
19pub(crate) mod session_setup;
20pub(crate) mod state_bridge;
21mod task_lifecycle;
22pub(crate) mod tool_execution;
23mod workspace_context;
24
25/// Test-only access to the real process-wide auxiliary semaphore.
26#[cfg(feature = "test-utils")]
27#[doc(hidden)]
28pub async fn test_acquire_auxiliary_budget(
29    provider: &std::sync::Arc<dyn bamboo_llm::LLMProvider>,
30    model: &str,
31    limit: usize,
32) -> tokio::sync::OwnedSemaphorePermit {
33    auxiliary_budget::acquire(provider, model, limit).await
34}
35
36pub use bamboo_agent_core::PromptSnapshot;
37pub(crate) use loop_execution::run_agent_loop_with_config;
38pub use state_bridge::{refresh_turn_boundary_with_inbox, TurnBoundaryRefresh};
39
40pub fn read_prompt_snapshot(session: &Session) -> Option<PromptSnapshot> {
41    session_setup::read_prompt_snapshot(session)
42}
43
44pub fn refresh_prompt_snapshot(session: &mut Session) {
45    session_setup::refresh_prompt_snapshot(session)
46}
47
48pub(super) fn to_event_token_usage(prompt_tokens: u64, completion_tokens: u64) -> TokenUsage {
49    let mut usage = TokenUsage {
50        prompt_tokens,
51        completion_tokens,
52        total_tokens: 0,
53    };
54    usage.recompute_total();
55    usage
56}
57
58/// Result type for agent loop operations.
59pub type Result<T> = std::result::Result<T, AgentError>;
60
61#[cfg(test)]
62mod tests;
63
64/// Stable, content-free outcome categories shared by loop and provider spans.
65fn telemetry_outcome<T>(
66    result: &std::result::Result<T, AgentError>,
67) -> bamboo_infrastructure::telemetry::Outcome {
68    match result {
69        Ok(_) => bamboo_infrastructure::telemetry::Outcome::Success,
70        Err(error) => telemetry_error_outcome(error),
71    }
72}
73
74fn telemetry_error_outcome(error: &AgentError) -> bamboo_infrastructure::telemetry::Outcome {
75    use bamboo_infrastructure::telemetry::Outcome;
76    match error {
77        AgentError::Cancelled => Outcome::Cancelled,
78        AgentError::StreamTimeout(_) => Outcome::Timeout,
79        AgentError::LLMOverflow(_) => Outcome::ContextOverflow,
80        AgentError::EmptyAssistantResponse { .. } => Outcome::EmptyResponse,
81        AgentError::LLM(_) | AgentError::LLMNonRetryable(_) => Outcome::ProviderError,
82        _ => Outcome::ExecutionError,
83    }
84}