llm 1.3.8

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

use chrono::Utc;

use crate::provider::ProviderId;

use super::id::ConversationId;
use super::state::Conversation;

#[derive(Debug)]
pub struct ConversationManager {
    conversations: VecDeque<Conversation>,
    active_id: Option<ConversationId>,
}

impl ConversationManager {
    pub fn new() -> Self {
        Self {
            conversations: VecDeque::new(),
            active_id: None,
        }
    }

    pub fn add(&mut self, conversation: Conversation) {
        let id = conversation.id;
        self.conversations.push_front(conversation);
        self.active_id = Some(id);
    }

    pub fn list(&self) -> impl Iterator<Item = &Conversation> {
        self.conversations.iter()
    }

    pub fn active(&self) -> Option<&Conversation> {
        let id = self.active_id?;
        self.conversations.iter().find(|c| c.id == id)
    }

    pub fn active_mut(&mut self) -> Option<&mut Conversation> {
        let id = self.active_id?;
        self.conversations.iter_mut().find(|c| c.id == id)
    }

    pub fn set_active(&mut self, id: ConversationId) -> bool {
        if self.conversations.iter().any(|c| c.id == id) {
            self.active_id = Some(id);
            true
        } else {
            false
        }
    }

    pub fn new_conversation(
        &mut self,
        provider_id: ProviderId,
        model: Option<String>,
        system_prompt: Option<String>,
    ) -> ConversationId {
        let conversation = Conversation::new(provider_id, model, system_prompt);
        let id = conversation.id;
        self.add(conversation);
        id
    }

    pub fn fork_conversation(&mut self, id: ConversationId) -> Option<ConversationId> {
        let mut cloned = self.conversations.iter().find(|c| c.id == id)?.clone();
        let now = Utc::now();
        cloned.id = ConversationId::new();
        cloned.parent_id = Some(id);
        cloned.created_at = now;
        cloned.updated_at = now;
        cloned.title = format!("Copy of {}", cloned.title);
        cloned.dirty = true;
        self.add(cloned);
        self.active_id
    }

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