collet 0.1.1

Relentless agentic coding orchestrator with zero-drop agent loops
Documentation
use super::super::App;
use crate::agent::r#loop::AgentEvent;
use crate::tui::state::{ChatMessage, MessageRole, SwarmPhase, SwarmUiStatus};

impl App {
    pub(crate) fn auto_continue(
        &mut self,
        reason: &crate::agent::guard::StopReason,
        event_tx: tokio::sync::mpsc::UnboundedSender<AgentEvent>,
    ) {
        self.continuation_count += 1;

        let continuation_prompt = format!(
            "The previous execution was stopped: {reason}. \
             This is auto-continuation round {round}/{max}. \
             Review what was accomplished so far and continue the remaining work. \
             Focus on completing the original task: {task}",
            reason = reason,
            round = self.continuation_count,
            max = self.config.max_continuations,
            task = self.current_task,
        );

        self.state.messages.push(ChatMessage::text(
            MessageRole::System,
            format!(
                "⟳ Auto-continuing ({}/{}): {}",
                self.continuation_count, self.config.max_continuations, reason,
            ),
        ));

        // self.context is already set — dispatch_agent will take() it
        self.state.input = continuation_prompt;
        self.state.cursor = self.state.input.len();
        self.submit_message(event_tx);
    }

    pub(crate) fn fire_pending_dispatch(&mut self, d: crate::app::PendingDispatch) {
        use crate::app::PendingDispatch;
        let PendingDispatch {
            context,
            augmented_input,
            event_tx,
            effective_mode,
            agent_name,
            additional_agents,
            client,
            config,
            working_dir,
            lsp_manager,
            trust_level,
            cancel,
            approval_gate,
            approval_req_tx_swarm,
            images,
            shared_mcp,
            shared_skills,
            shared_tool_index,
        } = d;

        // Fast mode always forces single-agent (no swarm).
        let effective_mode = if self.fast_mode {
            crate::agent::swarm::config::CollaborationMode::None
        } else {
            effective_mode
        };

        if effective_mode.is_parallel() {
            let collab_config = self.config.collaboration.clone();
            let coordinator = {
                // The deferred client may carry an auto-routed model (e.g. light-tier).
                // The SwarmCoordinator manages its own coordinator/worker model selection
                // via CollaborationConfig, so reset to the base config model here.
                let mut swarm_client = client.clone();
                swarm_client.model = config.model.clone();
                let mut c = crate::agent::swarm::coordinator::SwarmCoordinator::new(
                    config.clone(),
                    collab_config,
                    swarm_client,
                    working_dir.clone(),
                    lsp_manager.clone(),
                    config.agents.clone(),
                );
                if !agent_name.is_empty() && agent_name != "arbor" {
                    c = c.with_preferred_agent(agent_name);
                }
                if !additional_agents.is_empty() {
                    c = c.with_additional_agents(additional_agents);
                }
                if let (Some(mcp), Some(skills), Some(idx)) = (
                    &self.cached_mcp,
                    &self.cached_skills,
                    &self.cached_tool_index,
                ) {
                    c = c.with_shared_resources(mcp.clone(), skills.clone(), idx.clone());
                }
                c
            }
            .with_approval(
                approval_gate.shared_mode(),
                approval_req_tx_swarm,
                self.session_approvals.clone(),
            );
            self.swarm_knowledge = Some(coordinator.shared_knowledge());
            self.state.swarm_status = Some(SwarmUiStatus {
                mode_label: format!("{}", effective_mode).to_uppercase(),
                agents: Vec::new(),
                phase: SwarmPhase::Analyzing,
                pending_conflicts: Vec::new(),
            });
            tokio::spawn(async move {
                coordinator
                    .run_or_recover(context, augmented_input, event_tx, cancel)
                    .await;
            });
        } else {
            tokio::spawn(async move {
                if let Some(mcp) = shared_mcp {
                    crate::agent::r#loop::run_with_shared_mcp(
                        crate::agent::r#loop::AgentParams {
                            client,
                            config,
                            context,
                            user_msg: augmented_input,
                            working_dir,
                            event_tx,
                            cancel,
                            lsp_manager,
                            trust_level,
                            approval_gate,
                            images,
                        },
                        crate::agent::r#loop::SwarmParams {
                            mcp_manager: mcp,
                            shared_knowledge: None,
                            shared_tool_index,
                            shared_skill_registry: shared_skills,
                            instruction_rx: None,
                        },
                    )
                    .await;
                } else {
                    crate::agent::r#loop::run_with_mode(crate::agent::r#loop::AgentParams {
                        client,
                        config,
                        context,
                        user_msg: augmented_input,
                        working_dir,
                        event_tx,
                        cancel,
                        lsp_manager,
                        trust_level,
                        approval_gate,
                        images,
                    })
                    .await;
                }
            });
        }
    }
}