bamboo-engine 2026.11.1

Execution engine and orchestration for the Bamboo agent framework
//! Agent loop runner implementation.
//!
//! This module provides the core agent execution loop that orchestrates LLM interactions,
//! tool execution, and event streaming for conversational AI agents.

use bamboo_agent_core::TokenUsage;
use bamboo_agent_core::{AgentError, Session};

pub(crate) mod auxiliary_budget;
pub mod image_fallback;
mod logging;
mod loop_execution;
mod metrics_lifecycle;
pub(crate) mod prompt_context;
pub(crate) mod round_frame;
pub(crate) mod round_lifecycle;
pub(crate) mod round_prelude;
pub(crate) mod session_finalize;
pub(crate) mod session_setup;
pub(crate) mod state_bridge;
mod task_lifecycle;
pub(crate) mod tool_execution;
mod workspace_context;

/// Test-only access to the real process-wide auxiliary semaphore.
#[cfg(feature = "test-utils")]
#[doc(hidden)]
pub async fn test_acquire_auxiliary_budget(
    provider: &std::sync::Arc<dyn bamboo_llm::LLMProvider>,
    model: &str,
    limit: usize,
) -> tokio::sync::OwnedSemaphorePermit {
    auxiliary_budget::acquire(provider, model, limit).await
}

pub use bamboo_agent_core::PromptSnapshot;
pub(crate) use loop_execution::run_agent_loop_with_config;
pub use state_bridge::{refresh_turn_boundary_with_inbox, TurnBoundaryRefresh};

pub fn read_prompt_snapshot(session: &Session) -> Option<PromptSnapshot> {
    session_setup::read_prompt_snapshot(session)
}

pub fn refresh_prompt_snapshot(session: &mut Session) {
    session_setup::refresh_prompt_snapshot(session)
}

pub(super) fn to_event_token_usage(prompt_tokens: u64, completion_tokens: u64) -> TokenUsage {
    let mut usage = TokenUsage {
        prompt_tokens,
        completion_tokens,
        total_tokens: 0,
    };
    usage.recompute_total();
    usage
}

/// Result type for agent loop operations.
pub type Result<T> = std::result::Result<T, AgentError>;

#[cfg(test)]
mod tests;

/// Stable, content-free outcome categories shared by loop and provider spans.
fn telemetry_outcome<T>(
    result: &std::result::Result<T, AgentError>,
) -> bamboo_infrastructure::telemetry::Outcome {
    match result {
        Ok(_) => bamboo_infrastructure::telemetry::Outcome::Success,
        Err(error) => telemetry_error_outcome(error),
    }
}

fn telemetry_error_outcome(error: &AgentError) -> bamboo_infrastructure::telemetry::Outcome {
    use bamboo_infrastructure::telemetry::Outcome;
    match error {
        AgentError::Cancelled => Outcome::Cancelled,
        AgentError::StreamTimeout(_) => Outcome::Timeout,
        AgentError::LLMOverflow(_) => Outcome::ContextOverflow,
        AgentError::EmptyAssistantResponse { .. } => Outcome::EmptyResponse,
        AgentError::LLM(_) | AgentError::LLMNonRetryable(_) => Outcome::ProviderError,
        _ => Outcome::ExecutionError,
    }
}