llm 1.3.8

A Rust library unifying multiple LLM backends.
Documentation
use std::collections::HashMap;

use crate::config::AppConfig;
use crate::conversation::{Conversation, ConversationId, ConversationManager, MessageId};
use crate::dialogue::DialogueController;
use crate::history::BacktrackState;
use crate::input::{InputBuffer, InputHistory};
use crate::persistence::JsonConversationStore;
use crate::provider::{ProviderHandle, ProviderOverrides, ProviderRegistry};
use crate::skills::SkillCatalog;
use crate::terminal::TerminalCapabilities;

use super::overlay::OverlayState;
use super::scroll::ScrollState;
use super::status::AppStatus;
use super::PasteDetector;
use super::{AnimationState, CollapsibleState, StatusMetrics};

pub struct AppState {
    pub config: AppConfig,
    pub provider_registry: ProviderRegistry,
    pub store: JsonConversationStore,
    pub conversations: ConversationManager,
    pub skills: SkillCatalog,
    pub input: InputBuffer,
    pub history: InputHistory,
    pub status: AppStatus,
    pub status_metrics: StatusMetrics,
    pub collapsible: CollapsibleState,
    pub backtrack: BacktrackState,
    pub overlay: OverlayState,
    pub scroll: ScrollState,
    pub provider_cache: HashMap<ConversationId, ProviderHandle>,
    pub selected_message: Option<MessageId>,
    pub input_mode: InputMode,
    pub focus: Focus,
    pub terminal_size: (u16, u16),
    pub terminal_caps: TerminalCapabilities,
    pub animation: AnimationState,
    pub paste_detector: PasteDetector,
    pub should_quit: bool,
    pub session_overrides: ProviderOverrides,
    /// Active dialogue controller for multi-LLM conversations.
    pub dialogue_controller: Option<DialogueController>,
}

impl AppState {
    pub fn new(
        config: AppConfig,
        registry: ProviderRegistry,
        store: JsonConversationStore,
        terminal_caps: TerminalCapabilities,
    ) -> Self {
        Self {
            config,
            provider_registry: registry,
            store,
            conversations: ConversationManager::new(),
            skills: SkillCatalog::default(),
            input: InputBuffer::default(),
            history: InputHistory::default(),
            status: AppStatus::Idle,
            status_metrics: StatusMetrics::default(),
            collapsible: CollapsibleState::default(),
            backtrack: BacktrackState::default(),
            overlay: OverlayState::None,
            scroll: ScrollState::default(),
            provider_cache: HashMap::new(),
            selected_message: None,
            input_mode: InputMode::Insert,
            focus: Focus::Input,
            terminal_size: (0, 0),
            terminal_caps,
            animation: AnimationState::default(),
            paste_detector: PasteDetector::default(),
            should_quit: false,
            session_overrides: ProviderOverrides::default(),
            dialogue_controller: None,
        }
    }

    pub fn active_conversation(&self) -> Option<&Conversation> {
        self.conversations.active()
    }

    pub fn active_conversation_mut(&mut self) -> Option<&mut Conversation> {
        self.conversations.active_mut()
    }

    pub fn active_conversation_id(&self) -> Option<ConversationId> {
        self.conversations.active_id()
    }

    pub fn mark_dirty(&mut self) {
        if let Some(conv) = self.active_conversation_mut() {
            conv.dirty = true;
        }
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum InputMode {
    Insert,
    Normal,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Focus {
    Input,
    Messages,
}