Skip to main content

codetether_agent/session/
title.rs

1//! Title generation and context-change hooks.
2
3use anyhow::Result;
4use chrono::Utc;
5
6use super::helper::text::truncate_with_ellipsis;
7use super::types::Session;
8
9impl Session {
10    /// Generate a title from the first user message if one is not already
11    /// set.
12    pub async fn generate_title(&mut self) -> Result<()> {
13        if self.title.is_some() {
14            return Ok(());
15        }
16        self.set_title_from_first_user_message();
17        Ok(())
18    }
19
20    /// Regenerate the title from the first user message, even if already
21    /// set.
22    pub async fn regenerate_title(&mut self) -> Result<()> {
23        self.set_title_from_first_user_message();
24        Ok(())
25    }
26
27    fn set_title_from_first_user_message(&mut self) {
28        let Some(msg) = self
29            .messages
30            .iter()
31            .find(|m| m.role == crate::provider::Role::User)
32        else {
33            return;
34        };
35        let text: String = msg
36            .content
37            .iter()
38            .filter_map(|p| match p {
39                crate::provider::ContentPart::Text { text } => Some(text.clone()),
40                _ => None,
41            })
42            .collect::<Vec<_>>()
43            .join(" ");
44        self.title = Some(truncate_with_ellipsis(&text, 47));
45    }
46
47    /// Set a custom title for the session.
48    pub fn set_title(&mut self, title: impl Into<String>) {
49        self.title = Some(title.into());
50        self.updated_at = Utc::now();
51    }
52
53    /// Clear the title, allowing it to be regenerated on the next call to
54    /// [`Session::generate_title`].
55    pub fn clear_title(&mut self) {
56        self.title = None;
57        self.updated_at = Utc::now();
58    }
59
60    /// React to a context change (directory change, model change, etc.).
61    /// Bumps `updated_at` and optionally regenerates the title.
62    pub async fn on_context_change(&mut self, regenerate_title: bool) -> Result<()> {
63        self.updated_at = Utc::now();
64        if regenerate_title {
65            self.regenerate_title().await?;
66        }
67        Ok(())
68    }
69}