140 lines · 3.8 KB · Rust
RawDownload
use crate::{AgentTool, Thread, ToolCallEventStream, ToolInput};use agent_client_protocol::schema as acp;use gpui::{App, SharedString, Task, WeakEntity};use schemars::JsonSchema;use serde::{Deserialize, Serialize};use std::sync::Arc; const MAX_TITLE_LEN: usize = 200; /// Updates the current session title.#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]pub struct UpdateTitleToolInput {    /// A concise, human-readable title for the current session.    pub title: String,} pub struct UpdateTitleTool {    thread: WeakEntity<Thread>,} impl UpdateTitleTool {    pub fn new(thread: WeakEntity<Thread>) -> Self {        Self { thread }    }     pub(crate) fn title_for_input(        input: Result<UpdateTitleToolInput, serde_json::Value>,    ) -> SharedString {        let Ok(input) = input else {            return "Update title".into();        };        let Ok(title) = normalize_title(&input.title) else {            return "Update title".into();        };        format!("Update title: {title}").into()    }} impl AgentTool for UpdateTitleTool {    type Input = UpdateTitleToolInput;    type Output = String;     const NAME: &'static str = "update_title";     fn kind() -> acp::ToolKind {        acp::ToolKind::Think    }     fn initial_title(        &self,        input: Result<Self::Input, serde_json::Value>,        _cx: &mut App,    ) -> SharedString {        Self::title_for_input(input)    }     fn run(        self: Arc<Self>,        input: ToolInput<Self::Input>,        _event_stream: ToolCallEventStream,        cx: &mut App,    ) -> Task<Result<Self::Output, Self::Output>> {        let thread = self.thread.clone();        cx.spawn(async move |cx| {            let input = input.recv().await.map_err(|error| error.to_string())?;            let title = normalize_title(&input.title)?;             thread                .update(cx, |thread, cx| {                    thread.set_title(title.into(), cx);                })                .map_err(|error| error.to_string())?;             Ok("Session title updated".to_string())        })    }     fn replay(        &self,        input: Self::Input,        _output: Self::Output,        event_stream: ToolCallEventStream,        cx: &mut App,    ) -> anyhow::Result<()> {        let title = self.initial_title(Ok(input), cx).to_string();        event_stream.update_fields(acp::ToolCallUpdateFields::new().title(title));        Ok(())    }} fn normalize_title(title: &str) -> Result<String, String> {    let title = title.lines().next().unwrap_or("").trim();    if title.is_empty() {        return Err("Title cannot be empty".to_string());    }    Ok(util::truncate_and_trailoff(title, MAX_TITLE_LEN))} #[cfg(test)]mod tests {    use super::*;    use gpui::TestAppContext;     #[test]    fn test_normalize_title() {        assert_eq!(            normalize_title("  Title from model\nignored").unwrap(),            "Title from model"        );        assert!(normalize_title(" \nignored").is_err());    }     #[gpui::test]    async fn test_initial_title(cx: &mut TestAppContext) {        let tool = UpdateTitleTool::new(WeakEntity::new_invalid());         let title = cx.update(|cx| {            tool.initial_title(                Ok(UpdateTitleToolInput {                    title: "Investigate title updates".to_string(),                }),                cx,            )        });        assert_eq!(            title,            SharedString::from("Update title: Investigate title updates")        );         let title = cx.update(|cx| {            tool.initial_title(                Ok(UpdateTitleToolInput {                    title: " ".to_string(),                }),                cx,            )        });        assert_eq!(title, SharedString::from("Update title"));    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t