Rename `assistant_context` crate to `assistant_text_thread` (#41024)

Bennet Fenner created

Previously we had `Context` and `ContextStore` in both `agent_ui` (used
to store context for the inline assistant) and `assistant_context` (used
for text threads) which is confusing.
This PR makes it so that the `assistant_context` concepts are now called
`TextThread*`, the crate was renamed to `assistant_text_thread`

Release Notes:

- N/A

Change summary

Cargo.lock                                                      |  94 
Cargo.toml                                                      |   4 
crates/agent/Cargo.toml                                         |   4 
crates/agent/src/agent.rs                                       |  20 
crates/agent/src/history_store.rs                               |  42 
crates/agent/src/native_agent_server.rs                         |   7 
crates/agent/src/tests/mod.rs                                   |   5 
crates/agent_ui/Cargo.toml                                      |   4 
crates/agent_ui/src/acp/entry_view_state.rs                     |   6 
crates/agent_ui/src/acp/message_editor.rs                       |  28 
crates/agent_ui/src/acp/thread_history.rs                       |   8 
crates/agent_ui/src/acp/thread_view.rs                          |  22 
crates/agent_ui/src/agent_panel.rs                              | 154 
crates/agent_ui/src/agent_ui.rs                                 |   2 
crates/agent_ui/src/context.rs                                  |  12 
crates/agent_ui/src/context_store.rs                            |  37 
crates/agent_ui/src/context_strip.rs                            |  16 
crates/agent_ui/src/inline_assistant.rs                         |   8 
crates/agent_ui/src/slash_command_picker.rs                     |   4 
crates/agent_ui/src/text_thread_editor.rs                       | 352 +-
crates/agent_ui/src/ui/context_pill.rs                          |   4 
crates/assistant_text_thread/Cargo.toml                         |   4 
crates/assistant_text_thread/LICENSE-GPL                        |   0 
crates/assistant_text_thread/src/assistant_text_thread.rs       |  15 
crates/assistant_text_thread/src/assistant_text_thread_tests.rs | 408 +-
crates/assistant_text_thread/src/text_thread.rs                 | 318 +-
crates/assistant_text_thread/src/text_thread_store.rs           | 343 +-
crates/collab/Cargo.toml                                        |   2 
crates/collab/src/tests/integration_tests.rs                    |  52 
crates/collab/src/tests/test_server.rs                          |   2 
crates/paths/src/paths.rs                                       |   2 
31 files changed, 1,007 insertions(+), 972 deletions(-)

Detailed changes

Cargo.lock πŸ”—

@@ -142,7 +142,7 @@ dependencies = [
  "agent_servers",
  "agent_settings",
  "anyhow",
- "assistant_context",
+ "assistant_text_thread",
  "chrono",
  "client",
  "clock",
@@ -315,9 +315,9 @@ dependencies = [
  "ai_onboarding",
  "anyhow",
  "arrayvec",
- "assistant_context",
  "assistant_slash_command",
  "assistant_slash_commands",
+ "assistant_text_thread",
  "audio",
  "buffer_diff",
  "chrono",
@@ -803,107 +803,107 @@ dependencies = [
 ]
 
 [[package]]
-name = "assistant_context"
+name = "assistant_slash_command"
 version = "0.1.0"
 dependencies = [
- "agent_settings",
  "anyhow",
- "assistant_slash_command",
- "assistant_slash_commands",
- "chrono",
- "client",
- "clock",
- "cloud_llm_client",
+ "async-trait",
  "collections",
- "context_server",
- "fs",
+ "derive_more 0.99.20",
+ "extension",
  "futures 0.3.31",
- "fuzzy",
  "gpui",
- "indoc",
  "language",
  "language_model",
- "log",
- "open_ai",
  "parking_lot",
- "paths",
  "pretty_assertions",
- "project",
- "prompt_store",
- "proto",
- "rand 0.9.2",
- "regex",
- "rpc",
  "serde",
  "serde_json",
- "settings",
- "smallvec",
- "smol",
- "telemetry_events",
- "text",
  "ui",
- "unindent",
  "util",
- "uuid",
  "workspace",
- "zed_env_vars",
 ]
 
 [[package]]
-name = "assistant_slash_command"
+name = "assistant_slash_commands"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "async-trait",
+ "assistant_slash_command",
+ "chrono",
  "collections",
- "derive_more 0.99.20",
- "extension",
+ "context_server",
+ "editor",
+ "feature_flags",
+ "fs",
  "futures 0.3.31",
+ "fuzzy",
+ "globset",
  "gpui",
+ "html_to_markdown",
+ "http_client",
  "language",
- "language_model",
- "parking_lot",
  "pretty_assertions",
+ "project",
+ "prompt_store",
+ "rope",
  "serde",
  "serde_json",
+ "settings",
+ "smol",
+ "text",
  "ui",
  "util",
  "workspace",
+ "worktree",
+ "zlog",
 ]
 
 [[package]]
-name = "assistant_slash_commands"
+name = "assistant_text_thread"
 version = "0.1.0"
 dependencies = [
+ "agent_settings",
  "anyhow",
  "assistant_slash_command",
+ "assistant_slash_commands",
  "chrono",
+ "client",
+ "clock",
+ "cloud_llm_client",
  "collections",
  "context_server",
- "editor",
- "feature_flags",
  "fs",
  "futures 0.3.31",
  "fuzzy",
- "globset",
  "gpui",
- "html_to_markdown",
- "http_client",
+ "indoc",
  "language",
+ "language_model",
+ "log",
+ "open_ai",
+ "parking_lot",
+ "paths",
  "pretty_assertions",
  "project",
  "prompt_store",
- "rope",
+ "proto",
+ "rand 0.9.2",
+ "regex",
+ "rpc",
  "serde",
  "serde_json",
  "settings",
+ "smallvec",
  "smol",
+ "telemetry_events",
  "text",
  "ui",
+ "unindent",
  "util",
+ "uuid",
  "workspace",
- "worktree",
- "zlog",
+ "zed_env_vars",
 ]
 
 [[package]]
@@ -3324,8 +3324,8 @@ version = "0.44.0"
 dependencies = [
  "agent_settings",
  "anyhow",
- "assistant_context",
  "assistant_slash_command",
+ "assistant_text_thread",
  "async-trait",
  "async-tungstenite",
  "audio",

Cargo.toml πŸ”—

@@ -13,7 +13,7 @@ members = [
     "crates/anthropic",
     "crates/askpass",
     "crates/assets",
-    "crates/assistant_context",
+    "crates/assistant_text_thread",
     "crates/assistant_slash_command",
     "crates/assistant_slash_commands",
     "crates/audio",
@@ -246,7 +246,7 @@ ai_onboarding = { path = "crates/ai_onboarding" }
 anthropic = { path = "crates/anthropic" }
 askpass = { path = "crates/askpass" }
 assets = { path = "crates/assets" }
-assistant_context = { path = "crates/assistant_context" }
+assistant_text_thread = { path = "crates/assistant_text_thread" }
 assistant_slash_command = { path = "crates/assistant_slash_command" }
 assistant_slash_commands = { path = "crates/assistant_slash_commands" }
 audio = { path = "crates/audio" }

crates/agent/Cargo.toml πŸ”—

@@ -24,7 +24,7 @@ agent-client-protocol.workspace = true
 agent_servers.workspace = true
 agent_settings.workspace = true
 anyhow.workspace = true
-assistant_context.workspace = true
+assistant_text_thread.workspace = true
 chrono.workspace = true
 client.workspace = true
 cloud_llm_client.workspace = true
@@ -76,7 +76,7 @@ zstd.workspace = true
 
 [dev-dependencies]
 agent_servers = { workspace = true, "features" = ["test-support"] }
-assistant_context = { workspace = true, "features" = ["test-support"] }
+assistant_text_thread = { workspace = true, "features" = ["test-support"] }
 client = { workspace = true, "features" = ["test-support"] }
 clock = { workspace = true, "features" = ["test-support"] }
 context_server = { workspace = true, "features" = ["test-support"] }

crates/agent/src/agent.rs πŸ”—

@@ -1266,8 +1266,9 @@ mod internal_tests {
         )
         .await;
         let project = Project::test(fs.clone(), [], cx).await;
-        let context_store = cx.new(|cx| assistant_context::ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store =
+            cx.new(|cx| assistant_text_thread::TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
         let agent = NativeAgent::new(
             project.clone(),
             history_store,
@@ -1327,8 +1328,9 @@ mod internal_tests {
         let fs = FakeFs::new(cx.executor());
         fs.insert_tree("/", json!({ "a": {}  })).await;
         let project = Project::test(fs.clone(), [], cx).await;
-        let context_store = cx.new(|cx| assistant_context::ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store =
+            cx.new(|cx| assistant_text_thread::TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
         let connection = NativeAgentConnection(
             NativeAgent::new(
                 project.clone(),
@@ -1402,8 +1404,9 @@ mod internal_tests {
         .await;
         let project = Project::test(fs.clone(), [], cx).await;
 
-        let context_store = cx.new(|cx| assistant_context::ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store =
+            cx.new(|cx| assistant_text_thread::TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
 
         // Create the agent and connection
         let agent = NativeAgent::new(
@@ -1474,8 +1477,9 @@ mod internal_tests {
         )
         .await;
         let project = Project::test(fs.clone(), [path!("/a").as_ref()], cx).await;
-        let context_store = cx.new(|cx| assistant_context::ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store =
+            cx.new(|cx| assistant_text_thread::TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
         let agent = NativeAgent::new(
             project.clone(),
             history_store.clone(),

crates/agent/src/history_store.rs πŸ”—

@@ -2,12 +2,12 @@ use crate::{DbThread, DbThreadMetadata, ThreadsDatabase};
 use acp_thread::MentionUri;
 use agent_client_protocol as acp;
 use anyhow::{Context as _, Result, anyhow};
-use assistant_context::{AssistantContext, SavedContextMetadata};
+use assistant_text_thread::{SavedTextThreadMetadata, TextThread};
 use chrono::{DateTime, Utc};
 use db::kvp::KEY_VALUE_STORE;
 use gpui::{App, AsyncApp, Entity, SharedString, Task, prelude::*};
 use itertools::Itertools;
-use paths::contexts_dir;
+use paths::text_threads_dir;
 use project::Project;
 use serde::{Deserialize, Serialize};
 use std::{collections::VecDeque, path::Path, rc::Rc, sync::Arc, time::Duration};
@@ -50,21 +50,23 @@ pub fn load_agent_thread(
 #[derive(Clone, Debug)]
 pub enum HistoryEntry {
     AcpThread(DbThreadMetadata),
-    TextThread(SavedContextMetadata),
+    TextThread(SavedTextThreadMetadata),
 }
 
 impl HistoryEntry {
     pub fn updated_at(&self) -> DateTime<Utc> {
         match self {
             HistoryEntry::AcpThread(thread) => thread.updated_at,
-            HistoryEntry::TextThread(context) => context.mtime.to_utc(),
+            HistoryEntry::TextThread(text_thread) => text_thread.mtime.to_utc(),
         }
     }
 
     pub fn id(&self) -> HistoryEntryId {
         match self {
             HistoryEntry::AcpThread(thread) => HistoryEntryId::AcpThread(thread.id.clone()),
-            HistoryEntry::TextThread(context) => HistoryEntryId::TextThread(context.path.clone()),
+            HistoryEntry::TextThread(text_thread) => {
+                HistoryEntryId::TextThread(text_thread.path.clone())
+            }
         }
     }
 
@@ -74,9 +76,9 @@ impl HistoryEntry {
                 id: thread.id.clone(),
                 name: thread.title.to_string(),
             },
-            HistoryEntry::TextThread(context) => MentionUri::TextThread {
-                path: context.path.as_ref().to_owned(),
-                name: context.title.to_string(),
+            HistoryEntry::TextThread(text_thread) => MentionUri::TextThread {
+                path: text_thread.path.as_ref().to_owned(),
+                name: text_thread.title.to_string(),
             },
         }
     }
@@ -90,7 +92,7 @@ impl HistoryEntry {
                     &thread.title
                 }
             }
-            HistoryEntry::TextThread(context) => &context.title,
+            HistoryEntry::TextThread(text_thread) => &text_thread.title,
         }
     }
 }
@@ -120,7 +122,7 @@ enum SerializedRecentOpen {
 pub struct HistoryStore {
     threads: Vec<DbThreadMetadata>,
     entries: Vec<HistoryEntry>,
-    text_thread_store: Entity<assistant_context::ContextStore>,
+    text_thread_store: Entity<assistant_text_thread::TextThreadStore>,
     recently_opened_entries: VecDeque<HistoryEntryId>,
     _subscriptions: Vec<gpui::Subscription>,
     _save_recently_opened_entries_task: Task<()>,
@@ -128,7 +130,7 @@ pub struct HistoryStore {
 
 impl HistoryStore {
     pub fn new(
-        text_thread_store: Entity<assistant_context::ContextStore>,
+        text_thread_store: Entity<assistant_text_thread::TextThreadStore>,
         cx: &mut Context<Self>,
     ) -> Self {
         let subscriptions =
@@ -192,16 +194,16 @@ impl HistoryStore {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         self.text_thread_store
-            .update(cx, |store, cx| store.delete_local_context(path, cx))
+            .update(cx, |store, cx| store.delete_local(path, cx))
     }
 
     pub fn load_text_thread(
         &self,
         path: Arc<Path>,
         cx: &mut Context<Self>,
-    ) -> Task<Result<Entity<AssistantContext>>> {
+    ) -> Task<Result<Entity<TextThread>>> {
         self.text_thread_store
-            .update(cx, |store, cx| store.open_local_context(path, cx))
+            .update(cx, |store, cx| store.open_local(path, cx))
     }
 
     pub fn reload(&self, cx: &mut Context<Self>) {
@@ -243,7 +245,7 @@ impl HistoryStore {
         history_entries.extend(
             self.text_thread_store
                 .read(cx)
-                .unordered_contexts()
+                .unordered_text_threads()
                 .cloned()
                 .map(HistoryEntry::TextThread),
         );
@@ -278,14 +280,14 @@ impl HistoryStore {
         let context_entries = self
             .text_thread_store
             .read(cx)
-            .unordered_contexts()
-            .flat_map(|context| {
+            .unordered_text_threads()
+            .flat_map(|text_thread| {
                 self.recently_opened_entries
                     .iter()
                     .enumerate()
                     .flat_map(|(index, entry)| match entry {
-                        HistoryEntryId::TextThread(path) if &context.path == path => {
-                            Some((index, HistoryEntry::TextThread(context.clone())))
+                        HistoryEntryId::TextThread(path) if &text_thread.path == path => {
+                            Some((index, HistoryEntry::TextThread(text_thread.clone())))
                         }
                         _ => None,
                     })
@@ -347,7 +349,7 @@ impl HistoryStore {
                         acp::SessionId(id.as_str().into()),
                     )),
                     SerializedRecentOpen::TextThread(file_name) => Some(
-                        HistoryEntryId::TextThread(contexts_dir().join(file_name).into()),
+                        HistoryEntryId::TextThread(text_threads_dir().join(file_name).into()),
                     ),
                 })
                 .collect();

crates/agent/src/native_agent_server.rs πŸ”—

@@ -81,7 +81,7 @@ impl AgentServer for NativeAgentServer {
 mod tests {
     use super::*;
 
-    use assistant_context::ContextStore;
+    use assistant_text_thread::TextThreadStore;
     use gpui::AppContext;
 
     agent_servers::e2e_tests::common_e2e_tests!(
@@ -116,8 +116,9 @@ mod tests {
             });
 
             let history = cx.update(|cx| {
-                let context_store = cx.new(move |cx| ContextStore::fake(project.clone(), cx));
-                cx.new(move |cx| HistoryStore::new(context_store, cx))
+                let text_thread_store =
+                    cx.new(move |cx| TextThreadStore::fake(project.clone(), cx));
+                cx.new(move |cx| HistoryStore::new(text_thread_store, cx))
             });
 
             NativeAgentServer::new(fs.clone(), history)

crates/agent/src/tests/mod.rs πŸ”—

@@ -1834,8 +1834,9 @@ async fn test_agent_connection(cx: &mut TestAppContext) {
     fake_fs.insert_tree(path!("/test"), json!({})).await;
     let project = Project::test(fake_fs.clone(), [Path::new("/test")], cx).await;
     let cwd = Path::new("/test");
-    let context_store = cx.new(|cx| assistant_context::ContextStore::fake(project.clone(), cx));
-    let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+    let text_thread_store =
+        cx.new(|cx| assistant_text_thread::TextThreadStore::fake(project.clone(), cx));
+    let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
 
     // Create agent and connection
     let agent = NativeAgent::new(

crates/agent_ui/Cargo.toml πŸ”—

@@ -25,7 +25,7 @@ agent_settings.workspace = true
 ai_onboarding.workspace = true
 anyhow.workspace = true
 arrayvec.workspace = true
-assistant_context.workspace = true
+assistant_text_thread.workspace = true
 assistant_slash_command.workspace = true
 assistant_slash_commands.workspace = true
 audio.workspace = true
@@ -102,7 +102,7 @@ zed_actions.workspace = true
 [dev-dependencies]
 acp_thread = { workspace = true, features = ["test-support"] }
 agent = { workspace = true, features = ["test-support"] }
-assistant_context = { workspace = true, features = ["test-support"] }
+assistant_text_thread = { workspace = true, features = ["test-support"] }
 buffer_diff = { workspace = true, features = ["test-support"] }
 db = { workspace = true, features = ["test-support"] }
 editor = { workspace = true, features = ["test-support"] }

crates/agent_ui/src/acp/entry_view_state.rs πŸ”—

@@ -402,7 +402,7 @@ mod tests {
     use agent::HistoryStore;
     use agent_client_protocol as acp;
     use agent_settings::AgentSettings;
-    use assistant_context::ContextStore;
+    use assistant_text_thread::TextThreadStore;
     use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};
     use editor::{EditorSettings, RowInfo};
     use fs::FakeFs;
@@ -466,8 +466,8 @@ mod tests {
             connection.send_update(session_id, acp::SessionUpdate::ToolCall(tool_call), cx)
         });
 
-        let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
 
         let view_state = cx.new(|_cx| {
             EntryViewState::new(

crates/agent_ui/src/acp/message_editor.rs πŸ”—

@@ -629,12 +629,12 @@ impl MessageEditor {
         path: PathBuf,
         cx: &mut Context<Self>,
     ) -> Task<Result<Mention>> {
-        let context = self.history_store.update(cx, |store, cx| {
+        let text_thread_task = self.history_store.update(cx, |store, cx| {
             store.load_text_thread(path.as_path().into(), cx)
         });
         cx.spawn(async move |_, cx| {
-            let context = context.await?;
-            let xml = context.update(cx, |context, cx| context.to_xml(cx))?;
+            let text_thread = text_thread_task.await?;
+            let xml = text_thread.update(cx, |text_thread, cx| text_thread.to_xml(cx))?;
             Ok(Mention::Text {
                 content: xml,
                 tracked_buffers: Vec::new(),
@@ -1591,7 +1591,7 @@ mod tests {
     use acp_thread::MentionUri;
     use agent::{HistoryStore, outline};
     use agent_client_protocol as acp;
-    use assistant_context::ContextStore;
+    use assistant_text_thread::TextThreadStore;
     use editor::{AnchorRangeExt as _, Editor, EditorMode};
     use fs::FakeFs;
     use futures::StreamExt as _;
@@ -1622,8 +1622,8 @@ mod tests {
         let (workspace, cx) =
             cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
 
-        let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
 
         let message_editor = cx.update(|window, cx| {
             cx.new(|cx| {
@@ -1727,8 +1727,8 @@ mod tests {
         .await;
 
         let project = Project::test(fs.clone(), ["/test".as_ref()], cx).await;
-        let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
         let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default()));
         // Start with no available commands - simulating Claude which doesn't support slash commands
         let available_commands = Rc::new(RefCell::new(vec![]));
@@ -1891,8 +1891,8 @@ mod tests {
 
         let mut cx = VisualTestContext::from_window(*window, cx);
 
-        let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
         let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default()));
         let available_commands = Rc::new(RefCell::new(vec![
             acp::AvailableCommand {
@@ -2131,8 +2131,8 @@ mod tests {
             opened_editors.push(buffer);
         }
 
-        let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
         let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default()));
 
         let (message_editor, editor) = workspace.update_in(&mut cx, |workspace, window, cx| {
@@ -2658,8 +2658,8 @@ mod tests {
         let (workspace, cx) =
             cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
 
-        let context_store = cx.new(|cx| ContextStore::fake(project.clone(), cx));
-        let history_store = cx.new(|cx| HistoryStore::new(context_store, cx));
+        let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
+        let history_store = cx.new(|cx| HistoryStore::new(text_thread_store, cx));
 
         let message_editor = cx.update(|window, cx| {
             cx.new(|cx| {

crates/agent_ui/src/acp/thread_history.rs πŸ”—

@@ -324,8 +324,8 @@ impl AcpThreadHistory {
             HistoryEntry::AcpThread(thread) => self
                 .history_store
                 .update(cx, |this, cx| this.delete_thread(thread.id.clone(), cx)),
-            HistoryEntry::TextThread(context) => self.history_store.update(cx, |this, cx| {
-                this.delete_text_thread(context.path.clone(), cx)
+            HistoryEntry::TextThread(text_thread) => self.history_store.update(cx, |this, cx| {
+                this.delete_text_thread(text_thread.path.clone(), cx)
             }),
         };
         task.detach_and_log_err(cx);
@@ -635,12 +635,12 @@ impl RenderOnce for AcpHistoryEntryElement {
                                     });
                                 }
                             }
-                            HistoryEntry::TextThread(context) => {
+                            HistoryEntry::TextThread(text_thread) => {
                                 if let Some(panel) = workspace.read(cx).panel::<AgentPanel>(cx) {
                                     panel.update(cx, |panel, cx| {
                                         panel
                                             .open_saved_text_thread(
-                                                context.path.clone(),
+                                                text_thread.path.clone(),
                                                 window,
                                                 cx,
                                             )

crates/agent_ui/src/acp/thread_view.rs πŸ”—

@@ -5414,9 +5414,11 @@ impl AcpThreadView {
             HistoryEntry::AcpThread(thread) => self.history_store.update(cx, |history, cx| {
                 history.delete_thread(thread.id.clone(), cx)
             }),
-            HistoryEntry::TextThread(context) => self.history_store.update(cx, |history, cx| {
-                history.delete_text_thread(context.path.clone(), cx)
-            }),
+            HistoryEntry::TextThread(text_thread) => {
+                self.history_store.update(cx, |history, cx| {
+                    history.delete_text_thread(text_thread.path.clone(), cx)
+                })
+            }
         };
         task.detach_and_log_err(cx);
     }
@@ -5735,7 +5737,7 @@ fn terminal_command_markdown_style(window: &Window, cx: &App) -> MarkdownStyle {
 pub(crate) mod tests {
     use acp_thread::StubAgentConnection;
     use agent_client_protocol::SessionId;
-    use assistant_context::ContextStore;
+    use assistant_text_thread::TextThreadStore;
     use editor::EditorSettings;
     use fs::FakeFs;
     use gpui::{EventEmitter, SemanticVersion, TestAppContext, VisualTestContext};
@@ -5898,10 +5900,10 @@ pub(crate) mod tests {
         let (workspace, cx) =
             cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
 
-        let context_store =
-            cx.update(|_window, cx| cx.new(|cx| ContextStore::fake(project.clone(), cx)));
+        let text_thread_store =
+            cx.update(|_window, cx| cx.new(|cx| TextThreadStore::fake(project.clone(), cx)));
         let history_store =
-            cx.update(|_window, cx| cx.new(|cx| HistoryStore::new(context_store, cx)));
+            cx.update(|_window, cx| cx.new(|cx| HistoryStore::new(text_thread_store, cx)));
 
         let thread_view = cx.update(|window, cx| {
             cx.new(|cx| {
@@ -6170,10 +6172,10 @@ pub(crate) mod tests {
         let (workspace, cx) =
             cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
 
-        let context_store =
-            cx.update(|_window, cx| cx.new(|cx| ContextStore::fake(project.clone(), cx)));
+        let text_thread_store =
+            cx.update(|_window, cx| cx.new(|cx| TextThreadStore::fake(project.clone(), cx)));
         let history_store =
-            cx.update(|_window, cx| cx.new(|cx| HistoryStore::new(context_store, cx)));
+            cx.update(|_window, cx| cx.new(|cx| HistoryStore::new(text_thread_store, cx)));
 
         let connection = Rc::new(StubAgentConnection::new());
         let thread_view = cx.update(|window, cx| {

crates/agent_ui/src/agent_panel.rs πŸ”—

@@ -36,8 +36,8 @@ use crate::{
 use agent_settings::AgentSettings;
 use ai_onboarding::AgentPanelOnboarding;
 use anyhow::{Result, anyhow};
-use assistant_context::{AssistantContext, ContextEvent, ContextSummary};
 use assistant_slash_command::SlashCommandWorkingSet;
+use assistant_text_thread::{TextThread, TextThreadEvent, TextThreadSummary};
 use client::{UserStore, zed_urls};
 use cloud_llm_client::{Plan, PlanV1, PlanV2, UsageLimit};
 use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer};
@@ -199,7 +199,7 @@ enum ActiveView {
         thread_view: Entity<AcpThreadView>,
     },
     TextThread {
-        context_editor: Entity<TextThreadEditor>,
+        text_thread_editor: Entity<TextThreadEditor>,
         title_editor: Entity<Editor>,
         buffer_search_bar: Entity<BufferSearchBar>,
         _subscriptions: Vec<gpui::Subscription>,
@@ -301,13 +301,13 @@ impl ActiveView {
     }
 
     pub fn text_thread(
-        context_editor: Entity<TextThreadEditor>,
+        text_thread_editor: Entity<TextThreadEditor>,
         acp_history_store: Entity<agent::HistoryStore>,
         language_registry: Arc<LanguageRegistry>,
         window: &mut Window,
         cx: &mut App,
     ) -> Self {
-        let title = context_editor.read(cx).title(cx).to_string();
+        let title = text_thread_editor.read(cx).title(cx).to_string();
 
         let editor = cx.new(|cx| {
             let mut editor = Editor::single_line(window, cx);
@@ -323,7 +323,7 @@ impl ActiveView {
         let subscriptions = vec![
             window.subscribe(&editor, cx, {
                 {
-                    let context_editor = context_editor.clone();
+                    let text_thread_editor = text_thread_editor.clone();
                     move |editor, event, window, cx| match event {
                         EditorEvent::BufferEdited => {
                             if suppress_first_edit {
@@ -332,19 +332,19 @@ impl ActiveView {
                             }
                             let new_summary = editor.read(cx).text(cx);
 
-                            context_editor.update(cx, |context_editor, cx| {
-                                context_editor
-                                    .context()
-                                    .update(cx, |assistant_context, cx| {
-                                        assistant_context.set_custom_summary(new_summary, cx);
+                            text_thread_editor.update(cx, |text_thread_editor, cx| {
+                                text_thread_editor
+                                    .text_thread()
+                                    .update(cx, |text_thread, cx| {
+                                        text_thread.set_custom_summary(new_summary, cx);
                                     })
                             })
                         }
                         EditorEvent::Blurred => {
                             if editor.read(cx).text(cx).is_empty() {
-                                let summary = context_editor
+                                let summary = text_thread_editor
                                     .read(cx)
-                                    .context()
+                                    .text_thread()
                                     .read(cx)
                                     .summary()
                                     .or_default();
@@ -358,17 +358,17 @@ impl ActiveView {
                     }
                 }
             }),
-            window.subscribe(&context_editor.read(cx).context().clone(), cx, {
+            window.subscribe(&text_thread_editor.read(cx).text_thread().clone(), cx, {
                 let editor = editor.clone();
-                move |assistant_context, event, window, cx| match event {
-                    ContextEvent::SummaryGenerated => {
-                        let summary = assistant_context.read(cx).summary().or_default();
+                move |text_thread, event, window, cx| match event {
+                    TextThreadEvent::SummaryGenerated => {
+                        let summary = text_thread.read(cx).summary().or_default();
 
                         editor.update(cx, |editor, cx| {
                             editor.set_text(summary, window, cx);
                         })
                     }
-                    ContextEvent::PathChanged { old_path, new_path } => {
+                    TextThreadEvent::PathChanged { old_path, new_path } => {
                         acp_history_store.update(cx, |history_store, cx| {
                             if let Some(old_path) = old_path {
                                 history_store
@@ -389,11 +389,11 @@ impl ActiveView {
         let buffer_search_bar =
             cx.new(|cx| BufferSearchBar::new(Some(language_registry), window, cx));
         buffer_search_bar.update(cx, |buffer_search_bar, cx| {
-            buffer_search_bar.set_active_pane_item(Some(&context_editor), window, cx)
+            buffer_search_bar.set_active_pane_item(Some(&text_thread_editor), window, cx)
         });
 
         Self::TextThread {
-            context_editor,
+            text_thread_editor,
             title_editor: editor,
             buffer_search_bar,
             _subscriptions: subscriptions,
@@ -410,7 +410,7 @@ pub struct AgentPanel {
     language_registry: Arc<LanguageRegistry>,
     acp_history: Entity<AcpThreadHistory>,
     history_store: Entity<agent::HistoryStore>,
-    text_thread_store: Entity<assistant_context::ContextStore>,
+    text_thread_store: Entity<assistant_text_thread::TextThreadStore>,
     prompt_store: Option<Entity<PromptStore>>,
     context_server_registry: Entity<ContextServerRegistry>,
     inline_assist_context_store: Entity<ContextStore>,
@@ -474,7 +474,7 @@ impl AgentPanel {
             let text_thread_store = workspace
                 .update(cx, |workspace, cx| {
                     let project = workspace.project().clone();
-                    assistant_context::ContextStore::new(
+                    assistant_text_thread::TextThreadStore::new(
                         project,
                         prompt_builder,
                         slash_commands,
@@ -512,7 +512,7 @@ impl AgentPanel {
 
     fn new(
         workspace: &Workspace,
-        text_thread_store: Entity<assistant_context::ContextStore>,
+        text_thread_store: Entity<assistant_text_thread::TextThreadStore>,
         prompt_store: Option<Entity<PromptStore>>,
         window: &mut Window,
         cx: &mut Context<Self>,
@@ -565,8 +565,8 @@ impl AgentPanel {
             DefaultView::TextThread => {
                 let context = text_thread_store.update(cx, |store, cx| store.create(cx));
                 let lsp_adapter_delegate = make_lsp_adapter_delegate(&project.clone(), cx).unwrap();
-                let context_editor = cx.new(|cx| {
-                    let mut editor = TextThreadEditor::for_context(
+                let text_thread_editor = cx.new(|cx| {
+                    let mut editor = TextThreadEditor::for_text_thread(
                         context,
                         fs.clone(),
                         workspace.clone(),
@@ -579,7 +579,7 @@ impl AgentPanel {
                     editor
                 });
                 ActiveView::text_thread(
-                    context_editor,
+                    text_thread_editor,
                     history_store.clone(),
                     language_registry.clone(),
                     window,
@@ -736,8 +736,8 @@ impl AgentPanel {
             .log_err()
             .flatten();
 
-        let context_editor = cx.new(|cx| {
-            let mut editor = TextThreadEditor::for_context(
+        let text_thread_editor = cx.new(|cx| {
+            let mut editor = TextThreadEditor::for_text_thread(
                 context,
                 self.fs.clone(),
                 self.workspace.clone(),
@@ -757,7 +757,7 @@ impl AgentPanel {
 
         self.set_active_view(
             ActiveView::text_thread(
-                context_editor.clone(),
+                text_thread_editor.clone(),
                 self.history_store.clone(),
                 self.language_registry.clone(),
                 window,
@@ -766,7 +766,7 @@ impl AgentPanel {
             window,
             cx,
         );
-        context_editor.focus_handle(cx).focus(window);
+        text_thread_editor.focus_handle(cx).focus(window);
     }
 
     fn external_thread(
@@ -905,20 +905,20 @@ impl AgentPanel {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
-        let context = self
+        let text_thread_task = self
             .history_store
             .update(cx, |store, cx| store.load_text_thread(path, cx));
         cx.spawn_in(window, async move |this, cx| {
-            let context = context.await?;
+            let text_thread = text_thread_task.await?;
             this.update_in(cx, |this, window, cx| {
-                this.open_text_thread(context, window, cx);
+                this.open_text_thread(text_thread, window, cx);
             })
         })
     }
 
     pub(crate) fn open_text_thread(
         &mut self,
-        context: Entity<AssistantContext>,
+        text_thread: Entity<TextThread>,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
@@ -926,8 +926,8 @@ impl AgentPanel {
             .log_err()
             .flatten();
         let editor = cx.new(|cx| {
-            TextThreadEditor::for_context(
-                context,
+            TextThreadEditor::for_text_thread(
+                text_thread,
                 self.fs.clone(),
                 self.workspace.clone(),
                 self.project.clone(),
@@ -965,8 +965,10 @@ impl AgentPanel {
                         ActiveView::ExternalAgentThread { thread_view } => {
                             thread_view.focus_handle(cx).focus(window);
                         }
-                        ActiveView::TextThread { context_editor, .. } => {
-                            context_editor.focus_handle(cx).focus(window);
+                        ActiveView::TextThread {
+                            text_thread_editor, ..
+                        } => {
+                            text_thread_editor.focus_handle(cx).focus(window);
                         }
                         ActiveView::History | ActiveView::Configuration => {}
                     }
@@ -1183,9 +1185,11 @@ impl AgentPanel {
         }
     }
 
-    pub(crate) fn active_context_editor(&self) -> Option<Entity<TextThreadEditor>> {
+    pub(crate) fn active_text_thread_editor(&self) -> Option<Entity<TextThreadEditor>> {
         match &self.active_view {
-            ActiveView::TextThread { context_editor, .. } => Some(context_editor.clone()),
+            ActiveView::TextThread {
+                text_thread_editor, ..
+            } => Some(text_thread_editor.clone()),
             _ => None,
         }
     }
@@ -1206,16 +1210,16 @@ impl AgentPanel {
         let new_is_special = new_is_history || new_is_config;
 
         match &new_view {
-            ActiveView::TextThread { context_editor, .. } => {
-                self.history_store.update(cx, |store, cx| {
-                    if let Some(path) = context_editor.read(cx).context().read(cx).path() {
-                        store.push_recently_opened_entry(
-                            agent::HistoryEntryId::TextThread(path.clone()),
-                            cx,
-                        )
-                    }
-                })
-            }
+            ActiveView::TextThread {
+                text_thread_editor, ..
+            } => self.history_store.update(cx, |store, cx| {
+                if let Some(path) = text_thread_editor.read(cx).text_thread().read(cx).path() {
+                    store.push_recently_opened_entry(
+                        agent::HistoryEntryId::TextThread(path.clone()),
+                        cx,
+                    )
+                }
+            }),
             ActiveView::ExternalAgentThread { .. } => {}
             ActiveView::History | ActiveView::Configuration => {}
         }
@@ -1372,7 +1376,9 @@ impl Focusable for AgentPanel {
         match &self.active_view {
             ActiveView::ExternalAgentThread { thread_view, .. } => thread_view.focus_handle(cx),
             ActiveView::History => self.acp_history.focus_handle(cx),
-            ActiveView::TextThread { context_editor, .. } => context_editor.focus_handle(cx),
+            ActiveView::TextThread {
+                text_thread_editor, ..
+            } => text_thread_editor.focus_handle(cx),
             ActiveView::Configuration => {
                 if let Some(configuration) = self.configuration.as_ref() {
                     configuration.focus_handle(cx)
@@ -1507,17 +1513,17 @@ impl AgentPanel {
             }
             ActiveView::TextThread {
                 title_editor,
-                context_editor,
+                text_thread_editor,
                 ..
             } => {
-                let summary = context_editor.read(cx).context().read(cx).summary();
+                let summary = text_thread_editor.read(cx).text_thread().read(cx).summary();
 
                 match summary {
-                    ContextSummary::Pending => Label::new(ContextSummary::DEFAULT)
+                    TextThreadSummary::Pending => Label::new(TextThreadSummary::DEFAULT)
                         .color(Color::Muted)
                         .truncate()
                         .into_any_element(),
-                    ContextSummary::Content(summary) => {
+                    TextThreadSummary::Content(summary) => {
                         if summary.done {
                             div()
                                 .w_full()
@@ -1530,17 +1536,17 @@ impl AgentPanel {
                                 .into_any_element()
                         }
                     }
-                    ContextSummary::Error => h_flex()
+                    TextThreadSummary::Error => h_flex()
                         .w_full()
                         .child(title_editor.clone())
                         .child(
                             IconButton::new("retry-summary-generation", IconName::RotateCcw)
                                 .icon_size(IconSize::Small)
                                 .on_click({
-                                    let context_editor = context_editor.clone();
+                                    let text_thread_editor = text_thread_editor.clone();
                                     move |_, _window, cx| {
-                                        context_editor.update(cx, |context_editor, cx| {
-                                            context_editor.regenerate_summary(cx);
+                                        text_thread_editor.update(cx, |text_thread_editor, cx| {
+                                            text_thread_editor.regenerate_summary(cx);
                                         });
                                     }
                                 })
@@ -2243,7 +2249,7 @@ impl AgentPanel {
 
     fn render_text_thread(
         &self,
-        context_editor: &Entity<TextThreadEditor>,
+        text_thread_editor: &Entity<TextThreadEditor>,
         buffer_search_bar: &Entity<BufferSearchBar>,
         window: &mut Window,
         cx: &mut Context<Self>,
@@ -2277,7 +2283,7 @@ impl AgentPanel {
                     )
                 })
             })
-            .child(context_editor.clone())
+            .child(text_thread_editor.clone())
             .child(self.render_drag_target(cx))
     }
 
@@ -2353,10 +2359,12 @@ impl AgentPanel {
                     thread_view.insert_dragged_files(paths, added_worktrees, window, cx);
                 });
             }
-            ActiveView::TextThread { context_editor, .. } => {
-                context_editor.update(cx, |context_editor, cx| {
+            ActiveView::TextThread {
+                text_thread_editor, ..
+            } => {
+                text_thread_editor.update(cx, |text_thread_editor, cx| {
                     TextThreadEditor::insert_dragged_files(
-                        context_editor,
+                        text_thread_editor,
                         paths,
                         added_worktrees,
                         window,
@@ -2427,7 +2435,7 @@ impl Render for AgentPanel {
                     .child(self.render_drag_target(cx)),
                 ActiveView::History => parent.child(self.acp_history.clone()),
                 ActiveView::TextThread {
-                    context_editor,
+                    text_thread_editor,
                     buffer_search_bar,
                     ..
                 } => {
@@ -2450,7 +2458,7 @@ impl Render for AgentPanel {
                             }
                         })
                         .child(self.render_text_thread(
-                            context_editor,
+                            text_thread_editor,
                             buffer_search_bar,
                             window,
                             cx,
@@ -2528,17 +2536,17 @@ impl rules_library::InlineAssistDelegate for PromptLibraryInlineAssist {
 pub struct ConcreteAssistantPanelDelegate;
 
 impl AgentPanelDelegate for ConcreteAssistantPanelDelegate {
-    fn active_context_editor(
+    fn active_text_thread_editor(
         &self,
         workspace: &mut Workspace,
         _window: &mut Window,
         cx: &mut Context<Workspace>,
     ) -> Option<Entity<TextThreadEditor>> {
         let panel = workspace.panel::<AgentPanel>(cx)?;
-        panel.read(cx).active_context_editor()
+        panel.read(cx).active_text_thread_editor()
     }
 
-    fn open_saved_context(
+    fn open_local_text_thread(
         &self,
         workspace: &mut Workspace,
         path: Arc<Path>,
@@ -2554,10 +2562,10 @@ impl AgentPanelDelegate for ConcreteAssistantPanelDelegate {
         })
     }
 
-    fn open_remote_context(
+    fn open_remote_text_thread(
         &self,
         _workspace: &mut Workspace,
-        _context_id: assistant_context::ContextId,
+        _text_thread_id: assistant_text_thread::TextThreadId,
         _window: &mut Window,
         _cx: &mut Context<Workspace>,
     ) -> Task<Result<Entity<TextThreadEditor>>> {
@@ -2588,15 +2596,15 @@ impl AgentPanelDelegate for ConcreteAssistantPanelDelegate {
                     thread_view.update(cx, |thread_view, cx| {
                         thread_view.insert_selections(window, cx);
                     });
-                } else if let Some(context_editor) = panel.active_context_editor() {
+                } else if let Some(text_thread_editor) = panel.active_text_thread_editor() {
                     let snapshot = buffer.read(cx).snapshot(cx);
                     let selection_ranges = selection_ranges
                         .into_iter()
                         .map(|range| range.to_point(&snapshot))
                         .collect::<Vec<_>>();
 
-                    context_editor.update(cx, |context_editor, cx| {
-                        context_editor.quote_ranges(selection_ranges, snapshot, window, cx)
+                    text_thread_editor.update(cx, |text_thread_editor, cx| {
+                        text_thread_editor.quote_ranges(selection_ranges, snapshot, window, cx)
                     });
                 }
             });

crates/agent_ui/src/agent_ui.rs πŸ”—

@@ -250,7 +250,7 @@ pub fn init(
 ) {
     AgentSettings::register(cx);
 
-    assistant_context::init(client.clone(), cx);
+    assistant_text_thread::init(client.clone(), cx);
     rules_library::init(cx);
     if !is_eval {
         // Initializing the language model from the user settings messes with the eval, so we only initialize them when

crates/agent_ui/src/context.rs πŸ”—

@@ -1,5 +1,5 @@
 use agent::outline;
-use assistant_context::AssistantContext;
+use assistant_text_thread::TextThread;
 use futures::future;
 use futures::{FutureExt, future::Shared};
 use gpui::{App, AppContext as _, ElementId, Entity, SharedString, Task};
@@ -581,7 +581,7 @@ impl Display for ThreadContext {
 
 #[derive(Debug, Clone)]
 pub struct TextThreadContextHandle {
-    pub context: Entity<AssistantContext>,
+    pub text_thread: Entity<TextThread>,
     pub context_id: ContextId,
 }
 
@@ -595,20 +595,20 @@ pub struct TextThreadContext {
 impl TextThreadContextHandle {
     // pub fn lookup_key() ->
     pub fn eq_for_key(&self, other: &Self) -> bool {
-        self.context == other.context
+        self.text_thread == other.text_thread
     }
 
     pub fn hash_for_key<H: Hasher>(&self, state: &mut H) {
-        self.context.hash(state)
+        self.text_thread.hash(state)
     }
 
     pub fn title(&self, cx: &App) -> SharedString {
-        self.context.read(cx).summary().or_default()
+        self.text_thread.read(cx).summary().or_default()
     }
 
     fn load(self, cx: &App) -> Task<Option<AgentContext>> {
         let title = self.title(cx);
-        let text = self.context.read(cx).to_xml(cx);
+        let text = self.text_thread.read(cx).to_xml(cx);
         let context = AgentContext::TextThread(TextThreadContext {
             title,
             text: text.into(),

crates/agent_ui/src/context_store.rs πŸ”—

@@ -5,7 +5,7 @@ use crate::context::{
 };
 use agent_client_protocol as acp;
 use anyhow::{Context as _, Result, anyhow};
-use assistant_context::AssistantContext;
+use assistant_text_thread::TextThread;
 use collections::{HashSet, IndexSet};
 use futures::{self, FutureExt};
 use gpui::{App, Context, Entity, EventEmitter, Image, SharedString, Task, WeakEntity};
@@ -200,13 +200,13 @@ impl ContextStore {
 
     pub fn add_text_thread(
         &mut self,
-        context: Entity<AssistantContext>,
+        text_thread: Entity<TextThread>,
         remove_if_exists: bool,
         cx: &mut Context<Self>,
     ) -> Option<AgentContextHandle> {
         let context_id = self.next_context_id.post_inc();
         let context = AgentContextHandle::TextThread(TextThreadContextHandle {
-            context,
+            text_thread,
             context_id,
         });
 
@@ -353,21 +353,15 @@ impl ContextStore {
                     );
                 };
             }
-            // SuggestedContext::Thread { thread, name: _ } => {
-            //     if let Some(thread) = thread.upgrade() {
-            //         let context_id = self.next_context_id.post_inc();
-            //         self.insert_context(
-            //             AgentContextHandle::Thread(ThreadContextHandle { thread, context_id }),
-            //             cx,
-            //         );
-            //     }
-            // }
-            SuggestedContext::TextThread { context, name: _ } => {
-                if let Some(context) = context.upgrade() {
+            SuggestedContext::TextThread {
+                text_thread,
+                name: _,
+            } => {
+                if let Some(text_thread) = text_thread.upgrade() {
                     let context_id = self.next_context_id.post_inc();
                     self.insert_context(
                         AgentContextHandle::TextThread(TextThreadContextHandle {
-                            context,
+                            text_thread,
                             context_id,
                         }),
                         cx,
@@ -392,7 +386,7 @@ impl ContextStore {
             // }
             AgentContextHandle::TextThread(text_thread_context) => {
                 self.context_text_thread_paths
-                    .extend(text_thread_context.context.read(cx).path().cloned());
+                    .extend(text_thread_context.text_thread.read(cx).path().cloned());
             }
             _ => {}
         }
@@ -414,7 +408,7 @@ impl ContextStore {
                         .remove(thread_context.thread.read(cx).id());
                 }
                 AgentContextHandle::TextThread(text_thread_context) => {
-                    if let Some(path) = text_thread_context.context.read(cx).path() {
+                    if let Some(path) = text_thread_context.text_thread.read(cx).path() {
                         self.context_text_thread_paths.remove(path);
                     }
                 }
@@ -538,13 +532,9 @@ pub enum SuggestedContext {
         icon_path: Option<SharedString>,
         buffer: WeakEntity<Buffer>,
     },
-    // Thread {
-    //     name: SharedString,
-    //     thread: WeakEntity<Thread>,
-    // },
     TextThread {
         name: SharedString,
-        context: WeakEntity<AssistantContext>,
+        text_thread: WeakEntity<TextThread>,
     },
 }
 
@@ -552,7 +542,6 @@ impl SuggestedContext {
     pub fn name(&self) -> &SharedString {
         match self {
             Self::File { name, .. } => name,
-            // Self::Thread { name, .. } => name,
             Self::TextThread { name, .. } => name,
         }
     }
@@ -560,7 +549,6 @@ impl SuggestedContext {
     pub fn icon_path(&self) -> Option<SharedString> {
         match self {
             Self::File { icon_path, .. } => icon_path.clone(),
-            // Self::Thread { .. } => None,
             Self::TextThread { .. } => None,
         }
     }
@@ -568,7 +556,6 @@ impl SuggestedContext {
     pub fn kind(&self) -> ContextKind {
         match self {
             Self::File { .. } => ContextKind::File,
-            // Self::Thread { .. } => ContextKind::Thread,
             Self::TextThread { .. } => ContextKind::TextThread,
         }
     }

crates/agent_ui/src/context_strip.rs πŸ”—

@@ -132,19 +132,19 @@ impl ContextStrip {
         let workspace = self.workspace.upgrade()?;
         let panel = workspace.read(cx).panel::<AgentPanel>(cx)?.read(cx);
 
-        if let Some(active_context_editor) = panel.active_context_editor() {
-            let context = active_context_editor.read(cx).context();
-            let weak_context = context.downgrade();
-            let context = context.read(cx);
-            let path = context.path()?;
+        if let Some(active_text_thread_editor) = panel.active_text_thread_editor() {
+            let text_thread = active_text_thread_editor.read(cx).text_thread();
+            let weak_text_thread = text_thread.downgrade();
+            let text_thread = text_thread.read(cx);
+            let path = text_thread.path()?;
 
             if self.context_store.read(cx).includes_text_thread(path) {
                 return None;
             }
 
             Some(SuggestedContext::TextThread {
-                name: context.summary().or_default(),
-                context: weak_context,
+                name: text_thread.summary().or_default(),
+                text_thread: weak_text_thread,
             })
         } else {
             None
@@ -332,7 +332,7 @@ impl ContextStrip {
             AgentContextHandle::TextThread(text_thread_context) => {
                 workspace.update(cx, |workspace, cx| {
                     if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
-                        let context = text_thread_context.context.clone();
+                        let context = text_thread_context.text_thread.clone();
                         window.defer(cx, move |window, cx| {
                             panel.update(cx, |panel, cx| {
                                 panel.open_text_thread(context, window, cx)

crates/agent_ui/src/inline_assistant.rs πŸ”—

@@ -1508,8 +1508,8 @@ impl InlineAssistant {
             return Some(InlineAssistTarget::Terminal(terminal_view));
         }
 
-        let context_editor = agent_panel
-            .and_then(|panel| panel.read(cx).active_context_editor())
+        let text_thread_editor = agent_panel
+            .and_then(|panel| panel.read(cx).active_text_thread_editor())
             .and_then(|editor| {
                 let editor = &editor.read(cx).editor().clone();
                 if editor.read(cx).is_focused(window) {
@@ -1519,8 +1519,8 @@ impl InlineAssistant {
                 }
             });
 
-        if let Some(context_editor) = context_editor {
-            Some(InlineAssistTarget::Editor(context_editor))
+        if let Some(text_thread_editor) = text_thread_editor {
+            Some(InlineAssistTarget::Editor(text_thread_editor))
         } else if let Some(workspace_editor) = workspace
             .active_item(cx)
             .and_then(|item| item.act_as::<Editor>(cx))

crates/agent_ui/src/slash_command_picker.rs πŸ”—

@@ -155,8 +155,8 @@ impl PickerDelegate for SlashCommandDelegate {
             match command {
                 SlashCommandEntry::Info(info) => {
                     self.active_context_editor
-                        .update(cx, |context_editor, cx| {
-                            context_editor.insert_command(&info.name, window, cx)
+                        .update(cx, |text_thread_editor, cx| {
+                            text_thread_editor.insert_command(&info.name, window, cx)
                         })
                         .ok();
                 }

crates/agent_ui/src/text_thread_editor.rs πŸ”—

@@ -74,10 +74,10 @@ use workspace::{
 use zed_actions::agent::{AddSelectionToThread, ToggleModelSelector};
 
 use crate::{slash_command::SlashCommandCompletionProvider, slash_command_picker};
-use assistant_context::{
-    AssistantContext, CacheStatus, Content, ContextEvent, ContextId, InvokedSlashCommandId,
-    InvokedSlashCommandStatus, Message, MessageId, MessageMetadata, MessageStatus,
-    PendingSlashCommandStatus, ThoughtProcessOutputSection,
+use assistant_text_thread::{
+    CacheStatus, Content, InvokedSlashCommandId, InvokedSlashCommandStatus, Message, MessageId,
+    MessageMetadata, MessageStatus, PendingSlashCommandStatus, TextThread, TextThreadEvent,
+    TextThreadId, ThoughtProcessOutputSection,
 };
 
 actions!(
@@ -126,14 +126,14 @@ pub enum ThoughtProcessStatus {
 }
 
 pub trait AgentPanelDelegate {
-    fn active_context_editor(
+    fn active_text_thread_editor(
         &self,
         workspace: &mut Workspace,
         window: &mut Window,
         cx: &mut Context<Workspace>,
     ) -> Option<Entity<TextThreadEditor>>;
 
-    fn open_saved_context(
+    fn open_local_text_thread(
         &self,
         workspace: &mut Workspace,
         path: Arc<Path>,
@@ -141,10 +141,10 @@ pub trait AgentPanelDelegate {
         cx: &mut Context<Workspace>,
     ) -> Task<Result<()>>;
 
-    fn open_remote_context(
+    fn open_remote_text_thread(
         &self,
         workspace: &mut Workspace,
-        context_id: ContextId,
+        text_thread_id: TextThreadId,
         window: &mut Window,
         cx: &mut Context<Workspace>,
     ) -> Task<Result<Entity<TextThreadEditor>>>;
@@ -177,7 +177,7 @@ struct GlobalAssistantPanelDelegate(Arc<dyn AgentPanelDelegate>);
 impl Global for GlobalAssistantPanelDelegate {}
 
 pub struct TextThreadEditor {
-    context: Entity<AssistantContext>,
+    text_thread: Entity<TextThread>,
     fs: Arc<dyn Fs>,
     slash_commands: Arc<SlashCommandWorkingSet>,
     workspace: WeakEntity<Workspace>,
@@ -223,8 +223,8 @@ impl TextThreadEditor {
         .detach();
     }
 
-    pub fn for_context(
-        context: Entity<AssistantContext>,
+    pub fn for_text_thread(
+        text_thread: Entity<TextThread>,
         fs: Arc<dyn Fs>,
         workspace: WeakEntity<Workspace>,
         project: Entity<Project>,
@@ -233,14 +233,14 @@ impl TextThreadEditor {
         cx: &mut Context<Self>,
     ) -> Self {
         let completion_provider = SlashCommandCompletionProvider::new(
-            context.read(cx).slash_commands().clone(),
+            text_thread.read(cx).slash_commands().clone(),
             Some(cx.entity().downgrade()),
             Some(workspace.clone()),
         );
 
         let editor = cx.new(|cx| {
             let mut editor =
-                Editor::for_buffer(context.read(cx).buffer().clone(), None, window, cx);
+                Editor::for_buffer(text_thread.read(cx).buffer().clone(), None, window, cx);
             editor.disable_scrollbars_and_minimap(window, cx);
             editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
             editor.set_show_line_numbers(false, cx);
@@ -264,18 +264,24 @@ impl TextThreadEditor {
         });
 
         let _subscriptions = vec![
-            cx.observe(&context, |_, _, cx| cx.notify()),
-            cx.subscribe_in(&context, window, Self::handle_context_event),
+            cx.observe(&text_thread, |_, _, cx| cx.notify()),
+            cx.subscribe_in(&text_thread, window, Self::handle_text_thread_event),
             cx.subscribe_in(&editor, window, Self::handle_editor_event),
             cx.subscribe_in(&editor, window, Self::handle_editor_search_event),
             cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
         ];
 
-        let slash_command_sections = context.read(cx).slash_command_output_sections().to_vec();
-        let thought_process_sections = context.read(cx).thought_process_output_sections().to_vec();
-        let slash_commands = context.read(cx).slash_commands().clone();
+        let slash_command_sections = text_thread
+            .read(cx)
+            .slash_command_output_sections()
+            .to_vec();
+        let thought_process_sections = text_thread
+            .read(cx)
+            .thought_process_output_sections()
+            .to_vec();
+        let slash_commands = text_thread.read(cx).slash_commands().clone();
         let mut this = Self {
-            context,
+            text_thread,
             slash_commands,
             editor,
             lsp_adapter_delegate,
@@ -337,8 +343,8 @@ impl TextThreadEditor {
         });
     }
 
-    pub fn context(&self) -> &Entity<AssistantContext> {
-        &self.context
+    pub fn text_thread(&self) -> &Entity<TextThread> {
+        &self.text_thread
     }
 
     pub fn editor(&self) -> &Entity<Editor> {
@@ -350,9 +356,9 @@ impl TextThreadEditor {
         self.editor.update(cx, |editor, cx| {
             editor.insert(&format!("/{command_name}\n\n"), window, cx)
         });
-        let command = self.context.update(cx, |context, cx| {
-            context.reparse(cx);
-            context.parsed_slash_commands()[0].clone()
+        let command = self.text_thread.update(cx, |text_thread, cx| {
+            text_thread.reparse(cx);
+            text_thread.parsed_slash_commands()[0].clone()
         });
         self.run_command(
             command.source_range,
@@ -375,11 +381,14 @@ impl TextThreadEditor {
 
     fn send_to_model(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.last_error = None;
-        if let Some(user_message) = self.context.update(cx, |context, cx| context.assist(cx)) {
+        if let Some(user_message) = self
+            .text_thread
+            .update(cx, |text_thread, cx| text_thread.assist(cx))
+        {
             let new_selection = {
                 let cursor = user_message
                     .start
-                    .to_offset(self.context.read(cx).buffer().read(cx));
+                    .to_offset(self.text_thread.read(cx).buffer().read(cx));
                 cursor..cursor
             };
             self.editor.update(cx, |editor, cx| {
@@ -403,8 +412,8 @@ impl TextThreadEditor {
         self.last_error = None;
 
         if self
-            .context
-            .update(cx, |context, cx| context.cancel_last_assist(cx))
+            .text_thread
+            .update(cx, |text_thread, cx| text_thread.cancel_last_assist(cx))
         {
             return;
         }
@@ -419,13 +428,13 @@ impl TextThreadEditor {
         cx: &mut Context<Self>,
     ) {
         let cursors = self.cursors(cx);
-        self.context.update(cx, |context, cx| {
-            let messages = context
+        self.text_thread.update(cx, |text_thread, cx| {
+            let messages = text_thread
                 .messages_for_offsets(cursors, cx)
                 .into_iter()
                 .map(|message| message.id)
                 .collect();
-            context.cycle_message_roles(messages, cx)
+            text_thread.cycle_message_roles(messages, cx)
         });
     }
 
@@ -491,11 +500,11 @@ impl TextThreadEditor {
         let selections = self.editor.read(cx).selections.disjoint_anchors_arc();
         let mut commands_by_range = HashMap::default();
         let workspace = self.workspace.clone();
-        self.context.update(cx, |context, cx| {
-            context.reparse(cx);
+        self.text_thread.update(cx, |text_thread, cx| {
+            text_thread.reparse(cx);
             for selection in selections.iter() {
                 if let Some(command) =
-                    context.pending_command_for_position(selection.head().text_anchor, cx)
+                    text_thread.pending_command_for_position(selection.head().text_anchor, cx)
                 {
                     commands_by_range
                         .entry(command.source_range.clone())
@@ -533,14 +542,14 @@ impl TextThreadEditor {
         cx: &mut Context<Self>,
     ) {
         if let Some(command) = self.slash_commands.command(name, cx) {
-            let context = self.context.read(cx);
-            let sections = context
+            let text_thread = self.text_thread.read(cx);
+            let sections = text_thread
                 .slash_command_output_sections()
                 .iter()
-                .filter(|section| section.is_valid(context.buffer().read(cx)))
+                .filter(|section| section.is_valid(text_thread.buffer().read(cx)))
                 .cloned()
                 .collect::<Vec<_>>();
-            let snapshot = context.buffer().read(cx).snapshot();
+            let snapshot = text_thread.buffer().read(cx).snapshot();
             let output = command.run(
                 arguments,
                 &sections,
@@ -550,8 +559,8 @@ impl TextThreadEditor {
                 window,
                 cx,
             );
-            self.context.update(cx, |context, cx| {
-                context.insert_command_output(
+            self.text_thread.update(cx, |text_thread, cx| {
+                text_thread.insert_command_output(
                     command_range,
                     name,
                     output,
@@ -562,32 +571,32 @@ impl TextThreadEditor {
         }
     }
 
-    fn handle_context_event(
+    fn handle_text_thread_event(
         &mut self,
-        _: &Entity<AssistantContext>,
-        event: &ContextEvent,
+        _: &Entity<TextThread>,
+        event: &TextThreadEvent,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
-        let context_editor = cx.entity().downgrade();
+        let text_thread_editor = cx.entity().downgrade();
 
         match event {
-            ContextEvent::MessagesEdited => {
+            TextThreadEvent::MessagesEdited => {
                 self.update_message_headers(cx);
                 self.update_image_blocks(cx);
-                self.context.update(cx, |context, cx| {
-                    context.save(Some(Duration::from_millis(500)), self.fs.clone(), cx);
+                self.text_thread.update(cx, |text_thread, cx| {
+                    text_thread.save(Some(Duration::from_millis(500)), self.fs.clone(), cx);
                 });
             }
-            ContextEvent::SummaryChanged => {
+            TextThreadEvent::SummaryChanged => {
                 cx.emit(EditorEvent::TitleChanged);
-                self.context.update(cx, |context, cx| {
-                    context.save(Some(Duration::from_millis(500)), self.fs.clone(), cx);
+                self.text_thread.update(cx, |text_thread, cx| {
+                    text_thread.save(Some(Duration::from_millis(500)), self.fs.clone(), cx);
                 });
             }
-            ContextEvent::SummaryGenerated => {}
-            ContextEvent::PathChanged { .. } => {}
-            ContextEvent::StartedThoughtProcess(range) => {
+            TextThreadEvent::SummaryGenerated => {}
+            TextThreadEvent::PathChanged { .. } => {}
+            TextThreadEvent::StartedThoughtProcess(range) => {
                 let creases = self.insert_thought_process_output_sections(
                     [(
                         ThoughtProcessOutputSection {
@@ -600,7 +609,7 @@ impl TextThreadEditor {
                 );
                 self.pending_thought_process = Some((creases[0], range.start));
             }
-            ContextEvent::EndedThoughtProcess(end) => {
+            TextThreadEvent::EndedThoughtProcess(end) => {
                 if let Some((crease_id, start)) = self.pending_thought_process.take() {
                     self.editor.update(cx, |editor, cx| {
                         let multi_buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
@@ -626,7 +635,7 @@ impl TextThreadEditor {
                     );
                 }
             }
-            ContextEvent::StreamedCompletion => {
+            TextThreadEvent::StreamedCompletion => {
                 self.editor.update(cx, |editor, cx| {
                     if let Some(scroll_position) = self.scroll_position {
                         let snapshot = editor.snapshot(window, cx);
@@ -641,7 +650,7 @@ impl TextThreadEditor {
                     }
                 });
             }
-            ContextEvent::ParsedSlashCommandsUpdated { removed, updated } => {
+            TextThreadEvent::ParsedSlashCommandsUpdated { removed, updated } => {
                 self.editor.update(cx, |editor, cx| {
                     let buffer = editor.buffer().read(cx).snapshot(cx);
                     let (&excerpt_id, _, _) = buffer.as_singleton().unwrap();
@@ -657,12 +666,12 @@ impl TextThreadEditor {
                         updated.iter().map(|command| {
                             let workspace = self.workspace.clone();
                             let confirm_command = Arc::new({
-                                let context_editor = context_editor.clone();
+                                let text_thread_editor = text_thread_editor.clone();
                                 let command = command.clone();
                                 move |window: &mut Window, cx: &mut App| {
-                                    context_editor
-                                        .update(cx, |context_editor, cx| {
-                                            context_editor.run_command(
+                                    text_thread_editor
+                                        .update(cx, |text_thread_editor, cx| {
+                                            text_thread_editor.run_command(
                                                 command.source_range.clone(),
                                                 &command.name,
                                                 &command.arguments,
@@ -712,17 +721,17 @@ impl TextThreadEditor {
                     );
                 })
             }
-            ContextEvent::InvokedSlashCommandChanged { command_id } => {
+            TextThreadEvent::InvokedSlashCommandChanged { command_id } => {
                 self.update_invoked_slash_command(*command_id, window, cx);
             }
-            ContextEvent::SlashCommandOutputSectionAdded { section } => {
+            TextThreadEvent::SlashCommandOutputSectionAdded { section } => {
                 self.insert_slash_command_output_sections([section.clone()], false, window, cx);
             }
-            ContextEvent::Operation(_) => {}
-            ContextEvent::ShowAssistError(error_message) => {
+            TextThreadEvent::Operation(_) => {}
+            TextThreadEvent::ShowAssistError(error_message) => {
                 self.last_error = Some(AssistError::Message(error_message.clone()));
             }
-            ContextEvent::ShowPaymentRequiredError => {
+            TextThreadEvent::ShowPaymentRequiredError => {
                 self.last_error = Some(AssistError::PaymentRequired);
             }
         }
@@ -735,14 +744,14 @@ impl TextThreadEditor {
         cx: &mut Context<Self>,
     ) {
         if let Some(invoked_slash_command) =
-            self.context.read(cx).invoked_slash_command(&command_id)
+            self.text_thread.read(cx).invoked_slash_command(&command_id)
             && let InvokedSlashCommandStatus::Finished = invoked_slash_command.status
         {
             let run_commands_in_ranges = invoked_slash_command.run_commands_in_ranges.clone();
             for range in run_commands_in_ranges {
-                let commands = self.context.update(cx, |context, cx| {
-                    context.reparse(cx);
-                    context
+                let commands = self.text_thread.update(cx, |text_thread, cx| {
+                    text_thread.reparse(cx);
+                    text_thread
                         .pending_commands_for_range(range.clone(), cx)
                         .to_vec()
                 });
@@ -763,7 +772,7 @@ impl TextThreadEditor {
 
         self.editor.update(cx, |editor, cx| {
             if let Some(invoked_slash_command) =
-                self.context.read(cx).invoked_slash_command(&command_id)
+                self.text_thread.read(cx).invoked_slash_command(&command_id)
             {
                 if let InvokedSlashCommandStatus::Finished = invoked_slash_command.status {
                     let buffer = editor.buffer().read(cx).snapshot(cx);
@@ -790,7 +799,7 @@ impl TextThreadEditor {
                     let buffer = editor.buffer().read(cx).snapshot(cx);
                     let (&excerpt_id, _buffer_id, _buffer_snapshot) =
                         buffer.as_singleton().unwrap();
-                    let context = self.context.downgrade();
+                    let context = self.text_thread.downgrade();
                     let range = buffer
                         .anchor_range_in_excerpt(excerpt_id, invoked_slash_command.range.clone())
                         .unwrap();
@@ -1020,7 +1029,7 @@ impl TextThreadEditor {
 
             let render_block = |message: MessageMetadata| -> RenderBlock {
                 Arc::new({
-                    let context = self.context.clone();
+                    let text_thread = self.text_thread.clone();
 
                     move |cx| {
                         let message_id = MessageId(message.timestamp);
@@ -1093,10 +1102,10 @@ impl TextThreadEditor {
                                         )
                                     })
                                     .on_click({
-                                        let context = context.clone();
+                                        let text_thread = text_thread.clone();
                                         move |_, _window, cx| {
-                                            context.update(cx, |context, cx| {
-                                                context.cycle_message_roles(
+                                            text_thread.update(cx, |text_thread, cx| {
+                                                text_thread.cycle_message_roles(
                                                     HashSet::from_iter(Some(message_id)),
                                                     cx,
                                                 )
@@ -1158,11 +1167,11 @@ impl TextThreadEditor {
                                         .icon_position(IconPosition::Start)
                                         .tooltip(Tooltip::text("View Details"))
                                         .on_click({
-                                            let context = context.clone();
+                                            let text_thread = text_thread.clone();
                                             let error = error.clone();
                                             move |_, _window, cx| {
-                                                context.update(cx, |_, cx| {
-                                                    cx.emit(ContextEvent::ShowAssistError(
+                                                text_thread.update(cx, |_, cx| {
+                                                    cx.emit(TextThreadEvent::ShowAssistError(
                                                         error.clone(),
                                                     ));
                                                 });
@@ -1205,7 +1214,7 @@ impl TextThreadEditor {
             };
             let mut new_blocks = vec![];
             let mut block_index_to_message = vec![];
-            for message in self.context.read(cx).messages(cx) {
+            for message in self.text_thread.read(cx).messages(cx) {
                 if blocks_to_remove.remove(&message.id).is_some() {
                     // This is an old message that we might modify.
                     let Some((meta, block_id)) = old_blocks.get_mut(&message.id) else {
@@ -1246,18 +1255,18 @@ impl TextThreadEditor {
     ) -> Option<(String, bool)> {
         const CODE_FENCE_DELIMITER: &str = "```";
 
-        let context_editor = context_editor_view.read(cx).editor.clone();
-        context_editor.update(cx, |context_editor, cx| {
-            let display_map = context_editor.display_snapshot(cx);
-            if context_editor
+        let text_thread_editor = context_editor_view.read(cx).editor.clone();
+        text_thread_editor.update(cx, |text_thread_editor, cx| {
+            let display_map = text_thread_editor.display_snapshot(cx);
+            if text_thread_editor
                 .selections
                 .newest::<Point>(&display_map)
                 .is_empty()
             {
-                let snapshot = context_editor.buffer().read(cx).snapshot(cx);
+                let snapshot = text_thread_editor.buffer().read(cx).snapshot(cx);
                 let (_, _, snapshot) = snapshot.as_singleton()?;
 
-                let head = context_editor
+                let head = text_thread_editor
                     .selections
                     .newest::<Point>(&display_map)
                     .head();
@@ -1277,8 +1286,8 @@ impl TextThreadEditor {
 
                 (!text.is_empty()).then_some((text, true))
             } else {
-                let selection = context_editor.selections.newest_adjusted(&display_map);
-                let buffer = context_editor.buffer().read(cx).snapshot(cx);
+                let selection = text_thread_editor.selections.newest_adjusted(&display_map);
+                let buffer = text_thread_editor.buffer().read(cx).snapshot(cx);
                 let selected_text = buffer.text_for_range(selection.range()).collect::<String>();
 
                 (!selected_text.is_empty()).then_some((selected_text, false))
@@ -1296,7 +1305,7 @@ impl TextThreadEditor {
             return;
         };
         let Some(context_editor_view) =
-            agent_panel_delegate.active_context_editor(workspace, window, cx)
+            agent_panel_delegate.active_text_thread_editor(workspace, window, cx)
         else {
             return;
         };
@@ -1324,7 +1333,7 @@ impl TextThreadEditor {
         let result = maybe!({
             let agent_panel_delegate = <dyn AgentPanelDelegate>::try_global(cx)?;
             let context_editor_view =
-                agent_panel_delegate.active_context_editor(workspace, window, cx)?;
+                agent_panel_delegate.active_text_thread_editor(workspace, window, cx)?;
             Self::get_selection_or_code_block(&context_editor_view, cx)
         });
         let Some((text, is_code_block)) = result else {
@@ -1361,7 +1370,7 @@ impl TextThreadEditor {
             return;
         };
         let Some(context_editor_view) =
-            agent_panel_delegate.active_context_editor(workspace, window, cx)
+            agent_panel_delegate.active_text_thread_editor(workspace, window, cx)
         else {
             return;
         };
@@ -1622,29 +1631,33 @@ impl TextThreadEditor {
             )
         });
 
-        let context = self.context.read(cx);
+        let text_thread = self.text_thread.read(cx);
 
         let mut text = String::new();
 
         // If selection is empty, we want to copy the entire line
         if selection.range().is_empty() {
-            let snapshot = context.buffer().read(cx).snapshot();
+            let snapshot = text_thread.buffer().read(cx).snapshot();
             let point = snapshot.offset_to_point(selection.range().start);
             selection.start = snapshot.point_to_offset(Point::new(point.row, 0));
             selection.end = snapshot
                 .point_to_offset(cmp::min(Point::new(point.row + 1, 0), snapshot.max_point()));
-            for chunk in context.buffer().read(cx).text_for_range(selection.range()) {
+            for chunk in text_thread
+                .buffer()
+                .read(cx)
+                .text_for_range(selection.range())
+            {
                 text.push_str(chunk);
             }
         } else {
-            for message in context.messages(cx) {
+            for message in text_thread.messages(cx) {
                 if message.offset_range.start >= selection.range().end {
                     break;
                 } else if message.offset_range.end >= selection.range().start {
                     let range = cmp::max(message.offset_range.start, selection.range().start)
                         ..cmp::min(message.offset_range.end, selection.range().end);
                     if !range.is_empty() {
-                        for chunk in context.buffer().read(cx).text_for_range(range) {
+                        for chunk in text_thread.buffer().read(cx).text_for_range(range) {
                             text.push_str(chunk);
                         }
                         if message.offset_range.end < selection.range().end {
@@ -1755,7 +1768,7 @@ impl TextThreadEditor {
                 });
             });
 
-            self.context.update(cx, |context, cx| {
+            self.text_thread.update(cx, |text_thread, cx| {
                 for image in images {
                     let Some(render_image) = image.to_image_data(cx.svg_renderer()).log_err()
                     else {
@@ -1765,7 +1778,7 @@ impl TextThreadEditor {
                     let image_task = LanguageModelImage::from_image(Arc::new(image), cx).shared();
 
                     for image_position in image_positions.iter() {
-                        context.insert_content(
+                        text_thread.insert_content(
                             Content::Image {
                                 anchor: image_position.text_anchor,
                                 image_id,
@@ -1786,7 +1799,7 @@ impl TextThreadEditor {
             let excerpt_id = *buffer.as_singleton().unwrap().0;
             let old_blocks = std::mem::take(&mut self.image_blocks);
             let new_blocks = self
-                .context
+                .text_thread
                 .read(cx)
                 .contents(cx)
                 .map(
@@ -1834,36 +1847,36 @@ impl TextThreadEditor {
     }
 
     fn split(&mut self, _: &Split, _window: &mut Window, cx: &mut Context<Self>) {
-        self.context.update(cx, |context, cx| {
+        self.text_thread.update(cx, |text_thread, cx| {
             let selections = self.editor.read(cx).selections.disjoint_anchors_arc();
             for selection in selections.as_ref() {
                 let buffer = self.editor.read(cx).buffer().read(cx).snapshot(cx);
                 let range = selection
                     .map(|endpoint| endpoint.to_offset(&buffer))
                     .range();
-                context.split_message(range, cx);
+                text_thread.split_message(range, cx);
             }
         });
     }
 
     fn save(&mut self, _: &Save, _window: &mut Window, cx: &mut Context<Self>) {
-        self.context.update(cx, |context, cx| {
-            context.save(Some(Duration::from_millis(500)), self.fs.clone(), cx)
+        self.text_thread.update(cx, |text_thread, cx| {
+            text_thread.save(Some(Duration::from_millis(500)), self.fs.clone(), cx)
         });
     }
 
     pub fn title(&self, cx: &App) -> SharedString {
-        self.context.read(cx).summary().or_default()
+        self.text_thread.read(cx).summary().or_default()
     }
 
     pub fn regenerate_summary(&mut self, cx: &mut Context<Self>) {
-        self.context
-            .update(cx, |context, cx| context.summarize(true, cx));
+        self.text_thread
+            .update(cx, |text_thread, cx| text_thread.summarize(true, cx));
     }
 
     fn render_remaining_tokens(&self, cx: &App) -> Option<impl IntoElement + use<>> {
         let (token_count_color, token_count, max_token_count, tooltip) =
-            match token_state(&self.context, cx)? {
+            match token_state(&self.text_thread, cx)? {
                 TokenState::NoTokensLeft {
                     max_token_count,
                     token_count,
@@ -1911,7 +1924,7 @@ impl TextThreadEditor {
     fn render_send_button(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
         let focus_handle = self.focus_handle(cx);
 
-        let (style, tooltip) = match token_state(&self.context, cx) {
+        let (style, tooltip) = match token_state(&self.text_thread, cx) {
             Some(TokenState::NoTokensLeft { .. }) => (
                 ButtonStyle::Tinted(TintColor::Error),
                 Some(Tooltip::text("Token limit reached")(window, cx)),
@@ -1986,7 +1999,7 @@ impl TextThreadEditor {
     }
 
     fn render_burn_mode_toggle(&self, cx: &mut Context<Self>) -> Option<AnyElement> {
-        let context = self.context().read(cx);
+        let text_thread = self.text_thread().read(cx);
         let active_model = LanguageModelRegistry::read_global(cx)
             .default_model()
             .map(|default| default.model)?;
@@ -1994,7 +2007,7 @@ impl TextThreadEditor {
             return None;
         }
 
-        let active_completion_mode = context.completion_mode();
+        let active_completion_mode = text_thread.completion_mode();
         let burn_mode_enabled = active_completion_mode == CompletionMode::Burn;
         let icon = if burn_mode_enabled {
             IconName::ZedBurnModeOn
@@ -2009,8 +2022,8 @@ impl TextThreadEditor {
                 .toggle_state(burn_mode_enabled)
                 .selected_icon_color(Color::Error)
                 .on_click(cx.listener(move |this, _event, _window, cx| {
-                    this.context().update(cx, |context, _cx| {
-                        context.set_completion_mode(match active_completion_mode {
+                    this.text_thread().update(cx, |text_thread, _cx| {
+                        text_thread.set_completion_mode(match active_completion_mode {
                             CompletionMode::Burn => CompletionMode::Normal,
                             CompletionMode::Normal => CompletionMode::Burn,
                         });
@@ -2637,10 +2650,10 @@ impl FollowableItem for TextThreadEditor {
     }
 
     fn to_state_proto(&self, window: &Window, cx: &App) -> Option<proto::view::Variant> {
-        let context = self.context.read(cx);
+        let text_thread = self.text_thread.read(cx);
         Some(proto::view::Variant::ContextEditor(
             proto::view::ContextEditor {
-                context_id: context.id().to_proto(),
+                context_id: text_thread.id().to_proto(),
                 editor: if let Some(proto::view::Variant::Editor(proto)) =
                     self.editor.read(cx).to_state_proto(window, cx)
                 {
@@ -2666,22 +2679,22 @@ impl FollowableItem for TextThreadEditor {
             unreachable!()
         };
 
-        let context_id = ContextId::from_proto(state.context_id);
+        let text_thread_id = TextThreadId::from_proto(state.context_id);
         let editor_state = state.editor?;
 
         let project = workspace.read(cx).project().clone();
         let agent_panel_delegate = <dyn AgentPanelDelegate>::try_global(cx)?;
 
-        let context_editor_task = workspace.update(cx, |workspace, cx| {
-            agent_panel_delegate.open_remote_context(workspace, context_id, window, cx)
+        let text_thread_editor_task = workspace.update(cx, |workspace, cx| {
+            agent_panel_delegate.open_remote_text_thread(workspace, text_thread_id, window, cx)
         });
 
         Some(window.spawn(cx, async move |cx| {
-            let context_editor = context_editor_task.await?;
-            context_editor
-                .update_in(cx, |context_editor, window, cx| {
-                    context_editor.remote_id = Some(id);
-                    context_editor.editor.update(cx, |editor, cx| {
+            let text_thread_editor = text_thread_editor_task.await?;
+            text_thread_editor
+                .update_in(cx, |text_thread_editor, window, cx| {
+                    text_thread_editor.remote_id = Some(id);
+                    text_thread_editor.editor.update(cx, |editor, cx| {
                         editor.apply_update_proto(
                             &project,
                             proto::update_view::Variant::Editor(proto::update_view::Editor {
@@ -2698,7 +2711,7 @@ impl FollowableItem for TextThreadEditor {
                     })
                 })?
                 .await?;
-            Ok(context_editor)
+            Ok(text_thread_editor)
         }))
     }
 
@@ -2745,7 +2758,7 @@ impl FollowableItem for TextThreadEditor {
     }
 
     fn dedup(&self, existing: &Self, _window: &Window, cx: &App) -> Option<item::Dedup> {
-        if existing.context.read(cx).id() == self.context.read(cx).id() {
+        if existing.text_thread.read(cx).id() == self.text_thread.read(cx).id() {
             Some(item::Dedup::KeepExisting)
         } else {
             None
@@ -2757,17 +2770,17 @@ enum PendingSlashCommand {}
 
 fn invoked_slash_command_fold_placeholder(
     command_id: InvokedSlashCommandId,
-    context: WeakEntity<AssistantContext>,
+    text_thread: WeakEntity<TextThread>,
 ) -> FoldPlaceholder {
     FoldPlaceholder {
         constrain_width: false,
         merge_adjacent: false,
         render: Arc::new(move |fold_id, _, cx| {
-            let Some(context) = context.upgrade() else {
+            let Some(text_thread) = text_thread.upgrade() else {
                 return Empty.into_any();
             };
 
-            let Some(command) = context.read(cx).invoked_slash_command(&command_id) else {
+            let Some(command) = text_thread.read(cx).invoked_slash_command(&command_id) else {
                 return Empty.into_any();
             };
 
@@ -2808,14 +2821,15 @@ enum TokenState {
     },
 }
 
-fn token_state(context: &Entity<AssistantContext>, cx: &App) -> Option<TokenState> {
+fn token_state(text_thread: &Entity<TextThread>, cx: &App) -> Option<TokenState> {
     const WARNING_TOKEN_THRESHOLD: f32 = 0.8;
 
     let model = LanguageModelRegistry::read_global(cx)
         .default_model()?
         .model;
-    let token_count = context.read(cx).token_count()?;
-    let max_token_count = model.max_token_count_for_mode(context.read(cx).completion_mode().into());
+    let token_count = text_thread.read(cx).token_count()?;
+    let max_token_count =
+        model.max_token_count_for_mode(text_thread.read(cx).completion_mode().into());
     let token_state = if max_token_count.saturating_sub(token_count) == 0 {
         TokenState::NoTokensLeft {
             max_token_count,
@@ -2927,7 +2941,7 @@ mod tests {
 
     #[gpui::test]
     async fn test_copy_paste_whole_message(cx: &mut TestAppContext) {
-        let (context, context_editor, mut cx) = setup_context_editor_text(vec![
+        let (context, text_thread_editor, mut cx) = setup_text_thread_editor_text(vec![
             (Role::User, "What is the Zed editor?"),
             (
                 Role::Assistant,
@@ -2937,8 +2951,8 @@ mod tests {
         ],cx).await;
 
         // Select & Copy whole user message
-        assert_copy_paste_context_editor(
-            &context_editor,
+        assert_copy_paste_text_thread_editor(
+            &text_thread_editor,
             message_range(&context, 0, &mut cx),
             indoc! {"
                 What is the Zed editor?
@@ -2949,8 +2963,8 @@ mod tests {
         );
 
         // Select & Copy whole assistant message
-        assert_copy_paste_context_editor(
-            &context_editor,
+        assert_copy_paste_text_thread_editor(
+            &text_thread_editor,
             message_range(&context, 1, &mut cx),
             indoc! {"
                 What is the Zed editor?
@@ -2964,7 +2978,7 @@ mod tests {
 
     #[gpui::test]
     async fn test_copy_paste_no_selection(cx: &mut TestAppContext) {
-        let (context, context_editor, mut cx) = setup_context_editor_text(
+        let (context, text_thread_editor, mut cx) = setup_text_thread_editor_text(
             vec![
                 (Role::User, "user1"),
                 (Role::Assistant, "assistant1"),
@@ -2977,8 +2991,8 @@ mod tests {
 
         // Copy and paste first assistant message
         let message_2_range = message_range(&context, 1, &mut cx);
-        assert_copy_paste_context_editor(
-            &context_editor,
+        assert_copy_paste_text_thread_editor(
+            &text_thread_editor,
             message_2_range.start..message_2_range.start,
             indoc! {"
                 user1
@@ -2991,8 +3005,8 @@ mod tests {
 
         // Copy and cut second assistant message
         let message_3_range = message_range(&context, 2, &mut cx);
-        assert_copy_paste_context_editor(
-            &context_editor,
+        assert_copy_paste_text_thread_editor(
+            &text_thread_editor,
             message_3_range.start..message_3_range.start,
             indoc! {"
                 user1
@@ -3079,29 +3093,29 @@ mod tests {
         }
     }
 
-    async fn setup_context_editor_text(
+    async fn setup_text_thread_editor_text(
         messages: Vec<(Role, &str)>,
         cx: &mut TestAppContext,
     ) -> (
-        Entity<AssistantContext>,
+        Entity<TextThread>,
         Entity<TextThreadEditor>,
         VisualTestContext,
     ) {
         cx.update(init_test);
 
         let fs = FakeFs::new(cx.executor());
-        let context = create_context_with_messages(messages, cx);
+        let text_thread = create_text_thread_with_messages(messages, cx);
 
         let project = Project::test(fs.clone(), [path!("/test").as_ref()], cx).await;
         let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
         let workspace = window.root(cx).unwrap();
         let mut cx = VisualTestContext::from_window(*window, cx);
 
-        let context_editor = window
+        let text_thread_editor = window
             .update(&mut cx, |_, window, cx| {
                 cx.new(|cx| {
-                    TextThreadEditor::for_context(
-                        context.clone(),
+                    TextThreadEditor::for_text_thread(
+                        text_thread.clone(),
                         fs,
                         workspace.downgrade(),
                         project,
@@ -3113,59 +3127,59 @@ mod tests {
             })
             .unwrap();
 
-        (context, context_editor, cx)
+        (text_thread, text_thread_editor, cx)
     }
 
     fn message_range(
-        context: &Entity<AssistantContext>,
+        text_thread: &Entity<TextThread>,
         message_ix: usize,
         cx: &mut TestAppContext,
     ) -> Range<usize> {
-        context.update(cx, |context, cx| {
-            context
+        text_thread.update(cx, |text_thread, cx| {
+            text_thread
                 .messages(cx)
                 .nth(message_ix)
                 .unwrap()
                 .anchor_range
-                .to_offset(&context.buffer().read(cx).snapshot())
+                .to_offset(&text_thread.buffer().read(cx).snapshot())
         })
     }
 
-    fn assert_copy_paste_context_editor<T: editor::ToOffset>(
-        context_editor: &Entity<TextThreadEditor>,
+    fn assert_copy_paste_text_thread_editor<T: editor::ToOffset>(
+        text_thread_editor: &Entity<TextThreadEditor>,
         range: Range<T>,
         expected_text: &str,
         cx: &mut VisualTestContext,
     ) {
-        context_editor.update_in(cx, |context_editor, window, cx| {
-            context_editor.editor.update(cx, |editor, cx| {
+        text_thread_editor.update_in(cx, |text_thread_editor, window, cx| {
+            text_thread_editor.editor.update(cx, |editor, cx| {
                 editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
                     s.select_ranges([range])
                 });
             });
 
-            context_editor.copy(&Default::default(), window, cx);
+            text_thread_editor.copy(&Default::default(), window, cx);
 
-            context_editor.editor.update(cx, |editor, cx| {
+            text_thread_editor.editor.update(cx, |editor, cx| {
                 editor.move_to_end(&Default::default(), window, cx);
             });
 
-            context_editor.paste(&Default::default(), window, cx);
+            text_thread_editor.paste(&Default::default(), window, cx);
 
-            context_editor.editor.update(cx, |editor, cx| {
+            text_thread_editor.editor.update(cx, |editor, cx| {
                 assert_eq!(editor.text(cx), expected_text);
             });
         });
     }
 
-    fn create_context_with_messages(
+    fn create_text_thread_with_messages(
         mut messages: Vec<(Role, &str)>,
         cx: &mut TestAppContext,
-    ) -> Entity<AssistantContext> {
+    ) -> Entity<TextThread> {
         let registry = Arc::new(LanguageRegistry::test(cx.executor()));
         let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
         cx.new(|cx| {
-            let mut context = AssistantContext::local(
+            let mut text_thread = TextThread::local(
                 registry,
                 None,
                 None,
@@ -3173,33 +3187,33 @@ mod tests {
                 Arc::new(SlashCommandWorkingSet::default()),
                 cx,
             );
-            let mut message_1 = context.messages(cx).next().unwrap();
+            let mut message_1 = text_thread.messages(cx).next().unwrap();
             let (role, text) = messages.remove(0);
 
             loop {
                 if role == message_1.role {
-                    context.buffer().update(cx, |buffer, cx| {
+                    text_thread.buffer().update(cx, |buffer, cx| {
                         buffer.edit([(message_1.offset_range, text)], None, cx);
                     });
                     break;
                 }
                 let mut ids = HashSet::default();
                 ids.insert(message_1.id);
-                context.cycle_message_roles(ids, cx);
-                message_1 = context.messages(cx).next().unwrap();
+                text_thread.cycle_message_roles(ids, cx);
+                message_1 = text_thread.messages(cx).next().unwrap();
             }
 
             let mut last_message_id = message_1.id;
             for (role, text) in messages {
-                context.insert_message_after(last_message_id, role, MessageStatus::Done, cx);
-                let message = context.messages(cx).last().unwrap();
+                text_thread.insert_message_after(last_message_id, role, MessageStatus::Done, cx);
+                let message = text_thread.messages(cx).last().unwrap();
                 last_message_id = message.id;
-                context.buffer().update(cx, |buffer, cx| {
+                text_thread.buffer().update(cx, |buffer, cx| {
                     buffer.edit([(message.offset_range, text)], None, cx);
                 })
             }
 
-            context
+            text_thread
         })
     }
 

crates/agent_ui/src/ui/context_pill.rs πŸ”—

@@ -497,9 +497,9 @@ impl AddedContext {
             icon_path: None,
             status: ContextStatus::Ready,
             render_hover: {
-                let context = handle.context.clone();
+                let text_thread = handle.text_thread.clone();
                 Some(Rc::new(move |_, cx| {
-                    let text = context.read(cx).to_xml(cx);
+                    let text = text_thread.read(cx).to_xml(cx);
                     ContextPillHover::new_text(text.into(), cx).into()
                 }))
             },

crates/assistant_context/Cargo.toml β†’ crates/assistant_text_thread/Cargo.toml πŸ”—

@@ -1,5 +1,5 @@
 [package]
-name = "assistant_context"
+name = "assistant_text_thread"
 version = "0.1.0"
 edition.workspace = true
 publish.workspace = true
@@ -9,7 +9,7 @@ license = "GPL-3.0-or-later"
 workspace = true
 
 [lib]
-path = "src/assistant_context.rs"
+path = "src/assistant_text_thread.rs"
 
 [features]
 test-support = []

crates/assistant_text_thread/src/assistant_text_thread.rs πŸ”—

@@ -0,0 +1,15 @@
+#[cfg(test)]
+mod assistant_text_thread_tests;
+mod text_thread;
+mod text_thread_store;
+
+pub use crate::text_thread::*;
+pub use crate::text_thread_store::*;
+
+use client::Client;
+use gpui::App;
+use std::sync::Arc;
+
+pub fn init(client: Arc<Client>, _: &mut App) {
+    text_thread_store::init(&client.into());
+}

crates/assistant_context/src/assistant_context_tests.rs β†’ crates/assistant_text_thread/src/assistant_text_thread_tests.rs πŸ”—

@@ -1,6 +1,6 @@
 use crate::{
-    AssistantContext, CacheStatus, ContextEvent, ContextId, ContextOperation, ContextSummary,
-    InvokedSlashCommandId, MessageCacheMetadata, MessageId, MessageStatus,
+    CacheStatus, InvokedSlashCommandId, MessageCacheMetadata, MessageId, MessageStatus, TextThread,
+    TextThreadEvent, TextThreadId, TextThreadOperation, TextThreadSummary,
 };
 use anyhow::Result;
 use assistant_slash_command::{
@@ -47,8 +47,8 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
 
     let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
-    let context = cx.new(|cx| {
-        AssistantContext::local(
+    let text_thread = cx.new(|cx| {
+        TextThread::local(
             registry,
             None,
             None,
@@ -57,21 +57,21 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
             cx,
         )
     });
-    let buffer = context.read(cx).buffer.clone();
+    let buffer = text_thread.read(cx).buffer().clone();
 
-    let message_1 = context.read(cx).message_anchors[0].clone();
+    let message_1 = text_thread.read(cx).message_anchors[0].clone();
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![(message_1.id, Role::User, 0..0)]
     );
 
-    let message_2 = context.update(cx, |context, cx| {
+    let message_2 = text_thread.update(cx, |context, cx| {
         context
             .insert_message_after(message_1.id, Role::Assistant, MessageStatus::Done, cx)
             .unwrap()
     });
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..1),
             (message_2.id, Role::Assistant, 1..1)
@@ -82,20 +82,20 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
         buffer.edit([(0..0, "1"), (1..1, "2")], None, cx)
     });
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..2),
             (message_2.id, Role::Assistant, 2..3)
         ]
     );
 
-    let message_3 = context.update(cx, |context, cx| {
+    let message_3 = text_thread.update(cx, |context, cx| {
         context
             .insert_message_after(message_2.id, Role::User, MessageStatus::Done, cx)
             .unwrap()
     });
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..2),
             (message_2.id, Role::Assistant, 2..4),
@@ -103,13 +103,13 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
         ]
     );
 
-    let message_4 = context.update(cx, |context, cx| {
+    let message_4 = text_thread.update(cx, |context, cx| {
         context
             .insert_message_after(message_2.id, Role::User, MessageStatus::Done, cx)
             .unwrap()
     });
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..2),
             (message_2.id, Role::Assistant, 2..4),
@@ -122,7 +122,7 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
         buffer.edit([(4..4, "C"), (5..5, "D")], None, cx)
     });
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..2),
             (message_2.id, Role::Assistant, 2..4),
@@ -134,7 +134,7 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
     // Deleting across message boundaries merges the messages.
     buffer.update(cx, |buffer, cx| buffer.edit([(1..4, "")], None, cx));
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..3),
             (message_3.id, Role::User, 3..4),
@@ -144,7 +144,7 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
     // Undoing the deletion should also undo the merge.
     buffer.update(cx, |buffer, cx| buffer.undo(cx));
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..2),
             (message_2.id, Role::Assistant, 2..4),
@@ -156,7 +156,7 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
     // Redoing the deletion should also redo the merge.
     buffer.update(cx, |buffer, cx| buffer.redo(cx));
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..3),
             (message_3.id, Role::User, 3..4),
@@ -164,13 +164,13 @@ fn test_inserting_and_removing_messages(cx: &mut App) {
     );
 
     // Ensure we can still insert after a merged message.
-    let message_5 = context.update(cx, |context, cx| {
+    let message_5 = text_thread.update(cx, |context, cx| {
         context
             .insert_message_after(message_1.id, Role::System, MessageStatus::Done, cx)
             .unwrap()
     });
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..3),
             (message_5.id, Role::System, 3..4),
@@ -186,8 +186,8 @@ fn test_message_splitting(cx: &mut App) {
     let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
 
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
-    let context = cx.new(|cx| {
-        AssistantContext::local(
+    let text_thread = cx.new(|cx| {
+        TextThread::local(
             registry.clone(),
             None,
             None,
@@ -196,11 +196,11 @@ fn test_message_splitting(cx: &mut App) {
             cx,
         )
     });
-    let buffer = context.read(cx).buffer.clone();
+    let buffer = text_thread.read(cx).buffer().clone();
 
-    let message_1 = context.read(cx).message_anchors[0].clone();
+    let message_1 = text_thread.read(cx).message_anchors[0].clone();
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![(message_1.id, Role::User, 0..0)]
     );
 
@@ -208,26 +208,28 @@ fn test_message_splitting(cx: &mut App) {
         buffer.edit([(0..0, "aaa\nbbb\nccc\nddd\n")], None, cx)
     });
 
-    let (_, message_2) = context.update(cx, |context, cx| context.split_message(3..3, cx));
+    let (_, message_2) =
+        text_thread.update(cx, |text_thread, cx| text_thread.split_message(3..3, cx));
     let message_2 = message_2.unwrap();
 
     // We recycle newlines in the middle of a split message
     assert_eq!(buffer.read(cx).text(), "aaa\nbbb\nccc\nddd\n");
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..4),
             (message_2.id, Role::User, 4..16),
         ]
     );
 
-    let (_, message_3) = context.update(cx, |context, cx| context.split_message(3..3, cx));
+    let (_, message_3) =
+        text_thread.update(cx, |text_thread, cx| text_thread.split_message(3..3, cx));
     let message_3 = message_3.unwrap();
 
     // We don't recycle newlines at the end of a split message
     assert_eq!(buffer.read(cx).text(), "aaa\n\nbbb\nccc\nddd\n");
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..4),
             (message_3.id, Role::User, 4..5),
@@ -235,11 +237,12 @@ fn test_message_splitting(cx: &mut App) {
         ]
     );
 
-    let (_, message_4) = context.update(cx, |context, cx| context.split_message(9..9, cx));
+    let (_, message_4) =
+        text_thread.update(cx, |text_thread, cx| text_thread.split_message(9..9, cx));
     let message_4 = message_4.unwrap();
     assert_eq!(buffer.read(cx).text(), "aaa\n\nbbb\nccc\nddd\n");
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..4),
             (message_3.id, Role::User, 4..5),
@@ -248,11 +251,12 @@ fn test_message_splitting(cx: &mut App) {
         ]
     );
 
-    let (_, message_5) = context.update(cx, |context, cx| context.split_message(9..9, cx));
+    let (_, message_5) =
+        text_thread.update(cx, |text_thread, cx| text_thread.split_message(9..9, cx));
     let message_5 = message_5.unwrap();
     assert_eq!(buffer.read(cx).text(), "aaa\n\nbbb\n\nccc\nddd\n");
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..4),
             (message_3.id, Role::User, 4..5),
@@ -263,12 +267,12 @@ fn test_message_splitting(cx: &mut App) {
     );
 
     let (message_6, message_7) =
-        context.update(cx, |context, cx| context.split_message(14..16, cx));
+        text_thread.update(cx, |text_thread, cx| text_thread.split_message(14..16, cx));
     let message_6 = message_6.unwrap();
     let message_7 = message_7.unwrap();
     assert_eq!(buffer.read(cx).text(), "aaa\n\nbbb\n\nccc\ndd\nd\n");
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..4),
             (message_3.id, Role::User, 4..5),
@@ -287,8 +291,8 @@ fn test_messages_for_offsets(cx: &mut App) {
 
     let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
-    let context = cx.new(|cx| {
-        AssistantContext::local(
+    let text_thread = cx.new(|cx| {
+        TextThread::local(
             registry,
             None,
             None,
@@ -297,32 +301,32 @@ fn test_messages_for_offsets(cx: &mut App) {
             cx,
         )
     });
-    let buffer = context.read(cx).buffer.clone();
+    let buffer = text_thread.read(cx).buffer().clone();
 
-    let message_1 = context.read(cx).message_anchors[0].clone();
+    let message_1 = text_thread.read(cx).message_anchors[0].clone();
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![(message_1.id, Role::User, 0..0)]
     );
 
     buffer.update(cx, |buffer, cx| buffer.edit([(0..0, "aaa")], None, cx));
-    let message_2 = context
-        .update(cx, |context, cx| {
-            context.insert_message_after(message_1.id, Role::User, MessageStatus::Done, cx)
+    let message_2 = text_thread
+        .update(cx, |text_thread, cx| {
+            text_thread.insert_message_after(message_1.id, Role::User, MessageStatus::Done, cx)
         })
         .unwrap();
     buffer.update(cx, |buffer, cx| buffer.edit([(4..4, "bbb")], None, cx));
 
-    let message_3 = context
-        .update(cx, |context, cx| {
-            context.insert_message_after(message_2.id, Role::User, MessageStatus::Done, cx)
+    let message_3 = text_thread
+        .update(cx, |text_thread, cx| {
+            text_thread.insert_message_after(message_2.id, Role::User, MessageStatus::Done, cx)
         })
         .unwrap();
     buffer.update(cx, |buffer, cx| buffer.edit([(8..8, "ccc")], None, cx));
 
     assert_eq!(buffer.read(cx).text(), "aaa\nbbb\nccc");
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..4),
             (message_2.id, Role::User, 4..8),
@@ -331,22 +335,22 @@ fn test_messages_for_offsets(cx: &mut App) {
     );
 
     assert_eq!(
-        message_ids_for_offsets(&context, &[0, 4, 9], cx),
+        message_ids_for_offsets(&text_thread, &[0, 4, 9], cx),
         [message_1.id, message_2.id, message_3.id]
     );
     assert_eq!(
-        message_ids_for_offsets(&context, &[0, 1, 11], cx),
+        message_ids_for_offsets(&text_thread, &[0, 1, 11], cx),
         [message_1.id, message_3.id]
     );
 
-    let message_4 = context
-        .update(cx, |context, cx| {
-            context.insert_message_after(message_3.id, Role::User, MessageStatus::Done, cx)
+    let message_4 = text_thread
+        .update(cx, |text_thread, cx| {
+            text_thread.insert_message_after(message_3.id, Role::User, MessageStatus::Done, cx)
         })
         .unwrap();
     assert_eq!(buffer.read(cx).text(), "aaa\nbbb\nccc\n");
     assert_eq!(
-        messages(&context, cx),
+        messages(&text_thread, cx),
         vec![
             (message_1.id, Role::User, 0..4),
             (message_2.id, Role::User, 4..8),
@@ -355,12 +359,12 @@ fn test_messages_for_offsets(cx: &mut App) {
         ]
     );
     assert_eq!(
-        message_ids_for_offsets(&context, &[0, 4, 8, 12], cx),
+        message_ids_for_offsets(&text_thread, &[0, 4, 8, 12], cx),
         [message_1.id, message_2.id, message_3.id, message_4.id]
     );
 
     fn message_ids_for_offsets(
-        context: &Entity<AssistantContext>,
+        context: &Entity<TextThread>,
         offsets: &[usize],
         cx: &App,
     ) -> Vec<MessageId> {
@@ -398,8 +402,8 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
 
     let registry = Arc::new(LanguageRegistry::test(cx.executor()));
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
-    let context = cx.new(|cx| {
-        AssistantContext::local(
+    let text_thread = cx.new(|cx| {
+        TextThread::local(
             registry.clone(),
             None,
             None,
@@ -417,19 +421,19 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
     }
 
     let context_ranges = Rc::new(RefCell::new(ContextRanges::default()));
-    context.update(cx, |_, cx| {
-        cx.subscribe(&context, {
+    text_thread.update(cx, |_, cx| {
+        cx.subscribe(&text_thread, {
             let context_ranges = context_ranges.clone();
-            move |context, _, event, _| {
+            move |text_thread, _, event, _| {
                 let mut context_ranges = context_ranges.borrow_mut();
                 match event {
-                    ContextEvent::InvokedSlashCommandChanged { command_id } => {
-                        let command = context.invoked_slash_command(command_id).unwrap();
+                    TextThreadEvent::InvokedSlashCommandChanged { command_id } => {
+                        let command = text_thread.invoked_slash_command(command_id).unwrap();
                         context_ranges
                             .command_outputs
                             .insert(*command_id, command.range.clone());
                     }
-                    ContextEvent::ParsedSlashCommandsUpdated { removed, updated } => {
+                    TextThreadEvent::ParsedSlashCommandsUpdated { removed, updated } => {
                         for range in removed {
                             context_ranges.parsed_commands.remove(range);
                         }
@@ -439,7 +443,7 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
                                 .insert(command.source_range.clone());
                         }
                     }
-                    ContextEvent::SlashCommandOutputSectionAdded { section } => {
+                    TextThreadEvent::SlashCommandOutputSectionAdded { section } => {
                         context_ranges.output_sections.insert(section.range.clone());
                     }
                     _ => {}
@@ -449,7 +453,7 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
         .detach();
     });
 
-    let buffer = context.read_with(cx, |context, _| context.buffer.clone());
+    let buffer = text_thread.read_with(cx, |text_thread, _| text_thread.buffer().clone());
 
     // Insert a slash command
     buffer.update(cx, |buffer, cx| {
@@ -508,9 +512,9 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
     );
 
     let (command_output_tx, command_output_rx) = mpsc::unbounded();
-    context.update(cx, |context, cx| {
-        let command_source_range = context.parsed_slash_commands[0].source_range.clone();
-        context.insert_command_output(
+    text_thread.update(cx, |text_thread, cx| {
+        let command_source_range = text_thread.parsed_slash_commands[0].source_range.clone();
+        text_thread.insert_command_output(
             command_source_range,
             "file",
             Task::ready(Ok(command_output_rx.boxed())),
@@ -670,8 +674,8 @@ async fn test_serialization(cx: &mut TestAppContext) {
 
     let registry = Arc::new(LanguageRegistry::test(cx.executor()));
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
-    let context = cx.new(|cx| {
-        AssistantContext::local(
+    let text_thread = cx.new(|cx| {
+        TextThread::local(
             registry.clone(),
             None,
             None,
@@ -680,15 +684,15 @@ async fn test_serialization(cx: &mut TestAppContext) {
             cx,
         )
     });
-    let buffer = context.read_with(cx, |context, _| context.buffer.clone());
-    let message_0 = context.read_with(cx, |context, _| context.message_anchors[0].id);
-    let message_1 = context.update(cx, |context, cx| {
-        context
+    let buffer = text_thread.read_with(cx, |text_thread, _| text_thread.buffer().clone());
+    let message_0 = text_thread.read_with(cx, |text_thread, _| text_thread.message_anchors[0].id);
+    let message_1 = text_thread.update(cx, |text_thread, cx| {
+        text_thread
             .insert_message_after(message_0, Role::Assistant, MessageStatus::Done, cx)
             .unwrap()
     });
-    let message_2 = context.update(cx, |context, cx| {
-        context
+    let message_2 = text_thread.update(cx, |text_thread, cx| {
+        text_thread
             .insert_message_after(message_1.id, Role::System, MessageStatus::Done, cx)
             .unwrap()
     });
@@ -696,15 +700,15 @@ async fn test_serialization(cx: &mut TestAppContext) {
         buffer.edit([(0..0, "a"), (1..1, "b\nc")], None, cx);
         buffer.finalize_last_transaction();
     });
-    let _message_3 = context.update(cx, |context, cx| {
-        context
+    let _message_3 = text_thread.update(cx, |text_thread, cx| {
+        text_thread
             .insert_message_after(message_2.id, Role::System, MessageStatus::Done, cx)
             .unwrap()
     });
     buffer.update(cx, |buffer, cx| buffer.undo(cx));
     assert_eq!(buffer.read_with(cx, |buffer, _| buffer.text()), "a\nb\nc\n");
     assert_eq!(
-        cx.read(|cx| messages(&context, cx)),
+        cx.read(|cx| messages(&text_thread, cx)),
         [
             (message_0, Role::User, 0..2),
             (message_1.id, Role::Assistant, 2..6),
@@ -712,9 +716,9 @@ async fn test_serialization(cx: &mut TestAppContext) {
         ]
     );
 
-    let serialized_context = context.read_with(cx, |context, cx| context.serialize(cx));
+    let serialized_context = text_thread.read_with(cx, |text_thread, cx| text_thread.serialize(cx));
     let deserialized_context = cx.new(|cx| {
-        AssistantContext::deserialize(
+        TextThread::deserialize(
             serialized_context,
             Path::new("").into(),
             registry.clone(),
@@ -726,7 +730,7 @@ async fn test_serialization(cx: &mut TestAppContext) {
         )
     });
     let deserialized_buffer =
-        deserialized_context.read_with(cx, |context, _| context.buffer.clone());
+        deserialized_context.read_with(cx, |text_thread, _| text_thread.buffer().clone());
     assert_eq!(
         deserialized_buffer.read_with(cx, |buffer, _| buffer.text()),
         "a\nb\nc\n"
@@ -762,14 +766,14 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
 
     let registry = Arc::new(LanguageRegistry::test(cx.background_executor.clone()));
     let network = Arc::new(Mutex::new(Network::new(rng.clone())));
-    let mut contexts = Vec::new();
+    let mut text_threads = Vec::new();
 
     let num_peers = rng.random_range(min_peers..=max_peers);
-    let context_id = ContextId::new();
+    let context_id = TextThreadId::new();
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
     for i in 0..num_peers {
         let context = cx.new(|cx| {
-            AssistantContext::new(
+            TextThread::new(
                 context_id.clone(),
                 ReplicaId::new(i as u16),
                 language::Capability::ReadWrite,
@@ -786,7 +790,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
             cx.subscribe(&context, {
                 let network = network.clone();
                 move |_, event, _| {
-                    if let ContextEvent::Operation(op) = event {
+                    if let TextThreadEvent::Operation(op) = event {
                         network
                             .lock()
                             .broadcast(ReplicaId::new(i as u16), vec![op.to_proto()]);
@@ -796,7 +800,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
             .detach();
         });
 
-        contexts.push(context);
+        text_threads.push(context);
         network.lock().add_peer(ReplicaId::new(i as u16));
     }
 
@@ -806,30 +810,30 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
         || !network.lock().is_idle()
         || network.lock().contains_disconnected_peers()
     {
-        let context_index = rng.random_range(0..contexts.len());
-        let context = &contexts[context_index];
+        let context_index = rng.random_range(0..text_threads.len());
+        let text_thread = &text_threads[context_index];
 
         match rng.random_range(0..100) {
             0..=29 if mutation_count > 0 => {
                 log::info!("Context {}: edit buffer", context_index);
-                context.update(cx, |context, cx| {
-                    context
-                        .buffer
+                text_thread.update(cx, |text_thread, cx| {
+                    text_thread
+                        .buffer()
                         .update(cx, |buffer, cx| buffer.randomly_edit(&mut rng, 1, cx));
                 });
                 mutation_count -= 1;
             }
             30..=44 if mutation_count > 0 => {
-                context.update(cx, |context, cx| {
-                    let range = context.buffer.read(cx).random_byte_range(0, &mut rng);
+                text_thread.update(cx, |text_thread, cx| {
+                    let range = text_thread.buffer().read(cx).random_byte_range(0, &mut rng);
                     log::info!("Context {}: split message at {:?}", context_index, range);
-                    context.split_message(range, cx);
+                    text_thread.split_message(range, cx);
                 });
                 mutation_count -= 1;
             }
             45..=59 if mutation_count > 0 => {
-                context.update(cx, |context, cx| {
-                    if let Some(message) = context.messages(cx).choose(&mut rng) {
+                text_thread.update(cx, |text_thread, cx| {
+                    if let Some(message) = text_thread.messages(cx).choose(&mut rng) {
                         let role = *[Role::User, Role::Assistant, Role::System]
                             .choose(&mut rng)
                             .unwrap();
@@ -839,13 +843,13 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                             message.id,
                             role
                         );
-                        context.insert_message_after(message.id, role, MessageStatus::Done, cx);
+                        text_thread.insert_message_after(message.id, role, MessageStatus::Done, cx);
                     }
                 });
                 mutation_count -= 1;
             }
             60..=74 if mutation_count > 0 => {
-                context.update(cx, |context, cx| {
+                text_thread.update(cx, |text_thread, cx| {
                     let command_text = "/".to_string()
                         + slash_commands
                             .command_names()
@@ -854,7 +858,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                             .clone()
                             .as_ref();
 
-                    let command_range = context.buffer.update(cx, |buffer, cx| {
+                    let command_range = text_thread.buffer().update(cx, |buffer, cx| {
                         let offset = buffer.random_byte_range(0, &mut rng).start;
                         buffer.edit(
                             [(offset..offset, format!("\n{}\n", command_text))],
@@ -908,9 +912,15 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                         events.len()
                     );
 
-                    let command_range = context.buffer.read(cx).anchor_after(command_range.start)
-                        ..context.buffer.read(cx).anchor_after(command_range.end);
-                    context.insert_command_output(
+                    let command_range = text_thread
+                        .buffer()
+                        .read(cx)
+                        .anchor_after(command_range.start)
+                        ..text_thread
+                            .buffer()
+                            .read(cx)
+                            .anchor_after(command_range.end);
+                    text_thread.insert_command_output(
                         command_range,
                         "/command",
                         Task::ready(Ok(stream::iter(events).boxed())),
@@ -922,8 +932,8 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                 mutation_count -= 1;
             }
             75..=84 if mutation_count > 0 => {
-                context.update(cx, |context, cx| {
-                    if let Some(message) = context.messages(cx).choose(&mut rng) {
+                text_thread.update(cx, |text_thread, cx| {
+                    if let Some(message) = text_thread.messages(cx).choose(&mut rng) {
                         let new_status = match rng.random_range(0..3) {
                             0 => MessageStatus::Done,
                             1 => MessageStatus::Pending,
@@ -935,7 +945,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                             message.id,
                             new_status
                         );
-                        context.update_metadata(message.id, cx, |metadata| {
+                        text_thread.update_metadata(message.id, cx, |metadata| {
                             metadata.status = new_status;
                         });
                     }
@@ -948,8 +958,8 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                     network.lock().reconnect_peer(replica_id, ReplicaId::new(0));
 
                     let (ops_to_send, ops_to_receive) = cx.read(|cx| {
-                        let host_context = &contexts[0].read(cx);
-                        let guest_context = context.read(cx);
+                        let host_context = &text_threads[0].read(cx);
+                        let guest_context = text_thread.read(cx);
                         (
                             guest_context.serialize_ops(&host_context.version(cx), cx),
                             host_context.serialize_ops(&guest_context.version(cx), cx),
@@ -959,7 +969,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                     let ops_to_receive = ops_to_receive
                         .await
                         .into_iter()
-                        .map(ContextOperation::from_proto)
+                        .map(TextThreadOperation::from_proto)
                         .collect::<Result<Vec<_>>>()
                         .unwrap();
                     log::info!(
@@ -970,7 +980,9 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                     );
 
                     network.lock().broadcast(replica_id, ops_to_send);
-                    context.update(cx, |context, cx| context.apply_ops(ops_to_receive, cx));
+                    text_thread.update(cx, |text_thread, cx| {
+                        text_thread.apply_ops(ops_to_receive, cx)
+                    });
                 } else if rng.random_bool(0.1) && replica_id != ReplicaId::new(0) {
                     log::info!("Context {}: disconnecting", context_index);
                     network.lock().disconnect_peer(replica_id);
@@ -979,43 +991,43 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
                     let ops = network.lock().receive(replica_id);
                     let ops = ops
                         .into_iter()
-                        .map(ContextOperation::from_proto)
+                        .map(TextThreadOperation::from_proto)
                         .collect::<Result<Vec<_>>>()
                         .unwrap();
-                    context.update(cx, |context, cx| context.apply_ops(ops, cx));
+                    text_thread.update(cx, |text_thread, cx| text_thread.apply_ops(ops, cx));
                 }
             }
         }
     }
 
     cx.read(|cx| {
-        let first_context = contexts[0].read(cx);
-        for context in &contexts[1..] {
-            let context = context.read(cx);
-            assert!(context.pending_ops.is_empty(), "pending ops: {:?}", context.pending_ops);
+        let first_context = text_threads[0].read(cx);
+        for text_thread in &text_threads[1..] {
+            let text_thread = text_thread.read(cx);
+            assert!(text_thread.pending_ops.is_empty(), "pending ops: {:?}", text_thread.pending_ops);
             assert_eq!(
-                context.buffer.read(cx).text(),
-                first_context.buffer.read(cx).text(),
+                text_thread.buffer().read(cx).text(),
+                first_context.buffer().read(cx).text(),
                 "Context {:?} text != Context 0 text",
-                context.buffer.read(cx).replica_id()
+                text_thread.buffer().read(cx).replica_id()
             );
             assert_eq!(
-                context.message_anchors,
+                text_thread.message_anchors,
                 first_context.message_anchors,
                 "Context {:?} messages != Context 0 messages",
-                context.buffer.read(cx).replica_id()
+                text_thread.buffer().read(cx).replica_id()
             );
             assert_eq!(
-                context.messages_metadata,
+                text_thread.messages_metadata,
                 first_context.messages_metadata,
                 "Context {:?} message metadata != Context 0 message metadata",
-                context.buffer.read(cx).replica_id()
+                text_thread.buffer().read(cx).replica_id()
             );
             assert_eq!(
-                context.slash_command_output_sections,
+                text_thread.slash_command_output_sections,
                 first_context.slash_command_output_sections,
                 "Context {:?} slash command output sections != Context 0 slash command output sections",
-                context.buffer.read(cx).replica_id()
+                text_thread.buffer().read(cx).replica_id()
             );
         }
     });
@@ -1027,8 +1039,8 @@ fn test_mark_cache_anchors(cx: &mut App) {
 
     let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
-    let context = cx.new(|cx| {
-        AssistantContext::local(
+    let text_thread = cx.new(|cx| {
+        TextThread::local(
             registry,
             None,
             None,
@@ -1037,7 +1049,7 @@ fn test_mark_cache_anchors(cx: &mut App) {
             cx,
         )
     });
-    let buffer = context.read(cx).buffer.clone();
+    let buffer = text_thread.read(cx).buffer().clone();
 
     // Create a test cache configuration
     let cache_configuration = &Some(LanguageModelCacheConfiguration {
@@ -1046,14 +1058,14 @@ fn test_mark_cache_anchors(cx: &mut App) {
         min_total_token: 10,
     });
 
-    let message_1 = context.read(cx).message_anchors[0].clone();
+    let message_1 = text_thread.read(cx).message_anchors[0].clone();
 
-    context.update(cx, |context, cx| {
-        context.mark_cache_anchors(cache_configuration, false, cx)
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.mark_cache_anchors(cache_configuration, false, cx)
     });
 
     assert_eq!(
-        messages_cache(&context, cx)
+        messages_cache(&text_thread, cx)
             .iter()
             .filter(|(_, cache)| cache.as_ref().is_some_and(|cache| cache.is_anchor))
             .count(),
@@ -1062,41 +1074,41 @@ fn test_mark_cache_anchors(cx: &mut App) {
     );
 
     buffer.update(cx, |buffer, cx| buffer.edit([(0..0, "aaa")], None, cx));
-    let message_2 = context
-        .update(cx, |context, cx| {
-            context.insert_message_after(message_1.id, Role::User, MessageStatus::Pending, cx)
+    let message_2 = text_thread
+        .update(cx, |text_thread, cx| {
+            text_thread.insert_message_after(message_1.id, Role::User, MessageStatus::Pending, cx)
         })
         .unwrap();
 
     buffer.update(cx, |buffer, cx| buffer.edit([(4..4, "bbbbbbb")], None, cx));
-    let message_3 = context
-        .update(cx, |context, cx| {
-            context.insert_message_after(message_2.id, Role::User, MessageStatus::Pending, cx)
+    let message_3 = text_thread
+        .update(cx, |text_thread, cx| {
+            text_thread.insert_message_after(message_2.id, Role::User, MessageStatus::Pending, cx)
         })
         .unwrap();
     buffer.update(cx, |buffer, cx| buffer.edit([(12..12, "cccccc")], None, cx));
 
-    context.update(cx, |context, cx| {
-        context.mark_cache_anchors(cache_configuration, false, cx)
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.mark_cache_anchors(cache_configuration, false, cx)
     });
     assert_eq!(buffer.read(cx).text(), "aaa\nbbbbbbb\ncccccc");
     assert_eq!(
-        messages_cache(&context, cx)
+        messages_cache(&text_thread, cx)
             .iter()
             .filter(|(_, cache)| cache.as_ref().is_some_and(|cache| cache.is_anchor))
             .count(),
         0,
         "Messages should not be marked for cache before going over the token minimum."
     );
-    context.update(cx, |context, _| {
-        context.token_count = Some(20);
+    text_thread.update(cx, |text_thread, _| {
+        text_thread.token_count = Some(20);
     });
 
-    context.update(cx, |context, cx| {
-        context.mark_cache_anchors(cache_configuration, true, cx)
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.mark_cache_anchors(cache_configuration, true, cx)
     });
     assert_eq!(
-        messages_cache(&context, cx)
+        messages_cache(&text_thread, cx)
             .iter()
             .map(|(_, cache)| cache.as_ref().is_some_and(|cache| cache.is_anchor))
             .collect::<Vec<bool>>(),
@@ -1104,28 +1116,33 @@ fn test_mark_cache_anchors(cx: &mut App) {
         "Last message should not be an anchor on speculative request."
     );
 
-    context
-        .update(cx, |context, cx| {
-            context.insert_message_after(message_3.id, Role::Assistant, MessageStatus::Pending, cx)
+    text_thread
+        .update(cx, |text_thread, cx| {
+            text_thread.insert_message_after(
+                message_3.id,
+                Role::Assistant,
+                MessageStatus::Pending,
+                cx,
+            )
         })
         .unwrap();
 
-    context.update(cx, |context, cx| {
-        context.mark_cache_anchors(cache_configuration, false, cx)
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.mark_cache_anchors(cache_configuration, false, cx)
     });
     assert_eq!(
-        messages_cache(&context, cx)
+        messages_cache(&text_thread, cx)
             .iter()
             .map(|(_, cache)| cache.as_ref().is_some_and(|cache| cache.is_anchor))
             .collect::<Vec<bool>>(),
         vec![false, true, true, false],
         "Most recent message should also be cached if not a speculative request."
     );
-    context.update(cx, |context, cx| {
-        context.update_cache_status_for_completion(cx)
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.update_cache_status_for_completion(cx)
     });
     assert_eq!(
-        messages_cache(&context, cx)
+        messages_cache(&text_thread, cx)
             .iter()
             .map(|(_, cache)| cache
                 .as_ref()
@@ -1141,11 +1158,11 @@ fn test_mark_cache_anchors(cx: &mut App) {
     );
 
     buffer.update(cx, |buffer, cx| buffer.edit([(14..14, "d")], None, cx));
-    context.update(cx, |context, cx| {
-        context.mark_cache_anchors(cache_configuration, false, cx)
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.mark_cache_anchors(cache_configuration, false, cx)
     });
     assert_eq!(
-        messages_cache(&context, cx)
+        messages_cache(&text_thread, cx)
             .iter()
             .map(|(_, cache)| cache
                 .as_ref()
@@ -1160,11 +1177,11 @@ fn test_mark_cache_anchors(cx: &mut App) {
         "Modifying a message should invalidate it's cache but leave previous messages."
     );
     buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "e")], None, cx));
-    context.update(cx, |context, cx| {
-        context.mark_cache_anchors(cache_configuration, false, cx)
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.mark_cache_anchors(cache_configuration, false, cx)
     });
     assert_eq!(
-        messages_cache(&context, cx)
+        messages_cache(&text_thread, cx)
             .iter()
             .map(|(_, cache)| cache
                 .as_ref()
@@ -1182,31 +1199,36 @@ fn test_mark_cache_anchors(cx: &mut App) {
 
 #[gpui::test]
 async fn test_summarization(cx: &mut TestAppContext) {
-    let (context, fake_model) = setup_context_editor_with_fake_model(cx);
+    let (text_thread, fake_model) = setup_context_editor_with_fake_model(cx);
 
     // Initial state should be pending
-    context.read_with(cx, |context, _| {
-        assert!(matches!(context.summary(), ContextSummary::Pending));
-        assert_eq!(context.summary().or_default(), ContextSummary::DEFAULT);
+    text_thread.read_with(cx, |text_thread, _| {
+        assert!(matches!(text_thread.summary(), TextThreadSummary::Pending));
+        assert_eq!(
+            text_thread.summary().or_default(),
+            TextThreadSummary::DEFAULT
+        );
     });
 
-    let message_1 = context.read_with(cx, |context, _cx| context.message_anchors[0].clone());
-    context.update(cx, |context, cx| {
+    let message_1 = text_thread.read_with(cx, |text_thread, _cx| {
+        text_thread.message_anchors[0].clone()
+    });
+    text_thread.update(cx, |context, cx| {
         context
             .insert_message_after(message_1.id, Role::Assistant, MessageStatus::Done, cx)
             .unwrap();
     });
 
     // Send a message
-    context.update(cx, |context, cx| {
-        context.assist(cx);
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.assist(cx);
     });
 
     simulate_successful_response(&fake_model, cx);
 
     // Should start generating summary when there are >= 2 messages
-    context.read_with(cx, |context, _| {
-        assert!(!context.summary().content().unwrap().done);
+    text_thread.read_with(cx, |text_thread, _| {
+        assert!(!text_thread.summary().content().unwrap().done);
     });
 
     cx.run_until_parked();
@@ -1216,61 +1238,61 @@ async fn test_summarization(cx: &mut TestAppContext) {
     cx.run_until_parked();
 
     // Summary should be set
-    context.read_with(cx, |context, _| {
-        assert_eq!(context.summary().or_default(), "Brief Introduction");
+    text_thread.read_with(cx, |text_thread, _| {
+        assert_eq!(text_thread.summary().or_default(), "Brief Introduction");
     });
 
     // We should be able to manually set a summary
-    context.update(cx, |context, cx| {
-        context.set_custom_summary("Brief Intro".into(), cx);
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.set_custom_summary("Brief Intro".into(), cx);
     });
 
-    context.read_with(cx, |context, _| {
-        assert_eq!(context.summary().or_default(), "Brief Intro");
+    text_thread.read_with(cx, |text_thread, _| {
+        assert_eq!(text_thread.summary().or_default(), "Brief Intro");
     });
 }
 
 #[gpui::test]
 async fn test_thread_summary_error_set_manually(cx: &mut TestAppContext) {
-    let (context, fake_model) = setup_context_editor_with_fake_model(cx);
+    let (text_thread, fake_model) = setup_context_editor_with_fake_model(cx);
 
-    test_summarize_error(&fake_model, &context, cx);
+    test_summarize_error(&fake_model, &text_thread, cx);
 
     // Now we should be able to set a summary
-    context.update(cx, |context, cx| {
-        context.set_custom_summary("Brief Intro".into(), cx);
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.set_custom_summary("Brief Intro".into(), cx);
     });
 
-    context.read_with(cx, |context, _| {
-        assert_eq!(context.summary().or_default(), "Brief Intro");
+    text_thread.read_with(cx, |text_thread, _| {
+        assert_eq!(text_thread.summary().or_default(), "Brief Intro");
     });
 }
 
 #[gpui::test]
 async fn test_thread_summary_error_retry(cx: &mut TestAppContext) {
-    let (context, fake_model) = setup_context_editor_with_fake_model(cx);
+    let (text_thread, fake_model) = setup_context_editor_with_fake_model(cx);
 
-    test_summarize_error(&fake_model, &context, cx);
+    test_summarize_error(&fake_model, &text_thread, cx);
 
     // Sending another message should not trigger another summarize request
-    context.update(cx, |context, cx| {
-        context.assist(cx);
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.assist(cx);
     });
 
     simulate_successful_response(&fake_model, cx);
 
-    context.read_with(cx, |context, _| {
+    text_thread.read_with(cx, |text_thread, _| {
         // State is still Error, not Generating
-        assert!(matches!(context.summary(), ContextSummary::Error));
+        assert!(matches!(text_thread.summary(), TextThreadSummary::Error));
     });
 
     // But the summarize request can be invoked manually
-    context.update(cx, |context, cx| {
-        context.summarize(true, cx);
+    text_thread.update(cx, |text_thread, cx| {
+        text_thread.summarize(true, cx);
     });
 
-    context.read_with(cx, |context, _| {
-        assert!(!context.summary().content().unwrap().done);
+    text_thread.read_with(cx, |text_thread, _| {
+        assert!(!text_thread.summary().content().unwrap().done);
     });
 
     cx.run_until_parked();

crates/assistant_context/src/assistant_context.rs β†’ crates/assistant_text_thread/src/text_thread.rs πŸ”—

@@ -1,7 +1,3 @@
-#[cfg(test)]
-mod assistant_context_tests;
-mod context_store;
-
 use agent_settings::{AgentSettings, SUMMARIZE_THREAD_PROMPT};
 use anyhow::{Context as _, Result, bail};
 use assistant_slash_command::{
@@ -9,7 +5,7 @@ use assistant_slash_command::{
     SlashCommandResult, SlashCommandWorkingSet,
 };
 use assistant_slash_commands::FileCommandMetadata;
-use client::{self, Client, ModelRequestUsage, RequestUsage, proto, telemetry::Telemetry};
+use client::{self, ModelRequestUsage, RequestUsage, proto, telemetry::Telemetry};
 use clock::ReplicaId;
 use cloud_llm_client::{CompletionIntent, CompletionRequestStatus, UsageLimit};
 use collections::{HashMap, HashSet};
@@ -27,7 +23,7 @@ use language_model::{
     report_assistant_event,
 };
 use open_ai::Model as OpenAiModel;
-use paths::contexts_dir;
+use paths::text_threads_dir;
 use project::Project;
 use prompt_store::PromptBuilder;
 use serde::{Deserialize, Serialize};
@@ -48,16 +44,10 @@ use ui::IconName;
 use util::{ResultExt, TryFutureExt, post_inc};
 use uuid::Uuid;
 
-pub use crate::context_store::*;
-
-pub fn init(client: Arc<Client>, _: &mut App) {
-    context_store::init(&client.into());
-}
-
 #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
-pub struct ContextId(String);
+pub struct TextThreadId(String);
 
-impl ContextId {
+impl TextThreadId {
     pub fn new() -> Self {
         Self(Uuid::new_v4().to_string())
     }
@@ -130,7 +120,7 @@ impl MessageStatus {
 }
 
 #[derive(Clone, Debug)]
-pub enum ContextOperation {
+pub enum TextThreadOperation {
     InsertMessage {
         anchor: MessageAnchor,
         metadata: MessageMetadata,
@@ -142,7 +132,7 @@ pub enum ContextOperation {
         version: clock::Global,
     },
     UpdateSummary {
-        summary: ContextSummaryContent,
+        summary: TextThreadSummaryContent,
         version: clock::Global,
     },
     SlashCommandStarted {
@@ -170,7 +160,7 @@ pub enum ContextOperation {
     BufferOperation(language::Operation),
 }
 
-impl ContextOperation {
+impl TextThreadOperation {
     pub fn from_proto(op: proto::ContextOperation) -> Result<Self> {
         match op.variant.context("invalid variant")? {
             proto::context_operation::Variant::InsertMessage(insert) => {
@@ -212,7 +202,7 @@ impl ContextOperation {
                 version: language::proto::deserialize_version(&update.version),
             }),
             proto::context_operation::Variant::UpdateSummary(update) => Ok(Self::UpdateSummary {
-                summary: ContextSummaryContent {
+                summary: TextThreadSummaryContent {
                     text: update.summary,
                     done: update.done,
                     timestamp: language::proto::deserialize_timestamp(
@@ -453,7 +443,7 @@ impl ContextOperation {
 }
 
 #[derive(Debug, Clone)]
-pub enum ContextEvent {
+pub enum TextThreadEvent {
     ShowAssistError(SharedString),
     ShowPaymentRequiredError,
     MessagesEdited,
@@ -476,24 +466,24 @@ pub enum ContextEvent {
     SlashCommandOutputSectionAdded {
         section: SlashCommandOutputSection<language::Anchor>,
     },
-    Operation(ContextOperation),
+    Operation(TextThreadOperation),
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
-pub enum ContextSummary {
+pub enum TextThreadSummary {
     Pending,
-    Content(ContextSummaryContent),
+    Content(TextThreadSummaryContent),
     Error,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
-pub struct ContextSummaryContent {
+pub struct TextThreadSummaryContent {
     pub text: String,
     pub done: bool,
     pub timestamp: clock::Lamport,
 }
 
-impl ContextSummary {
+impl TextThreadSummary {
     pub const DEFAULT: &str = "New Text Thread";
 
     pub fn or_default(&self) -> SharedString {
@@ -505,48 +495,48 @@ impl ContextSummary {
             .map_or_else(|| message.into(), |content| content.text.clone().into())
     }
 
-    pub fn content(&self) -> Option<&ContextSummaryContent> {
+    pub fn content(&self) -> Option<&TextThreadSummaryContent> {
         match self {
-            ContextSummary::Content(content) => Some(content),
-            ContextSummary::Pending | ContextSummary::Error => None,
+            TextThreadSummary::Content(content) => Some(content),
+            TextThreadSummary::Pending | TextThreadSummary::Error => None,
         }
     }
 
-    fn content_as_mut(&mut self) -> Option<&mut ContextSummaryContent> {
+    fn content_as_mut(&mut self) -> Option<&mut TextThreadSummaryContent> {
         match self {
-            ContextSummary::Content(content) => Some(content),
-            ContextSummary::Pending | ContextSummary::Error => None,
+            TextThreadSummary::Content(content) => Some(content),
+            TextThreadSummary::Pending | TextThreadSummary::Error => None,
         }
     }
 
-    fn content_or_set_empty(&mut self) -> &mut ContextSummaryContent {
+    fn content_or_set_empty(&mut self) -> &mut TextThreadSummaryContent {
         match self {
-            ContextSummary::Content(content) => content,
-            ContextSummary::Pending | ContextSummary::Error => {
-                let content = ContextSummaryContent {
+            TextThreadSummary::Content(content) => content,
+            TextThreadSummary::Pending | TextThreadSummary::Error => {
+                let content = TextThreadSummaryContent {
                     text: "".to_string(),
                     done: false,
                     timestamp: clock::Lamport::MIN,
                 };
-                *self = ContextSummary::Content(content);
+                *self = TextThreadSummary::Content(content);
                 self.content_as_mut().unwrap()
             }
         }
     }
 
     pub fn is_pending(&self) -> bool {
-        matches!(self, ContextSummary::Pending)
+        matches!(self, TextThreadSummary::Pending)
     }
 
     fn timestamp(&self) -> Option<clock::Lamport> {
         match self {
-            ContextSummary::Content(content) => Some(content.timestamp),
-            ContextSummary::Pending | ContextSummary::Error => None,
+            TextThreadSummary::Content(content) => Some(content.timestamp),
+            TextThreadSummary::Pending | TextThreadSummary::Error => None,
         }
     }
 }
 
-impl PartialOrd for ContextSummary {
+impl PartialOrd for TextThreadSummary {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         self.timestamp().partial_cmp(&other.timestamp())
     }
@@ -668,27 +658,27 @@ struct PendingCompletion {
 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
 pub struct InvokedSlashCommandId(clock::Lamport);
 
-pub struct AssistantContext {
-    id: ContextId,
+pub struct TextThread {
+    id: TextThreadId,
     timestamp: clock::Lamport,
     version: clock::Global,
-    pending_ops: Vec<ContextOperation>,
-    operations: Vec<ContextOperation>,
+    pub(crate) pending_ops: Vec<TextThreadOperation>,
+    operations: Vec<TextThreadOperation>,
     buffer: Entity<Buffer>,
-    parsed_slash_commands: Vec<ParsedSlashCommand>,
+    pub(crate) parsed_slash_commands: Vec<ParsedSlashCommand>,
     invoked_slash_commands: HashMap<InvokedSlashCommandId, InvokedSlashCommand>,
     edits_since_last_parse: language::Subscription,
     slash_commands: Arc<SlashCommandWorkingSet>,
-    slash_command_output_sections: Vec<SlashCommandOutputSection<language::Anchor>>,
+    pub(crate) slash_command_output_sections: Vec<SlashCommandOutputSection<language::Anchor>>,
     thought_process_output_sections: Vec<ThoughtProcessOutputSection<language::Anchor>>,
-    message_anchors: Vec<MessageAnchor>,
+    pub(crate) message_anchors: Vec<MessageAnchor>,
     contents: Vec<Content>,
-    messages_metadata: HashMap<MessageId, MessageMetadata>,
-    summary: ContextSummary,
+    pub(crate) messages_metadata: HashMap<MessageId, MessageMetadata>,
+    summary: TextThreadSummary,
     summary_task: Task<Option<()>>,
     completion_count: usize,
     pending_completions: Vec<PendingCompletion>,
-    token_count: Option<u64>,
+    pub(crate) token_count: Option<u64>,
     pending_token_count: Task<Option<()>>,
     pending_save: Task<Result<()>>,
     pending_cache_warming_task: Task<Option<()>>,
@@ -711,9 +701,9 @@ impl ContextAnnotation for ParsedSlashCommand {
     }
 }
 
-impl EventEmitter<ContextEvent> for AssistantContext {}
+impl EventEmitter<TextThreadEvent> for TextThread {}
 
-impl AssistantContext {
+impl TextThread {
     pub fn local(
         language_registry: Arc<LanguageRegistry>,
         project: Option<Entity<Project>>,
@@ -723,7 +713,7 @@ impl AssistantContext {
         cx: &mut Context<Self>,
     ) -> Self {
         Self::new(
-            ContextId::new(),
+            TextThreadId::new(),
             ReplicaId::default(),
             language::Capability::ReadWrite,
             language_registry,
@@ -744,7 +734,7 @@ impl AssistantContext {
     }
 
     pub fn new(
-        id: ContextId,
+        id: TextThreadId,
         replica_id: ReplicaId,
         capability: language::Capability,
         language_registry: Arc<LanguageRegistry>,
@@ -780,7 +770,7 @@ impl AssistantContext {
             slash_command_output_sections: Vec::new(),
             thought_process_output_sections: Vec::new(),
             edits_since_last_parse: edits_since_last_slash_command_parse,
-            summary: ContextSummary::Pending,
+            summary: TextThreadSummary::Pending,
             summary_task: Task::ready(None),
             completion_count: Default::default(),
             pending_completions: Default::default(),
@@ -823,12 +813,12 @@ impl AssistantContext {
         this
     }
 
-    pub(crate) fn serialize(&self, cx: &App) -> SavedContext {
+    pub(crate) fn serialize(&self, cx: &App) -> SavedTextThread {
         let buffer = self.buffer.read(cx);
-        SavedContext {
+        SavedTextThread {
             id: Some(self.id.clone()),
             zed: "context".into(),
-            version: SavedContext::VERSION.into(),
+            version: SavedTextThread::VERSION.into(),
             text: buffer.text(),
             messages: self
                 .messages(cx)
@@ -876,7 +866,7 @@ impl AssistantContext {
     }
 
     pub fn deserialize(
-        saved_context: SavedContext,
+        saved_context: SavedTextThread,
         path: Arc<Path>,
         language_registry: Arc<LanguageRegistry>,
         prompt_builder: Arc<PromptBuilder>,
@@ -885,7 +875,7 @@ impl AssistantContext {
         telemetry: Option<Arc<Telemetry>>,
         cx: &mut Context<Self>,
     ) -> Self {
-        let id = saved_context.id.clone().unwrap_or_else(ContextId::new);
+        let id = saved_context.id.clone().unwrap_or_else(TextThreadId::new);
         let mut this = Self::new(
             id,
             ReplicaId::default(),
@@ -906,7 +896,7 @@ impl AssistantContext {
         this
     }
 
-    pub fn id(&self) -> &ContextId {
+    pub fn id(&self) -> &TextThreadId {
         &self.id
     }
 
@@ -914,9 +904,9 @@ impl AssistantContext {
         self.timestamp.replica_id
     }
 
-    pub fn version(&self, cx: &App) -> ContextVersion {
-        ContextVersion {
-            context: self.version.clone(),
+    pub fn version(&self, cx: &App) -> TextThreadVersion {
+        TextThreadVersion {
+            text_thread: self.version.clone(),
             buffer: self.buffer.read(cx).version(),
         }
     }
@@ -938,7 +928,7 @@ impl AssistantContext {
 
     pub fn serialize_ops(
         &self,
-        since: &ContextVersion,
+        since: &TextThreadVersion,
         cx: &App,
     ) -> Task<Vec<proto::ContextOperation>> {
         let buffer_ops = self
@@ -949,7 +939,7 @@ impl AssistantContext {
         let mut context_ops = self
             .operations
             .iter()
-            .filter(|op| !since.context.observed(op.timestamp()))
+            .filter(|op| !since.text_thread.observed(op.timestamp()))
             .cloned()
             .collect::<Vec<_>>();
         context_ops.extend(self.pending_ops.iter().cloned());
@@ -973,13 +963,13 @@ impl AssistantContext {
 
     pub fn apply_ops(
         &mut self,
-        ops: impl IntoIterator<Item = ContextOperation>,
+        ops: impl IntoIterator<Item = TextThreadOperation>,
         cx: &mut Context<Self>,
     ) {
         let mut buffer_ops = Vec::new();
         for op in ops {
             match op {
-                ContextOperation::BufferOperation(buffer_op) => buffer_ops.push(buffer_op),
+                TextThreadOperation::BufferOperation(buffer_op) => buffer_ops.push(buffer_op),
                 op @ _ => self.pending_ops.push(op),
             }
         }
@@ -988,7 +978,7 @@ impl AssistantContext {
         self.flush_ops(cx);
     }
 
-    fn flush_ops(&mut self, cx: &mut Context<AssistantContext>) {
+    fn flush_ops(&mut self, cx: &mut Context<TextThread>) {
         let mut changed_messages = HashSet::default();
         let mut summary_generated = false;
 
@@ -1001,7 +991,7 @@ impl AssistantContext {
 
             let timestamp = op.timestamp();
             match op.clone() {
-                ContextOperation::InsertMessage {
+                TextThreadOperation::InsertMessage {
                     anchor, metadata, ..
                 } => {
                     if self.messages_metadata.contains_key(&anchor.id) {
@@ -1011,7 +1001,7 @@ impl AssistantContext {
                         self.insert_message(anchor, metadata, cx);
                     }
                 }
-                ContextOperation::UpdateMessage {
+                TextThreadOperation::UpdateMessage {
                     message_id,
                     metadata: new_metadata,
                     ..
@@ -1022,7 +1012,7 @@ impl AssistantContext {
                         changed_messages.insert(message_id);
                     }
                 }
-                ContextOperation::UpdateSummary {
+                TextThreadOperation::UpdateSummary {
                     summary: new_summary,
                     ..
                 } => {
@@ -1031,11 +1021,11 @@ impl AssistantContext {
                         .timestamp()
                         .is_none_or(|current_timestamp| new_summary.timestamp > current_timestamp)
                     {
-                        self.summary = ContextSummary::Content(new_summary);
+                        self.summary = TextThreadSummary::Content(new_summary);
                         summary_generated = true;
                     }
                 }
-                ContextOperation::SlashCommandStarted {
+                TextThreadOperation::SlashCommandStarted {
                     id,
                     output_range,
                     name,
@@ -1052,9 +1042,9 @@ impl AssistantContext {
                             timestamp: id.0,
                         },
                     );
-                    cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id: id });
+                    cx.emit(TextThreadEvent::InvokedSlashCommandChanged { command_id: id });
                 }
-                ContextOperation::SlashCommandOutputSectionAdded { section, .. } => {
+                TextThreadOperation::SlashCommandOutputSectionAdded { section, .. } => {
                     let buffer = self.buffer.read(cx);
                     if let Err(ix) = self
                         .slash_command_output_sections
@@ -1062,10 +1052,10 @@ impl AssistantContext {
                     {
                         self.slash_command_output_sections
                             .insert(ix, section.clone());
-                        cx.emit(ContextEvent::SlashCommandOutputSectionAdded { section });
+                        cx.emit(TextThreadEvent::SlashCommandOutputSectionAdded { section });
                     }
                 }
-                ContextOperation::ThoughtProcessOutputSectionAdded { section, .. } => {
+                TextThreadOperation::ThoughtProcessOutputSectionAdded { section, .. } => {
                     let buffer = self.buffer.read(cx);
                     if let Err(ix) = self
                         .thought_process_output_sections
@@ -1075,7 +1065,7 @@ impl AssistantContext {
                             .insert(ix, section.clone());
                     }
                 }
-                ContextOperation::SlashCommandFinished {
+                TextThreadOperation::SlashCommandFinished {
                     id,
                     error_message,
                     timestamp,
@@ -1094,10 +1084,10 @@ impl AssistantContext {
                                 slash_command.status = InvokedSlashCommandStatus::Finished;
                             }
                         }
-                        cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id: id });
+                        cx.emit(TextThreadEvent::InvokedSlashCommandChanged { command_id: id });
                     }
                 }
-                ContextOperation::BufferOperation(_) => unreachable!(),
+                TextThreadOperation::BufferOperation(_) => unreachable!(),
             }
 
             self.version.observe(timestamp);
@@ -1107,43 +1097,43 @@ impl AssistantContext {
 
         if !changed_messages.is_empty() {
             self.message_roles_updated(changed_messages, cx);
-            cx.emit(ContextEvent::MessagesEdited);
+            cx.emit(TextThreadEvent::MessagesEdited);
             cx.notify();
         }
 
         if summary_generated {
-            cx.emit(ContextEvent::SummaryChanged);
-            cx.emit(ContextEvent::SummaryGenerated);
+            cx.emit(TextThreadEvent::SummaryChanged);
+            cx.emit(TextThreadEvent::SummaryGenerated);
             cx.notify();
         }
     }
 
-    fn can_apply_op(&self, op: &ContextOperation, cx: &App) -> bool {
+    fn can_apply_op(&self, op: &TextThreadOperation, cx: &App) -> bool {
         if !self.version.observed_all(op.version()) {
             return false;
         }
 
         match op {
-            ContextOperation::InsertMessage { anchor, .. } => self
+            TextThreadOperation::InsertMessage { anchor, .. } => self
                 .buffer
                 .read(cx)
                 .version
                 .observed(anchor.start.timestamp),
-            ContextOperation::UpdateMessage { message_id, .. } => {
+            TextThreadOperation::UpdateMessage { message_id, .. } => {
                 self.messages_metadata.contains_key(message_id)
             }
-            ContextOperation::UpdateSummary { .. } => true,
-            ContextOperation::SlashCommandStarted { output_range, .. } => {
+            TextThreadOperation::UpdateSummary { .. } => true,
+            TextThreadOperation::SlashCommandStarted { output_range, .. } => {
                 self.has_received_operations_for_anchor_range(output_range.clone(), cx)
             }
-            ContextOperation::SlashCommandOutputSectionAdded { section, .. } => {
+            TextThreadOperation::SlashCommandOutputSectionAdded { section, .. } => {
                 self.has_received_operations_for_anchor_range(section.range.clone(), cx)
             }
-            ContextOperation::ThoughtProcessOutputSectionAdded { section, .. } => {
+            TextThreadOperation::ThoughtProcessOutputSectionAdded { section, .. } => {
                 self.has_received_operations_for_anchor_range(section.range.clone(), cx)
             }
-            ContextOperation::SlashCommandFinished { .. } => true,
-            ContextOperation::BufferOperation(_) => {
+            TextThreadOperation::SlashCommandFinished { .. } => true,
+            TextThreadOperation::BufferOperation(_) => {
                 panic!("buffer operations should always be applied")
             }
         }
@@ -1164,9 +1154,9 @@ impl AssistantContext {
         observed_start && observed_end
     }
 
-    fn push_op(&mut self, op: ContextOperation, cx: &mut Context<Self>) {
+    fn push_op(&mut self, op: TextThreadOperation, cx: &mut Context<Self>) {
         self.operations.push(op.clone());
-        cx.emit(ContextEvent::Operation(op));
+        cx.emit(TextThreadEvent::Operation(op));
     }
 
     pub fn buffer(&self) -> &Entity<Buffer> {
@@ -1189,7 +1179,7 @@ impl AssistantContext {
         self.path.as_ref()
     }
 
-    pub fn summary(&self) -> &ContextSummary {
+    pub fn summary(&self) -> &TextThreadSummary {
         &self.summary
     }
 
@@ -1250,13 +1240,13 @@ impl AssistantContext {
             language::BufferEvent::Operation {
                 operation,
                 is_local: true,
-            } => cx.emit(ContextEvent::Operation(ContextOperation::BufferOperation(
-                operation.clone(),
-            ))),
+            } => cx.emit(TextThreadEvent::Operation(
+                TextThreadOperation::BufferOperation(operation.clone()),
+            )),
             language::BufferEvent::Edited => {
                 self.count_remaining_tokens(cx);
                 self.reparse(cx);
-                cx.emit(ContextEvent::MessagesEdited);
+                cx.emit(TextThreadEvent::MessagesEdited);
             }
             _ => {}
         }
@@ -1522,7 +1512,7 @@ impl AssistantContext {
         if !updated_parsed_slash_commands.is_empty()
             || !removed_parsed_slash_command_ranges.is_empty()
         {
-            cx.emit(ContextEvent::ParsedSlashCommandsUpdated {
+            cx.emit(TextThreadEvent::ParsedSlashCommandsUpdated {
                 removed: removed_parsed_slash_command_ranges,
                 updated: updated_parsed_slash_commands,
             });
@@ -1596,7 +1586,7 @@ impl AssistantContext {
                 && (!command.range.start.is_valid(buffer) || !command.range.end.is_valid(buffer))
             {
                 command.status = InvokedSlashCommandStatus::Finished;
-                cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id });
+                cx.emit(TextThreadEvent::InvokedSlashCommandChanged { command_id });
                 invalidated_command_ids.push(command_id);
             }
         }
@@ -1605,7 +1595,7 @@ impl AssistantContext {
             let version = self.version.clone();
             let timestamp = self.next_timestamp();
             self.push_op(
-                ContextOperation::SlashCommandFinished {
+                TextThreadOperation::SlashCommandFinished {
                     id: command_id,
                     timestamp,
                     error_message: None,
@@ -1910,9 +1900,9 @@ impl AssistantContext {
                     }
                 }
 
-                cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id });
+                cx.emit(TextThreadEvent::InvokedSlashCommandChanged { command_id });
                 this.push_op(
-                    ContextOperation::SlashCommandFinished {
+                    TextThreadOperation::SlashCommandFinished {
                         id: command_id,
                         timestamp,
                         error_message,
@@ -1935,9 +1925,9 @@ impl AssistantContext {
                 timestamp: command_id.0,
             },
         );
-        cx.emit(ContextEvent::InvokedSlashCommandChanged { command_id });
+        cx.emit(TextThreadEvent::InvokedSlashCommandChanged { command_id });
         self.push_op(
-            ContextOperation::SlashCommandStarted {
+            TextThreadOperation::SlashCommandStarted {
                 id: command_id,
                 output_range: command_range,
                 name: name.to_string(),
@@ -1961,13 +1951,13 @@ impl AssistantContext {
         };
         self.slash_command_output_sections
             .insert(insertion_ix, section.clone());
-        cx.emit(ContextEvent::SlashCommandOutputSectionAdded {
+        cx.emit(TextThreadEvent::SlashCommandOutputSectionAdded {
             section: section.clone(),
         });
         let version = self.version.clone();
         let timestamp = self.next_timestamp();
         self.push_op(
-            ContextOperation::SlashCommandOutputSectionAdded {
+            TextThreadOperation::SlashCommandOutputSectionAdded {
                 timestamp,
                 section,
                 version,
@@ -1996,7 +1986,7 @@ impl AssistantContext {
         let version = self.version.clone();
         let timestamp = self.next_timestamp();
         self.push_op(
-            ContextOperation::ThoughtProcessOutputSectionAdded {
+            TextThreadOperation::ThoughtProcessOutputSectionAdded {
                 timestamp,
                 section,
                 version,
@@ -2115,7 +2105,7 @@ impl AssistantContext {
                                             let end = buffer
                                                 .anchor_before(message_old_end_offset + chunk_len);
                                             context_event = Some(
-                                                ContextEvent::StartedThoughtProcess(start..end),
+                                                TextThreadEvent::StartedThoughtProcess(start..end),
                                             );
                                         } else {
                                             // This ensures that all the thinking chunks are inserted inside the thinking tag
@@ -2133,7 +2123,7 @@ impl AssistantContext {
                                         if let Some(start) = thought_process_stack.pop() {
                                             let end = buffer.anchor_before(message_old_end_offset);
                                             context_event =
-                                                Some(ContextEvent::EndedThoughtProcess(end));
+                                                Some(TextThreadEvent::EndedThoughtProcess(end));
                                             thought_process_output_section =
                                                 Some(ThoughtProcessOutputSection {
                                                     range: start..end,
@@ -2163,7 +2153,7 @@ impl AssistantContext {
                                 cx.emit(context_event);
                             }
 
-                            cx.emit(ContextEvent::StreamedCompletion);
+                            cx.emit(TextThreadEvent::StreamedCompletion);
 
                             Some(())
                         })?;
@@ -2184,7 +2174,7 @@ impl AssistantContext {
                 this.update(cx, |this, cx| {
                     let error_message = if let Some(error) = result.as_ref().err() {
                         if error.is::<PaymentRequiredError>() {
-                            cx.emit(ContextEvent::ShowPaymentRequiredError);
+                            cx.emit(TextThreadEvent::ShowPaymentRequiredError);
                             this.update_metadata(assistant_message_id, cx, |metadata| {
                                 metadata.status = MessageStatus::Canceled;
                             });
@@ -2195,7 +2185,7 @@ impl AssistantContext {
                                 .map(|err| err.to_string())
                                 .collect::<Vec<_>>()
                                 .join("\n");
-                            cx.emit(ContextEvent::ShowAssistError(SharedString::from(
+                            cx.emit(TextThreadEvent::ShowAssistError(SharedString::from(
                                 error_message.clone(),
                             )));
                             this.update_metadata(assistant_message_id, cx, |metadata| {
@@ -2412,13 +2402,13 @@ impl AssistantContext {
         if let Some(metadata) = self.messages_metadata.get_mut(&id) {
             f(metadata);
             metadata.timestamp = timestamp;
-            let operation = ContextOperation::UpdateMessage {
+            let operation = TextThreadOperation::UpdateMessage {
                 message_id: id,
                 metadata: metadata.clone(),
                 version,
             };
             self.push_op(operation, cx);
-            cx.emit(ContextEvent::MessagesEdited);
+            cx.emit(TextThreadEvent::MessagesEdited);
             cx.notify();
         }
     }
@@ -2482,7 +2472,7 @@ impl AssistantContext {
         };
         self.insert_message(anchor.clone(), metadata.clone(), cx);
         self.push_op(
-            ContextOperation::InsertMessage {
+            TextThreadOperation::InsertMessage {
                 anchor: anchor.clone(),
                 metadata,
                 version,
@@ -2505,7 +2495,7 @@ impl AssistantContext {
             Err(ix) => ix,
         };
         self.contents.insert(insertion_ix, content);
-        cx.emit(ContextEvent::MessagesEdited);
+        cx.emit(TextThreadEvent::MessagesEdited);
     }
 
     pub fn contents<'a>(&'a self, cx: &'a App) -> impl 'a + Iterator<Item = Content> {
@@ -2580,7 +2570,7 @@ impl AssistantContext {
             };
             self.insert_message(suffix.clone(), suffix_metadata.clone(), cx);
             self.push_op(
-                ContextOperation::InsertMessage {
+                TextThreadOperation::InsertMessage {
                     anchor: suffix.clone(),
                     metadata: suffix_metadata,
                     version,
@@ -2630,7 +2620,7 @@ impl AssistantContext {
                     };
                     self.insert_message(selection.clone(), selection_metadata.clone(), cx);
                     self.push_op(
-                        ContextOperation::InsertMessage {
+                        TextThreadOperation::InsertMessage {
                             anchor: selection.clone(),
                             metadata: selection_metadata,
                             version,
@@ -2642,7 +2632,7 @@ impl AssistantContext {
                 };
 
             if !edited_buffer {
-                cx.emit(ContextEvent::MessagesEdited);
+                cx.emit(TextThreadEvent::MessagesEdited);
             }
             new_messages
         } else {
@@ -2656,7 +2646,7 @@ impl AssistantContext {
         new_metadata: MessageMetadata,
         cx: &mut Context<Self>,
     ) {
-        cx.emit(ContextEvent::MessagesEdited);
+        cx.emit(TextThreadEvent::MessagesEdited);
 
         self.messages_metadata.insert(new_anchor.id, new_metadata);
 
@@ -2692,15 +2682,15 @@ impl AssistantContext {
             // If there is no summary, it is set with `done: false` so that "Loading Summary…" can
             // be displayed.
             match self.summary {
-                ContextSummary::Pending | ContextSummary::Error => {
-                    self.summary = ContextSummary::Content(ContextSummaryContent {
+                TextThreadSummary::Pending | TextThreadSummary::Error => {
+                    self.summary = TextThreadSummary::Content(TextThreadSummaryContent {
                         text: "".to_string(),
                         done: false,
                         timestamp: clock::Lamport::MIN,
                     });
                     replace_old = true;
                 }
-                ContextSummary::Content(_) => {}
+                TextThreadSummary::Content(_) => {}
             }
 
             self.summary_task = cx.spawn(async move |this, cx| {
@@ -2722,13 +2712,13 @@ impl AssistantContext {
                             }
                             summary.text.extend(lines.next());
                             summary.timestamp = timestamp;
-                            let operation = ContextOperation::UpdateSummary {
+                            let operation = TextThreadOperation::UpdateSummary {
                                 summary: summary.clone(),
                                 version,
                             };
                             this.push_op(operation, cx);
-                            cx.emit(ContextEvent::SummaryChanged);
-                            cx.emit(ContextEvent::SummaryGenerated);
+                            cx.emit(TextThreadEvent::SummaryChanged);
+                            cx.emit(TextThreadEvent::SummaryGenerated);
                         })?;
 
                         // Stop if the LLM generated multiple lines.
@@ -2752,13 +2742,13 @@ impl AssistantContext {
                         if let Some(summary) = this.summary.content_as_mut() {
                             summary.done = true;
                             summary.timestamp = timestamp;
-                            let operation = ContextOperation::UpdateSummary {
+                            let operation = TextThreadOperation::UpdateSummary {
                                 summary: summary.clone(),
                                 version,
                             };
                             this.push_op(operation, cx);
-                            cx.emit(ContextEvent::SummaryChanged);
-                            cx.emit(ContextEvent::SummaryGenerated);
+                            cx.emit(TextThreadEvent::SummaryChanged);
+                            cx.emit(TextThreadEvent::SummaryGenerated);
                         }
                     })?;
 
@@ -2768,8 +2758,8 @@ impl AssistantContext {
 
                 if let Err(err) = result {
                     this.update(cx, |this, cx| {
-                        this.summary = ContextSummary::Error;
-                        cx.emit(ContextEvent::SummaryChanged);
+                        this.summary = TextThreadSummary::Error;
+                        cx.emit(TextThreadEvent::SummaryChanged);
                     })
                     .log_err();
                     log::error!("Error generating context summary: {}", err);
@@ -2875,7 +2865,7 @@ impl AssistantContext {
         &mut self,
         debounce: Option<Duration>,
         fs: Arc<dyn Fs>,
-        cx: &mut Context<AssistantContext>,
+        cx: &mut Context<TextThread>,
     ) {
         if self.replica_id() != ReplicaId::default() {
             // Prevent saving a remote context for now.
@@ -2906,7 +2896,7 @@ impl AssistantContext {
                 let mut discriminant = 1;
                 let mut new_path;
                 loop {
-                    new_path = contexts_dir().join(&format!(
+                    new_path = text_threads_dir().join(&format!(
                         "{} - {}.zed.json",
                         summary.trim(),
                         discriminant
@@ -2918,7 +2908,7 @@ impl AssistantContext {
                     }
                 }
 
-                fs.create_dir(contexts_dir().as_ref()).await?;
+                fs.create_dir(text_threads_dir().as_ref()).await?;
 
                 // rename before write ensures that only one file exists
                 if let Some(old_path) = old_path.as_ref()
@@ -2940,7 +2930,7 @@ impl AssistantContext {
                     let new_path: Arc<Path> = new_path.clone().into();
                     move |this, cx| {
                         this.path = Some(new_path.clone());
-                        cx.emit(ContextEvent::PathChanged { old_path, new_path });
+                        cx.emit(TextThreadEvent::PathChanged { old_path, new_path });
                     }
                 })
                 .ok();
@@ -2959,7 +2949,7 @@ impl AssistantContext {
         summary.timestamp = timestamp;
         summary.done = true;
         summary.text = custom_summary;
-        cx.emit(ContextEvent::SummaryChanged);
+        cx.emit(TextThreadEvent::SummaryChanged);
     }
 
     fn update_model_request_usage(&self, amount: u32, limit: UsageLimit, cx: &mut App) {
@@ -2979,23 +2969,23 @@ impl AssistantContext {
 }
 
 #[derive(Debug, Default)]
-pub struct ContextVersion {
-    context: clock::Global,
+pub struct TextThreadVersion {
+    text_thread: clock::Global,
     buffer: clock::Global,
 }
 
-impl ContextVersion {
+impl TextThreadVersion {
     pub fn from_proto(proto: &proto::ContextVersion) -> Self {
         Self {
-            context: language::proto::deserialize_version(&proto.context_version),
+            text_thread: language::proto::deserialize_version(&proto.context_version),
             buffer: language::proto::deserialize_version(&proto.buffer_version),
         }
     }
 
-    pub fn to_proto(&self, context_id: ContextId) -> proto::ContextVersion {
+    pub fn to_proto(&self, context_id: TextThreadId) -> proto::ContextVersion {
         proto::ContextVersion {
             context_id: context_id.to_proto(),
-            context_version: language::proto::serialize_version(&self.context),
+            context_version: language::proto::serialize_version(&self.text_thread),
             buffer_version: language::proto::serialize_version(&self.buffer),
         }
     }
@@ -3063,8 +3053,8 @@ pub struct SavedMessage {
 }
 
 #[derive(Serialize, Deserialize)]
-pub struct SavedContext {
-    pub id: Option<ContextId>,
+pub struct SavedTextThread {
+    pub id: Option<TextThreadId>,
     pub zed: String,
     pub version: String,
     pub text: String,
@@ -3076,7 +3066,7 @@ pub struct SavedContext {
     pub thought_process_output_sections: Vec<ThoughtProcessOutputSection<usize>>,
 }
 
-impl SavedContext {
+impl SavedTextThread {
     pub const VERSION: &'static str = "0.4.0";
 
     pub fn from_json(json: &str) -> Result<Self> {
@@ -3086,9 +3076,9 @@ impl SavedContext {
             .context("version not found")?
         {
             serde_json::Value::String(version) => match version.as_str() {
-                SavedContext::VERSION => {
-                    Ok(serde_json::from_value::<SavedContext>(saved_context_json)?)
-                }
+                SavedTextThread::VERSION => Ok(serde_json::from_value::<SavedTextThread>(
+                    saved_context_json,
+                )?),
                 SavedContextV0_3_0::VERSION => {
                     let saved_context =
                         serde_json::from_value::<SavedContextV0_3_0>(saved_context_json)?;
@@ -3113,8 +3103,8 @@ impl SavedContext {
     fn into_ops(
         self,
         buffer: &Entity<Buffer>,
-        cx: &mut Context<AssistantContext>,
-    ) -> Vec<ContextOperation> {
+        cx: &mut Context<TextThread>,
+    ) -> Vec<TextThreadOperation> {
         let mut operations = Vec::new();
         let mut version = clock::Global::new();
         let mut next_timestamp = clock::Lamport::new(ReplicaId::default());
@@ -3124,7 +3114,7 @@ impl SavedContext {
             if message.id == MessageId(clock::Lamport::MIN) {
                 first_message_metadata = Some(message.metadata);
             } else {
-                operations.push(ContextOperation::InsertMessage {
+                operations.push(TextThreadOperation::InsertMessage {
                     anchor: MessageAnchor {
                         id: message.id,
                         start: buffer.read(cx).anchor_before(message.start),
@@ -3144,7 +3134,7 @@ impl SavedContext {
 
         if let Some(metadata) = first_message_metadata {
             let timestamp = next_timestamp.tick();
-            operations.push(ContextOperation::UpdateMessage {
+            operations.push(TextThreadOperation::UpdateMessage {
                 message_id: MessageId(clock::Lamport::MIN),
                 metadata: MessageMetadata {
                     role: metadata.role,
@@ -3160,7 +3150,7 @@ impl SavedContext {
         let buffer = buffer.read(cx);
         for section in self.slash_command_output_sections {
             let timestamp = next_timestamp.tick();
-            operations.push(ContextOperation::SlashCommandOutputSectionAdded {
+            operations.push(TextThreadOperation::SlashCommandOutputSectionAdded {
                 timestamp,
                 section: SlashCommandOutputSection {
                     range: buffer.anchor_after(section.range.start)
@@ -3177,7 +3167,7 @@ impl SavedContext {
 
         for section in self.thought_process_output_sections {
             let timestamp = next_timestamp.tick();
-            operations.push(ContextOperation::ThoughtProcessOutputSectionAdded {
+            operations.push(TextThreadOperation::ThoughtProcessOutputSectionAdded {
                 timestamp,
                 section: ThoughtProcessOutputSection {
                     range: buffer.anchor_after(section.range.start)
@@ -3190,8 +3180,8 @@ impl SavedContext {
         }
 
         let timestamp = next_timestamp.tick();
-        operations.push(ContextOperation::UpdateSummary {
-            summary: ContextSummaryContent {
+        operations.push(TextThreadOperation::UpdateSummary {
+            summary: TextThreadSummaryContent {
                 text: self.summary,
                 done: true,
                 timestamp,
@@ -3221,7 +3211,7 @@ struct SavedMessageMetadataPreV0_4_0 {
 
 #[derive(Serialize, Deserialize)]
 struct SavedContextV0_3_0 {
-    id: Option<ContextId>,
+    id: Option<TextThreadId>,
     zed: String,
     version: String,
     text: String,
@@ -3234,11 +3224,11 @@ struct SavedContextV0_3_0 {
 impl SavedContextV0_3_0 {
     const VERSION: &'static str = "0.3.0";
 
-    fn upgrade(self) -> SavedContext {
-        SavedContext {
+    fn upgrade(self) -> SavedTextThread {
+        SavedTextThread {
             id: self.id,
             zed: self.zed,
-            version: SavedContext::VERSION.into(),
+            version: SavedTextThread::VERSION.into(),
             text: self.text,
             messages: self
                 .messages
@@ -3270,7 +3260,7 @@ impl SavedContextV0_3_0 {
 
 #[derive(Serialize, Deserialize)]
 struct SavedContextV0_2_0 {
-    id: Option<ContextId>,
+    id: Option<TextThreadId>,
     zed: String,
     version: String,
     text: String,
@@ -3282,7 +3272,7 @@ struct SavedContextV0_2_0 {
 impl SavedContextV0_2_0 {
     const VERSION: &'static str = "0.2.0";
 
-    fn upgrade(self) -> SavedContext {
+    fn upgrade(self) -> SavedTextThread {
         SavedContextV0_3_0 {
             id: self.id,
             zed: self.zed,

crates/assistant_context/src/context_store.rs β†’ crates/assistant_text_thread/src/text_thread_store.rs πŸ”—

@@ -1,6 +1,6 @@
 use crate::{
-    AssistantContext, ContextEvent, ContextId, ContextOperation, ContextVersion, SavedContext,
-    SavedContextMetadata,
+    SavedTextThread, SavedTextThreadMetadata, TextThread, TextThreadEvent, TextThreadId,
+    TextThreadOperation, TextThreadVersion,
 };
 use anyhow::{Context as _, Result};
 use assistant_slash_command::{SlashCommandId, SlashCommandWorkingSet};
@@ -11,9 +11,9 @@ use context_server::ContextServerId;
 use fs::{Fs, RemoveOptions};
 use futures::StreamExt;
 use fuzzy::StringMatchCandidate;
-use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
+use gpui::{App, AppContext as _, AsyncApp, Context, Entity, Task, WeakEntity};
 use language::LanguageRegistry;
-use paths::contexts_dir;
+use paths::text_threads_dir;
 use project::{
     Project,
     context_server_store::{ContextServerStatus, ContextServerStore},
@@ -27,24 +27,24 @@ use util::{ResultExt, TryFutureExt};
 use zed_env_vars::ZED_STATELESS;
 
 pub(crate) fn init(client: &AnyProtoClient) {
-    client.add_entity_message_handler(ContextStore::handle_advertise_contexts);
-    client.add_entity_request_handler(ContextStore::handle_open_context);
-    client.add_entity_request_handler(ContextStore::handle_create_context);
-    client.add_entity_message_handler(ContextStore::handle_update_context);
-    client.add_entity_request_handler(ContextStore::handle_synchronize_contexts);
+    client.add_entity_message_handler(TextThreadStore::handle_advertise_contexts);
+    client.add_entity_request_handler(TextThreadStore::handle_open_context);
+    client.add_entity_request_handler(TextThreadStore::handle_create_context);
+    client.add_entity_message_handler(TextThreadStore::handle_update_context);
+    client.add_entity_request_handler(TextThreadStore::handle_synchronize_contexts);
 }
 
 #[derive(Clone)]
-pub struct RemoteContextMetadata {
-    pub id: ContextId,
+pub struct RemoteTextThreadMetadata {
+    pub id: TextThreadId,
     pub summary: Option<String>,
 }
 
-pub struct ContextStore {
-    contexts: Vec<ContextHandle>,
-    contexts_metadata: Vec<SavedContextMetadata>,
+pub struct TextThreadStore {
+    text_threads: Vec<TextThreadHandle>,
+    text_threads_metadata: Vec<SavedTextThreadMetadata>,
     context_server_slash_command_ids: HashMap<ContextServerId, Vec<SlashCommandId>>,
-    host_contexts: Vec<RemoteContextMetadata>,
+    host_text_threads: Vec<RemoteTextThreadMetadata>,
     fs: Arc<dyn Fs>,
     languages: Arc<LanguageRegistry>,
     slash_commands: Arc<SlashCommandWorkingSet>,
@@ -58,34 +58,28 @@ pub struct ContextStore {
     prompt_builder: Arc<PromptBuilder>,
 }
 
-pub enum ContextStoreEvent {
-    ContextCreated(ContextId),
+enum TextThreadHandle {
+    Weak(WeakEntity<TextThread>),
+    Strong(Entity<TextThread>),
 }
 
-impl EventEmitter<ContextStoreEvent> for ContextStore {}
-
-enum ContextHandle {
-    Weak(WeakEntity<AssistantContext>),
-    Strong(Entity<AssistantContext>),
-}
-
-impl ContextHandle {
-    fn upgrade(&self) -> Option<Entity<AssistantContext>> {
+impl TextThreadHandle {
+    fn upgrade(&self) -> Option<Entity<TextThread>> {
         match self {
-            ContextHandle::Weak(weak) => weak.upgrade(),
-            ContextHandle::Strong(strong) => Some(strong.clone()),
+            TextThreadHandle::Weak(weak) => weak.upgrade(),
+            TextThreadHandle::Strong(strong) => Some(strong.clone()),
         }
     }
 
-    fn downgrade(&self) -> WeakEntity<AssistantContext> {
+    fn downgrade(&self) -> WeakEntity<TextThread> {
         match self {
-            ContextHandle::Weak(weak) => weak.clone(),
-            ContextHandle::Strong(strong) => strong.downgrade(),
+            TextThreadHandle::Weak(weak) => weak.clone(),
+            TextThreadHandle::Strong(strong) => strong.downgrade(),
         }
     }
 }
 
-impl ContextStore {
+impl TextThreadStore {
     pub fn new(
         project: Entity<Project>,
         prompt_builder: Arc<PromptBuilder>,
@@ -97,14 +91,14 @@ impl ContextStore {
         let telemetry = project.read(cx).client().telemetry().clone();
         cx.spawn(async move |cx| {
             const CONTEXT_WATCH_DURATION: Duration = Duration::from_millis(100);
-            let (mut events, _) = fs.watch(contexts_dir(), CONTEXT_WATCH_DURATION).await;
+            let (mut events, _) = fs.watch(text_threads_dir(), CONTEXT_WATCH_DURATION).await;
 
             let this = cx.new(|cx: &mut Context<Self>| {
                 let mut this = Self {
-                    contexts: Vec::new(),
-                    contexts_metadata: Vec::new(),
+                    text_threads: Vec::new(),
+                    text_threads_metadata: Vec::new(),
                     context_server_slash_command_ids: HashMap::default(),
-                    host_contexts: Vec::new(),
+                    host_text_threads: Vec::new(),
                     fs,
                     languages,
                     slash_commands,
@@ -142,10 +136,10 @@ impl ContextStore {
     #[cfg(any(test, feature = "test-support"))]
     pub fn fake(project: Entity<Project>, cx: &mut Context<Self>) -> Self {
         Self {
-            contexts: Default::default(),
-            contexts_metadata: Default::default(),
+            text_threads: Default::default(),
+            text_threads_metadata: Default::default(),
             context_server_slash_command_ids: Default::default(),
-            host_contexts: Default::default(),
+            host_text_threads: Default::default(),
             fs: project.read(cx).fs().clone(),
             languages: project.read(cx).languages().clone(),
             slash_commands: Arc::default(),
@@ -166,13 +160,13 @@ impl ContextStore {
         mut cx: AsyncApp,
     ) -> Result<()> {
         this.update(&mut cx, |this, cx| {
-            this.host_contexts = envelope
+            this.host_text_threads = envelope
                 .payload
                 .contexts
                 .into_iter()
-                .map(|context| RemoteContextMetadata {
-                    id: ContextId::from_proto(context.context_id),
-                    summary: context.summary,
+                .map(|text_thread| RemoteTextThreadMetadata {
+                    id: TextThreadId::from_proto(text_thread.context_id),
+                    summary: text_thread.summary,
                 })
                 .collect();
             cx.notify();
@@ -184,25 +178,25 @@ impl ContextStore {
         envelope: TypedEnvelope<proto::OpenContext>,
         mut cx: AsyncApp,
     ) -> Result<proto::OpenContextResponse> {
-        let context_id = ContextId::from_proto(envelope.payload.context_id);
+        let context_id = TextThreadId::from_proto(envelope.payload.context_id);
         let operations = this.update(&mut cx, |this, cx| {
             anyhow::ensure!(
                 !this.project.read(cx).is_via_collab(),
                 "only the host contexts can be opened"
             );
 
-            let context = this
-                .loaded_context_for_id(&context_id, cx)
+            let text_thread = this
+                .loaded_text_thread_for_id(&context_id, cx)
                 .context("context not found")?;
             anyhow::ensure!(
-                context.read(cx).replica_id() == ReplicaId::default(),
+                text_thread.read(cx).replica_id() == ReplicaId::default(),
                 "context must be opened via the host"
             );
 
             anyhow::Ok(
-                context
+                text_thread
                     .read(cx)
-                    .serialize_ops(&ContextVersion::default(), cx),
+                    .serialize_ops(&TextThreadVersion::default(), cx),
             )
         })??;
         let operations = operations.await;
@@ -222,15 +216,14 @@ impl ContextStore {
                 "can only create contexts as the host"
             );
 
-            let context = this.create(cx);
-            let context_id = context.read(cx).id().clone();
-            cx.emit(ContextStoreEvent::ContextCreated(context_id.clone()));
+            let text_thread = this.create(cx);
+            let context_id = text_thread.read(cx).id().clone();
 
             anyhow::Ok((
                 context_id,
-                context
+                text_thread
                     .read(cx)
-                    .serialize_ops(&ContextVersion::default(), cx),
+                    .serialize_ops(&TextThreadVersion::default(), cx),
             ))
         })??;
         let operations = operations.await;
@@ -246,11 +239,11 @@ impl ContextStore {
         mut cx: AsyncApp,
     ) -> Result<()> {
         this.update(&mut cx, |this, cx| {
-            let context_id = ContextId::from_proto(envelope.payload.context_id);
-            if let Some(context) = this.loaded_context_for_id(&context_id, cx) {
+            let context_id = TextThreadId::from_proto(envelope.payload.context_id);
+            if let Some(text_thread) = this.loaded_text_thread_for_id(&context_id, cx) {
                 let operation_proto = envelope.payload.operation.context("invalid operation")?;
-                let operation = ContextOperation::from_proto(operation_proto)?;
-                context.update(cx, |context, cx| context.apply_ops([operation], cx));
+                let operation = TextThreadOperation::from_proto(operation_proto)?;
+                text_thread.update(cx, |text_thread, cx| text_thread.apply_ops([operation], cx));
             }
             Ok(())
         })?
@@ -269,12 +262,12 @@ impl ContextStore {
 
             let mut local_versions = Vec::new();
             for remote_version_proto in envelope.payload.contexts {
-                let remote_version = ContextVersion::from_proto(&remote_version_proto);
-                let context_id = ContextId::from_proto(remote_version_proto.context_id);
-                if let Some(context) = this.loaded_context_for_id(&context_id, cx) {
-                    let context = context.read(cx);
-                    let operations = context.serialize_ops(&remote_version, cx);
-                    local_versions.push(context.version(cx).to_proto(context_id.clone()));
+                let remote_version = TextThreadVersion::from_proto(&remote_version_proto);
+                let context_id = TextThreadId::from_proto(remote_version_proto.context_id);
+                if let Some(text_thread) = this.loaded_text_thread_for_id(&context_id, cx) {
+                    let text_thread = text_thread.read(cx);
+                    let operations = text_thread.serialize_ops(&remote_version, cx);
+                    local_versions.push(text_thread.version(cx).to_proto(context_id.clone()));
                     let client = this.client.clone();
                     let project_id = envelope.payload.project_id;
                     cx.background_spawn(async move {
@@ -308,9 +301,9 @@ impl ContextStore {
         }
 
         if is_shared {
-            self.contexts.retain_mut(|context| {
-                if let Some(strong_context) = context.upgrade() {
-                    *context = ContextHandle::Strong(strong_context);
+            self.text_threads.retain_mut(|text_thread| {
+                if let Some(strong_context) = text_thread.upgrade() {
+                    *text_thread = TextThreadHandle::Strong(strong_context);
                     true
                 } else {
                     false
@@ -345,12 +338,12 @@ impl ContextStore {
                 self.synchronize_contexts(cx);
             }
             project::Event::DisconnectedFromHost => {
-                self.contexts.retain_mut(|context| {
-                    if let Some(strong_context) = context.upgrade() {
-                        *context = ContextHandle::Weak(context.downgrade());
-                        strong_context.update(cx, |context, cx| {
-                            if context.replica_id() != ReplicaId::default() {
-                                context.set_capability(language::Capability::ReadOnly, cx);
+                self.text_threads.retain_mut(|text_thread| {
+                    if let Some(strong_context) = text_thread.upgrade() {
+                        *text_thread = TextThreadHandle::Weak(text_thread.downgrade());
+                        strong_context.update(cx, |text_thread, cx| {
+                            if text_thread.replica_id() != ReplicaId::default() {
+                                text_thread.set_capability(language::Capability::ReadOnly, cx);
                             }
                         });
                         true
@@ -358,20 +351,24 @@ impl ContextStore {
                         false
                     }
                 });
-                self.host_contexts.clear();
+                self.host_text_threads.clear();
                 cx.notify();
             }
             _ => {}
         }
     }
 
-    pub fn unordered_contexts(&self) -> impl Iterator<Item = &SavedContextMetadata> {
-        self.contexts_metadata.iter()
+    pub fn unordered_text_threads(&self) -> impl Iterator<Item = &SavedTextThreadMetadata> {
+        self.text_threads_metadata.iter()
     }
 
-    pub fn create(&mut self, cx: &mut Context<Self>) -> Entity<AssistantContext> {
+    pub fn host_text_threads(&self) -> impl Iterator<Item = &RemoteTextThreadMetadata> {
+        self.host_text_threads.iter()
+    }
+
+    pub fn create(&mut self, cx: &mut Context<Self>) -> Entity<TextThread> {
         let context = cx.new(|cx| {
-            AssistantContext::local(
+            TextThread::local(
                 self.languages.clone(),
                 Some(self.project.clone()),
                 Some(self.telemetry.clone()),
@@ -380,14 +377,11 @@ impl ContextStore {
                 cx,
             )
         });
-        self.register_context(&context, cx);
+        self.register_text_thread(&context, cx);
         context
     }
 
-    pub fn create_remote_context(
-        &mut self,
-        cx: &mut Context<Self>,
-    ) -> Task<Result<Entity<AssistantContext>>> {
+    pub fn create_remote(&mut self, cx: &mut Context<Self>) -> Task<Result<Entity<TextThread>>> {
         let project = self.project.read(cx);
         let Some(project_id) = project.remote_id() else {
             return Task::ready(Err(anyhow::anyhow!("project was not remote")));
@@ -403,10 +397,10 @@ impl ContextStore {
         let request = self.client.request(proto::CreateContext { project_id });
         cx.spawn(async move |this, cx| {
             let response = request.await?;
-            let context_id = ContextId::from_proto(response.context_id);
+            let context_id = TextThreadId::from_proto(response.context_id);
             let context_proto = response.context.context("invalid context")?;
-            let context = cx.new(|cx| {
-                AssistantContext::new(
+            let text_thread = cx.new(|cx| {
+                TextThread::new(
                     context_id.clone(),
                     replica_id,
                     capability,
@@ -423,29 +417,29 @@ impl ContextStore {
                     context_proto
                         .operations
                         .into_iter()
-                        .map(ContextOperation::from_proto)
+                        .map(TextThreadOperation::from_proto)
                         .collect::<Result<Vec<_>>>()
                 })
                 .await?;
-            context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
+            text_thread.update(cx, |context, cx| context.apply_ops(operations, cx))?;
             this.update(cx, |this, cx| {
-                if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) {
+                if let Some(existing_context) = this.loaded_text_thread_for_id(&context_id, cx) {
                     existing_context
                 } else {
-                    this.register_context(&context, cx);
+                    this.register_text_thread(&text_thread, cx);
                     this.synchronize_contexts(cx);
-                    context
+                    text_thread
                 }
             })
         })
     }
 
-    pub fn open_local_context(
+    pub fn open_local(
         &mut self,
         path: Arc<Path>,
         cx: &Context<Self>,
-    ) -> Task<Result<Entity<AssistantContext>>> {
-        if let Some(existing_context) = self.loaded_context_for_path(&path, cx) {
+    ) -> Task<Result<Entity<TextThread>>> {
+        if let Some(existing_context) = self.loaded_text_thread_for_path(&path, cx) {
             return Task::ready(Ok(existing_context));
         }
 
@@ -457,7 +451,7 @@ impl ContextStore {
             let path = path.clone();
             async move {
                 let saved_context = fs.load(&path).await?;
-                SavedContext::from_json(&saved_context)
+                SavedTextThread::from_json(&saved_context)
             }
         });
         let prompt_builder = self.prompt_builder.clone();
@@ -466,7 +460,7 @@ impl ContextStore {
         cx.spawn(async move |this, cx| {
             let saved_context = load.await?;
             let context = cx.new(|cx| {
-                AssistantContext::deserialize(
+                TextThread::deserialize(
                     saved_context,
                     path.clone(),
                     languages,
@@ -478,21 +472,17 @@ impl ContextStore {
                 )
             })?;
             this.update(cx, |this, cx| {
-                if let Some(existing_context) = this.loaded_context_for_path(&path, cx) {
+                if let Some(existing_context) = this.loaded_text_thread_for_path(&path, cx) {
                     existing_context
                 } else {
-                    this.register_context(&context, cx);
+                    this.register_text_thread(&context, cx);
                     context
                 }
             })
         })
     }
 
-    pub fn delete_local_context(
-        &mut self,
-        path: Arc<Path>,
-        cx: &mut Context<Self>,
-    ) -> Task<Result<()>> {
+    pub fn delete_local(&mut self, path: Arc<Path>, cx: &mut Context<Self>) -> Task<Result<()>> {
         let fs = self.fs.clone();
 
         cx.spawn(async move |this, cx| {
@@ -506,57 +496,57 @@ impl ContextStore {
             .await?;
 
             this.update(cx, |this, cx| {
-                this.contexts.retain(|context| {
-                    context
+                this.text_threads.retain(|text_thread| {
+                    text_thread
                         .upgrade()
-                        .and_then(|context| context.read(cx).path())
+                        .and_then(|text_thread| text_thread.read(cx).path())
                         != Some(&path)
                 });
-                this.contexts_metadata
-                    .retain(|context| context.path.as_ref() != path.as_ref());
+                this.text_threads_metadata
+                    .retain(|text_thread| text_thread.path.as_ref() != path.as_ref());
             })?;
 
             Ok(())
         })
     }
 
-    fn loaded_context_for_path(&self, path: &Path, cx: &App) -> Option<Entity<AssistantContext>> {
-        self.contexts.iter().find_map(|context| {
-            let context = context.upgrade()?;
-            if context.read(cx).path().map(Arc::as_ref) == Some(path) {
-                Some(context)
+    fn loaded_text_thread_for_path(&self, path: &Path, cx: &App) -> Option<Entity<TextThread>> {
+        self.text_threads.iter().find_map(|text_thread| {
+            let text_thread = text_thread.upgrade()?;
+            if text_thread.read(cx).path().map(Arc::as_ref) == Some(path) {
+                Some(text_thread)
             } else {
                 None
             }
         })
     }
 
-    pub fn loaded_context_for_id(
+    pub fn loaded_text_thread_for_id(
         &self,
-        id: &ContextId,
+        id: &TextThreadId,
         cx: &App,
-    ) -> Option<Entity<AssistantContext>> {
-        self.contexts.iter().find_map(|context| {
-            let context = context.upgrade()?;
-            if context.read(cx).id() == id {
-                Some(context)
+    ) -> Option<Entity<TextThread>> {
+        self.text_threads.iter().find_map(|text_thread| {
+            let text_thread = text_thread.upgrade()?;
+            if text_thread.read(cx).id() == id {
+                Some(text_thread)
             } else {
                 None
             }
         })
     }
 
-    pub fn open_remote_context(
+    pub fn open_remote(
         &mut self,
-        context_id: ContextId,
+        text_thread_id: TextThreadId,
         cx: &mut Context<Self>,
-    ) -> Task<Result<Entity<AssistantContext>>> {
+    ) -> Task<Result<Entity<TextThread>>> {
         let project = self.project.read(cx);
         let Some(project_id) = project.remote_id() else {
             return Task::ready(Err(anyhow::anyhow!("project was not remote")));
         };
 
-        if let Some(context) = self.loaded_context_for_id(&context_id, cx) {
+        if let Some(context) = self.loaded_text_thread_for_id(&text_thread_id, cx) {
             return Task::ready(Ok(context));
         }
 
@@ -567,16 +557,16 @@ impl ContextStore {
         let telemetry = self.telemetry.clone();
         let request = self.client.request(proto::OpenContext {
             project_id,
-            context_id: context_id.to_proto(),
+            context_id: text_thread_id.to_proto(),
         });
         let prompt_builder = self.prompt_builder.clone();
         let slash_commands = self.slash_commands.clone();
         cx.spawn(async move |this, cx| {
             let response = request.await?;
             let context_proto = response.context.context("invalid context")?;
-            let context = cx.new(|cx| {
-                AssistantContext::new(
-                    context_id.clone(),
+            let text_thread = cx.new(|cx| {
+                TextThread::new(
+                    text_thread_id.clone(),
                     replica_id,
                     capability,
                     language_registry,
@@ -592,38 +582,40 @@ impl ContextStore {
                     context_proto
                         .operations
                         .into_iter()
-                        .map(ContextOperation::from_proto)
+                        .map(TextThreadOperation::from_proto)
                         .collect::<Result<Vec<_>>>()
                 })
                 .await?;
-            context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
+            text_thread.update(cx, |context, cx| context.apply_ops(operations, cx))?;
             this.update(cx, |this, cx| {
-                if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) {
+                if let Some(existing_context) = this.loaded_text_thread_for_id(&text_thread_id, cx)
+                {
                     existing_context
                 } else {
-                    this.register_context(&context, cx);
+                    this.register_text_thread(&text_thread, cx);
                     this.synchronize_contexts(cx);
-                    context
+                    text_thread
                 }
             })
         })
     }
 
-    fn register_context(&mut self, context: &Entity<AssistantContext>, cx: &mut Context<Self>) {
+    fn register_text_thread(&mut self, text_thread: &Entity<TextThread>, cx: &mut Context<Self>) {
         let handle = if self.project_is_shared {
-            ContextHandle::Strong(context.clone())
+            TextThreadHandle::Strong(text_thread.clone())
         } else {
-            ContextHandle::Weak(context.downgrade())
+            TextThreadHandle::Weak(text_thread.downgrade())
         };
-        self.contexts.push(handle);
+        self.text_threads.push(handle);
         self.advertise_contexts(cx);
-        cx.subscribe(context, Self::handle_context_event).detach();
+        cx.subscribe(text_thread, Self::handle_context_event)
+            .detach();
     }
 
     fn handle_context_event(
         &mut self,
-        context: Entity<AssistantContext>,
-        event: &ContextEvent,
+        text_thread: Entity<TextThread>,
+        event: &TextThreadEvent,
         cx: &mut Context<Self>,
     ) {
         let Some(project_id) = self.project.read(cx).remote_id() else {
@@ -631,12 +623,12 @@ impl ContextStore {
         };
 
         match event {
-            ContextEvent::SummaryChanged => {
+            TextThreadEvent::SummaryChanged => {
                 self.advertise_contexts(cx);
             }
-            ContextEvent::PathChanged { old_path, new_path } => {
+            TextThreadEvent::PathChanged { old_path, new_path } => {
                 if let Some(old_path) = old_path.as_ref() {
-                    for metadata in &mut self.contexts_metadata {
+                    for metadata in &mut self.text_threads_metadata {
                         if &metadata.path == old_path {
                             metadata.path = new_path.clone();
                             break;
@@ -644,8 +636,8 @@ impl ContextStore {
                     }
                 }
             }
-            ContextEvent::Operation(operation) => {
-                let context_id = context.read(cx).id().to_proto();
+            TextThreadEvent::Operation(operation) => {
+                let context_id = text_thread.read(cx).id().to_proto();
                 let operation = operation.to_proto();
                 self.client
                     .send(proto::UpdateContext {
@@ -670,15 +662,15 @@ impl ContextStore {
         }
 
         let contexts = self
-            .contexts
+            .text_threads
             .iter()
             .rev()
-            .filter_map(|context| {
-                let context = context.upgrade()?.read(cx);
-                if context.replica_id() == ReplicaId::default() {
+            .filter_map(|text_thread| {
+                let text_thread = text_thread.upgrade()?.read(cx);
+                if text_thread.replica_id() == ReplicaId::default() {
                     Some(proto::ContextMetadata {
-                        context_id: context.id().to_proto(),
-                        summary: context
+                        context_id: text_thread.id().to_proto(),
+                        summary: text_thread
                             .summary()
                             .content()
                             .map(|summary| summary.text.clone()),
@@ -701,13 +693,13 @@ impl ContextStore {
             return;
         };
 
-        let contexts = self
-            .contexts
+        let text_threads = self
+            .text_threads
             .iter()
-            .filter_map(|context| {
-                let context = context.upgrade()?.read(cx);
-                if context.replica_id() != ReplicaId::default() {
-                    Some(context.version(cx).to_proto(context.id().clone()))
+            .filter_map(|text_thread| {
+                let text_thread = text_thread.upgrade()?.read(cx);
+                if text_thread.replica_id() != ReplicaId::default() {
+                    Some(text_thread.version(cx).to_proto(text_thread.id().clone()))
                 } else {
                     None
                 }
@@ -717,26 +709,27 @@ impl ContextStore {
         let client = self.client.clone();
         let request = self.client.request(proto::SynchronizeContexts {
             project_id,
-            contexts,
+            contexts: text_threads,
         });
         cx.spawn(async move |this, cx| {
             let response = request.await?;
 
-            let mut context_ids = Vec::new();
+            let mut text_thread_ids = Vec::new();
             let mut operations = Vec::new();
             this.read_with(cx, |this, cx| {
                 for context_version_proto in response.contexts {
-                    let context_version = ContextVersion::from_proto(&context_version_proto);
-                    let context_id = ContextId::from_proto(context_version_proto.context_id);
-                    if let Some(context) = this.loaded_context_for_id(&context_id, cx) {
-                        context_ids.push(context_id);
-                        operations.push(context.read(cx).serialize_ops(&context_version, cx));
+                    let text_thread_version = TextThreadVersion::from_proto(&context_version_proto);
+                    let text_thread_id = TextThreadId::from_proto(context_version_proto.context_id);
+                    if let Some(text_thread) = this.loaded_text_thread_for_id(&text_thread_id, cx) {
+                        text_thread_ids.push(text_thread_id);
+                        operations
+                            .push(text_thread.read(cx).serialize_ops(&text_thread_version, cx));
                     }
                 }
             })?;
 
             let operations = futures::future::join_all(operations).await;
-            for (context_id, operations) in context_ids.into_iter().zip(operations) {
+            for (context_id, operations) in text_thread_ids.into_iter().zip(operations) {
                 for operation in operations {
                     client.send(proto::UpdateContext {
                         project_id,
@@ -751,8 +744,8 @@ impl ContextStore {
         .detach_and_log_err(cx);
     }
 
-    pub fn search(&self, query: String, cx: &App) -> Task<Vec<SavedContextMetadata>> {
-        let metadata = self.contexts_metadata.clone();
+    pub fn search(&self, query: String, cx: &App) -> Task<Vec<SavedTextThreadMetadata>> {
+        let metadata = self.text_threads_metadata.clone();
         let executor = cx.background_executor().clone();
         cx.background_spawn(async move {
             if query.is_empty() {
@@ -782,20 +775,16 @@ impl ContextStore {
         })
     }
 
-    pub fn host_contexts(&self) -> &[RemoteContextMetadata] {
-        &self.host_contexts
-    }
-
     fn reload(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
         let fs = self.fs.clone();
         cx.spawn(async move |this, cx| {
             if *ZED_STATELESS {
                 return Ok(());
             }
-            fs.create_dir(contexts_dir()).await?;
+            fs.create_dir(text_threads_dir()).await?;
 
-            let mut paths = fs.read_dir(contexts_dir()).await?;
-            let mut contexts = Vec::<SavedContextMetadata>::new();
+            let mut paths = fs.read_dir(text_threads_dir()).await?;
+            let mut contexts = Vec::<SavedTextThreadMetadata>::new();
             while let Some(path) = paths.next().await {
                 let path = path?;
                 if path.extension() != Some(OsStr::new("json")) {
@@ -821,7 +810,7 @@ impl ContextStore {
                         .lines()
                         .next()
                     {
-                        contexts.push(SavedContextMetadata {
+                        contexts.push(SavedTextThreadMetadata {
                             title: title.to_string().into(),
                             path: path.into(),
                             mtime: metadata.mtime.timestamp_for_user().into(),
@@ -829,10 +818,10 @@ impl ContextStore {
                     }
                 }
             }
-            contexts.sort_unstable_by_key(|context| Reverse(context.mtime));
+            contexts.sort_unstable_by_key(|text_thread| Reverse(text_thread.mtime));
 
             this.update(cx, |this, cx| {
-                this.contexts_metadata = contexts;
+                this.text_threads_metadata = contexts;
                 cx.notify();
             })
         })

crates/collab/Cargo.toml πŸ”—

@@ -73,7 +73,7 @@ uuid.workspace = true
 
 [dev-dependencies]
 agent_settings.workspace = true
-assistant_context.workspace = true
+assistant_text_thread.workspace = true
 assistant_slash_command.workspace = true
 async-trait.workspace = true
 audio.workspace = true

crates/collab/src/tests/integration_tests.rs πŸ”—

@@ -6,8 +6,8 @@ use crate::{
     },
 };
 use anyhow::{Result, anyhow};
-use assistant_context::ContextStore;
 use assistant_slash_command::SlashCommandWorkingSet;
+use assistant_text_thread::TextThreadStore;
 use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus, assert_hunks};
 use call::{ActiveCall, ParticipantLocation, Room, room};
 use client::{RECEIVE_TIMEOUT, User};
@@ -6877,9 +6877,9 @@ async fn test_context_collaboration_with_reconnect(
     });
 
     let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
-    let context_store_a = cx_a
+    let text_thread_store_a = cx_a
         .update(|cx| {
-            ContextStore::new(
+            TextThreadStore::new(
                 project_a.clone(),
                 prompt_builder.clone(),
                 Arc::new(SlashCommandWorkingSet::default()),
@@ -6888,9 +6888,9 @@ async fn test_context_collaboration_with_reconnect(
         })
         .await
         .unwrap();
-    let context_store_b = cx_b
+    let text_thread_store_b = cx_b
         .update(|cx| {
-            ContextStore::new(
+            TextThreadStore::new(
                 project_b.clone(),
                 prompt_builder.clone(),
                 Arc::new(SlashCommandWorkingSet::default()),
@@ -6901,60 +6901,60 @@ async fn test_context_collaboration_with_reconnect(
         .unwrap();
 
     // Client A creates a new chats.
-    let context_a = context_store_a.update(cx_a, |store, cx| store.create(cx));
+    let text_thread_a = text_thread_store_a.update(cx_a, |store, cx| store.create(cx));
     executor.run_until_parked();
 
     // Client B retrieves host's contexts and joins one.
-    let context_b = context_store_b
+    let text_thread_b = text_thread_store_b
         .update(cx_b, |store, cx| {
-            let host_contexts = store.host_contexts().to_vec();
-            assert_eq!(host_contexts.len(), 1);
-            store.open_remote_context(host_contexts[0].id.clone(), cx)
+            let host_text_threads = store.host_text_threads().collect::<Vec<_>>();
+            assert_eq!(host_text_threads.len(), 1);
+            store.open_remote(host_text_threads[0].id.clone(), cx)
         })
         .await
         .unwrap();
 
     // Host and guest make changes
-    context_a.update(cx_a, |context, cx| {
-        context.buffer().update(cx, |buffer, cx| {
+    text_thread_a.update(cx_a, |text_thread, cx| {
+        text_thread.buffer().update(cx, |buffer, cx| {
             buffer.edit([(0..0, "Host change\n")], None, cx)
         })
     });
-    context_b.update(cx_b, |context, cx| {
-        context.buffer().update(cx, |buffer, cx| {
+    text_thread_b.update(cx_b, |text_thread, cx| {
+        text_thread.buffer().update(cx, |buffer, cx| {
             buffer.edit([(0..0, "Guest change\n")], None, cx)
         })
     });
     executor.run_until_parked();
     assert_eq!(
-        context_a.read_with(cx_a, |context, cx| context.buffer().read(cx).text()),
+        text_thread_a.read_with(cx_a, |text_thread, cx| text_thread.buffer().read(cx).text()),
         "Guest change\nHost change\n"
     );
     assert_eq!(
-        context_b.read_with(cx_b, |context, cx| context.buffer().read(cx).text()),
+        text_thread_b.read_with(cx_b, |text_thread, cx| text_thread.buffer().read(cx).text()),
         "Guest change\nHost change\n"
     );
 
     // Disconnect client A and make some changes while disconnected.
     server.disconnect_client(client_a.peer_id().unwrap());
     server.forbid_connections();
-    context_a.update(cx_a, |context, cx| {
-        context.buffer().update(cx, |buffer, cx| {
+    text_thread_a.update(cx_a, |text_thread, cx| {
+        text_thread.buffer().update(cx, |buffer, cx| {
             buffer.edit([(0..0, "Host offline change\n")], None, cx)
         })
     });
-    context_b.update(cx_b, |context, cx| {
-        context.buffer().update(cx, |buffer, cx| {
+    text_thread_b.update(cx_b, |text_thread, cx| {
+        text_thread.buffer().update(cx, |buffer, cx| {
             buffer.edit([(0..0, "Guest offline change\n")], None, cx)
         })
     });
     executor.run_until_parked();
     assert_eq!(
-        context_a.read_with(cx_a, |context, cx| context.buffer().read(cx).text()),
+        text_thread_a.read_with(cx_a, |text_thread, cx| text_thread.buffer().read(cx).text()),
         "Host offline change\nGuest change\nHost change\n"
     );
     assert_eq!(
-        context_b.read_with(cx_b, |context, cx| context.buffer().read(cx).text()),
+        text_thread_b.read_with(cx_b, |text_thread, cx| text_thread.buffer().read(cx).text()),
         "Guest offline change\nGuest change\nHost change\n"
     );
 
@@ -6962,11 +6962,11 @@ async fn test_context_collaboration_with_reconnect(
     server.allow_connections();
     executor.advance_clock(RECEIVE_TIMEOUT);
     assert_eq!(
-        context_a.read_with(cx_a, |context, cx| context.buffer().read(cx).text()),
+        text_thread_a.read_with(cx_a, |text_thread, cx| text_thread.buffer().read(cx).text()),
         "Guest offline change\nHost offline change\nGuest change\nHost change\n"
     );
     assert_eq!(
-        context_b.read_with(cx_b, |context, cx| context.buffer().read(cx).text()),
+        text_thread_b.read_with(cx_b, |text_thread, cx| text_thread.buffer().read(cx).text()),
         "Guest offline change\nHost offline change\nGuest change\nHost change\n"
     );
 
@@ -6974,8 +6974,8 @@ async fn test_context_collaboration_with_reconnect(
     server.forbid_connections();
     server.disconnect_client(client_a.peer_id().unwrap());
     executor.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
-    context_b.read_with(cx_b, |context, cx| {
-        assert!(context.buffer().read(cx).read_only());
+    text_thread_b.read_with(cx_b, |text_thread, cx| {
+        assert!(text_thread.buffer().read(cx).read_only());
     });
 }
 

crates/collab/src/tests/test_server.rs πŸ”—

@@ -358,7 +358,7 @@ impl TestServer {
                 settings::KeymapFile::load_asset_allow_partial_failure(os_keymap, cx).unwrap(),
             );
             language_model::LanguageModelRegistry::test(cx);
-            assistant_context::init(client.clone(), cx);
+            assistant_text_thread::init(client.clone(), cx);
             agent_settings::init(cx);
         });
 

crates/paths/src/paths.rs πŸ”—

@@ -288,7 +288,7 @@ pub fn snippets_dir() -> &'static PathBuf {
 /// Returns the path to the contexts directory.
 ///
 /// This is where the saved contexts from the Assistant are stored.
-pub fn contexts_dir() -> &'static PathBuf {
+pub fn text_threads_dir() -> &'static PathBuf {
     static CONTEXTS_DIR: OnceLock<PathBuf> = OnceLock::new();
     CONTEXTS_DIR.get_or_init(|| {
         if cfg!(target_os = "macos") {