use std::collections::HashSet;
use std::path::Path;
use std::sync::Arc;
use async_trait::async_trait;
use serde_json::Value;
use zagens_tools::{ToolError, ToolResult};
use tokio::sync::{Mutex as AsyncMutex, RwLock, mpsc};
use tokio_util::sync::CancellationToken;
use crate::chat::{LlmClient, Message, Tool};
use crate::compaction::CompactionConfig;
use crate::error_taxonomy::ErrorCategory;
use crate::events::Event;
use crate::scratchpad::ScratchpadConfig;
use crate::session::Session;
use crate::turn::{TurnContext, TurnLoopMode};
use super::control::TurnLoopControl;
use super::exec::{ToolExecOutcome, ToolExecutionPlan, ToolPlanApprovalMeta};
use crate::engine::streaming::ToolUseState;
#[derive(Debug, Clone, Copy)]
pub struct TurnLoopConfigView<'a> {
pub compaction: &'a CompactionConfig,
pub strict_tool_mode: bool,
pub scratchpad: &'a ScratchpadConfig,
pub workspace: &'a Path,
}
pub trait TurnLoopToolRegistry: Send + Sync {}
#[deprecated(
since = "0.8.16",
note = "use `zagens_core::engine::hosts::McpHost` instead; \
this alias will be removed in the next release"
)]
pub trait TurnLoopMcpPool: Send + Sync {}
#[allow(deprecated)]
impl<T: crate::engine::hosts::McpHost + ?Sized> TurnLoopMcpPool for T {}
#[async_trait]
pub trait TurnLoopHost: Send {
type ToolRegistry: TurnLoopToolRegistry;
type McpPool: crate::engine::hosts::McpHost;
fn session_mut(&mut self) -> &mut Session;
fn compaction_config(&self) -> &CompactionConfig;
#[must_use]
fn compaction_enabled(&self) -> bool {
self.compaction_config().enabled
}
fn workspace(&self) -> &Path;
#[must_use]
fn strict_tool_mode(&self) -> bool;
fn scratchpad_config(&self) -> &ScratchpadConfig;
fn scratchpad_run_id(&self) -> Option<&str>;
fn scratchpad_summary_injected_mut(&mut self) -> &mut bool;
fn cancel_token(&self) -> &CancellationToken;
fn tx_event(&self) -> &mpsc::Sender<Event>;
fn rx_steer_mut(&mut self) -> &mut mpsc::Receiver<String>;
fn tool_exec_lock(&self) -> Arc<RwLock<()>>;
fn llm_client(&self) -> Option<Arc<dyn LlmClient>>;
fn prepare_tool_catalog(&self, catalog: &mut Vec<Tool>);
fn initial_active_tool_names(&self, catalog: &[Tool]) -> HashSet<String>;
fn active_tools_for_step(
&self,
catalog: &[Tool],
active: &HashSet<String>,
force_update_plan_first: bool,
) -> Vec<Tool>;
fn is_mcp_tool_name(&self, name: &str) -> bool;
fn maybe_activate_deferred_tool(
&self,
tool_name: &str,
catalog: &[Tool],
active: &mut HashSet<String>,
) -> bool;
async fn execute_code_execution_tool(
&self,
input: &Value,
workspace: &Path,
) -> Result<ToolResult, ToolError>;
fn execute_tool_search(
&self,
tool_name: &str,
input: &Value,
catalog: &[Tool],
active: &mut HashSet<String>,
) -> Result<ToolResult, ToolError>;
fn reset_scratchpad_step(&mut self);
async fn refresh_system_prompt(&mut self, mode: TurnLoopMode);
async fn add_session_message(&mut self, message: Message);
async fn emit_session_updated(&mut self);
async fn run_auto_compaction(&mut self, client: &dyn LlmClient);
fn estimated_input_tokens(&self) -> usize;
async fn flush_pending_lsp_diagnostics(&mut self);
async fn layered_context_checkpoint(&mut self);
fn decorate_auth_error_message(&self, message: String) -> String;
async fn recover_context_overflow(
&mut self,
client: &dyn LlmClient,
reason: &str,
max_output_tokens: u32,
) -> bool;
async fn run_capacity_pre_request_checkpoint(
&mut self,
turn: &TurnContext,
client: Option<&dyn LlmClient>,
mode: TurnLoopMode,
) -> bool;
#[allow(clippy::too_many_arguments)]
async fn run_capacity_post_tool_checkpoint(
&mut self,
turn: &mut TurnContext,
mode: TurnLoopMode,
tool_registry: Option<&Self::ToolRegistry>,
tool_exec_lock: Arc<RwLock<()>>,
mcp_pool: Option<Arc<AsyncMutex<Self::McpPool>>>,
step_error_count: usize,
consecutive_tool_error_steps: u32,
) -> bool;
fn effective_reasoning_effort_for_request(&mut self) -> Option<String>;
fn parse_streaming_tool_input(&self, buffer: &str) -> Option<Value>;
fn final_streaming_tool_input(&self, state: &ToolUseState) -> Value;
async fn ensure_mcp_pool_for_tools(
&mut self,
tool_uses: &[ToolUseState],
) -> Option<Arc<AsyncMutex<Self::McpPool>>>;
fn resolve_hallucinated_tool_name(
&self,
name: &str,
catalog: &[Tool],
registry: Option<&Self::ToolRegistry>,
) -> Option<String>;
fn tool_plan_approval_meta(
&self,
tool_name: &str,
tool_input: &Value,
registry: Option<&Self::ToolRegistry>,
) -> ToolPlanApprovalMeta;
#[allow(clippy::too_many_arguments)]
async fn execute_tool_plans(
&mut self,
mode: TurnLoopMode,
plans: Vec<ToolExecutionPlan>,
tool_catalog: &[Tool],
active_tool_names: &mut HashSet<String>,
tool_registry: Option<&Self::ToolRegistry>,
mcp_pool: Option<Arc<AsyncMutex<Self::McpPool>>>,
tool_exec_lock: Arc<RwLock<()>>,
) -> Vec<ToolExecOutcome>;
async fn run_capacity_error_escalation_checkpoint(
&mut self,
turn: &mut TurnContext,
mode: TurnLoopMode,
step_error_count: usize,
consecutive_tool_error_steps: u32,
error_categories: &[ErrorCategory],
) -> bool;
async fn run_post_edit_lsp_hook(&mut self, tool_name: &str, tool_input: &Value);
fn record_scratchpad_tool_outcome(&mut self, tool_name: &str, success: bool);
async fn record_long_horizon_tool_outcome(
&mut self,
_tool_name: &str,
_tool_input: &Value,
_result: &str,
_success: bool,
) {
}
fn take_long_horizon_tool_suffix(&mut self) -> Option<String> {
None
}
async fn maybe_lht_pre_request_hooks(&mut self, _mode: TurnLoopMode) {}
async fn maybe_continue_at_step_limit(&mut self, _turn: &TurnContext) -> bool {
false
}
async fn maybe_continue_after_loop_guard_halt(&mut self, _turn: &TurnContext) -> bool {
false
}
async fn maybe_cycle_handoff_on_context_overflow(
&mut self,
_turn: &TurnContext,
_mode: TurnLoopMode,
) -> bool {
false
}
async fn maybe_advance_cycle_at_checkpoint(&mut self, _mode: TurnLoopMode) -> bool {
false
}
async fn note_incomplete_stop_if_lht(&mut self) {}
fn on_audit_scratchpad_bind_success(
&mut self,
_mode: TurnLoopMode,
_tool_name: &str,
_catalog: &mut [Tool],
_active: &mut HashSet<String>,
) {
}
async fn maybe_inject_scratchpad_summary(&mut self) -> bool;
async fn maybe_inject_scratchpad_reminder(&mut self);
async fn handle_no_tool_uses(
&mut self,
turn: &mut TurnContext,
pending_steers: &mut Vec<String>,
current_text_visible: &str,
has_sendable_assistant_content: bool,
) -> TurnLoopControl;
fn pre_tool_snapshot(&self, workspace: &Path, tool_id: &str);
}