Detailed changes
@@ -53,6 +53,89 @@ dependencies = [
name = "agent"
version = "0.1.0"
dependencies = [
+ "agent_settings",
+ "anyhow",
+ "assistant_context_editor",
+ "assistant_tool",
+ "assistant_tools",
+ "chrono",
+ "client",
+ "collections",
+ "component",
+ "context_server",
+ "convert_case 0.8.0",
+ "feature_flags",
+ "fs",
+ "futures 0.3.31",
+ "git",
+ "gpui",
+ "heed",
+ "http_client",
+ "icons",
+ "indoc",
+ "itertools 0.14.0",
+ "language",
+ "language_model",
+ "log",
+ "paths",
+ "postage",
+ "pretty_assertions",
+ "project",
+ "prompt_store",
+ "proto",
+ "rand 0.8.5",
+ "ref-cast",
+ "rope",
+ "schemars",
+ "serde",
+ "serde_json",
+ "settings",
+ "smol",
+ "sqlez",
+ "telemetry",
+ "text",
+ "theme",
+ "thiserror 2.0.12",
+ "time",
+ "util",
+ "uuid",
+ "workspace",
+ "workspace-hack",
+ "zed_llm_client",
+ "zstd",
+]
+
+[[package]]
+name = "agent_settings"
+version = "0.1.0"
+dependencies = [
+ "anthropic",
+ "anyhow",
+ "collections",
+ "deepseek",
+ "fs",
+ "gpui",
+ "language_model",
+ "lmstudio",
+ "log",
+ "mistral",
+ "ollama",
+ "open_ai",
+ "paths",
+ "schemars",
+ "serde",
+ "serde_json",
+ "serde_json_lenient",
+ "settings",
+ "workspace-hack",
+ "zed_llm_client",
+]
+
+[[package]]
+name = "agent_ui"
+version = "0.1.0"
+dependencies = [
+ "agent",
"agent_settings",
"anyhow",
"assistant_context_editor",
@@ -67,7 +150,6 @@ dependencies = [
"collections",
"component",
"context_server",
- "convert_case 0.8.0",
"db",
"editor",
"extension",
@@ -77,9 +159,7 @@ dependencies = [
"fs",
"futures 0.3.31",
"fuzzy",
- "git",
"gpui",
- "heed",
"html_to_markdown",
"http_client",
"indexed_docs",
@@ -99,13 +179,11 @@ dependencies = [
"parking_lot",
"paths",
"picker",
- "postage",
"pretty_assertions",
"project",
"prompt_store",
"proto",
"rand 0.8.5",
- "ref-cast",
"release_channel",
"rope",
"rules_library",
@@ -116,7 +194,6 @@ dependencies = [
"serde_json_lenient",
"settings",
"smol",
- "sqlez",
"streaming_diff",
"telemetry",
"telemetry_events",
@@ -124,7 +201,6 @@ dependencies = [
"terminal_view",
"text",
"theme",
- "thiserror 2.0.12",
"time",
"time_format",
"ui",
@@ -136,33 +212,6 @@ dependencies = [
"workspace-hack",
"zed_actions",
"zed_llm_client",
- "zstd",
-]
-
-[[package]]
-name = "agent_settings"
-version = "0.1.0"
-dependencies = [
- "anthropic",
- "anyhow",
- "collections",
- "deepseek",
- "fs",
- "gpui",
- "language_model",
- "lmstudio",
- "log",
- "mistral",
- "ollama",
- "open_ai",
- "paths",
- "schemars",
- "serde",
- "serde_json",
- "serde_json_lenient",
- "settings",
- "workspace-hack",
- "zed_llm_client",
]
[[package]]
@@ -5062,6 +5111,7 @@ version = "0.1.0"
dependencies = [
"agent",
"agent_settings",
+ "agent_ui",
"anyhow",
"assistant_tool",
"assistant_tools",
@@ -19868,6 +19918,7 @@ dependencies = [
"activity_indicator",
"agent",
"agent_settings",
+ "agent_ui",
"anyhow",
"ashpd",
"askpass",
@@ -2,6 +2,7 @@
resolver = "2"
members = [
"crates/activity_indicator",
+ "crates/agent_ui",
"crates/agent",
"crates/agent_settings",
"crates/anthropic",
@@ -214,6 +215,7 @@ edition = "2024"
activity_indicator = { path = "crates/activity_indicator" }
agent = { path = "crates/agent" }
+agent_ui = { path = "crates/agent_ui" }
agent_settings = { path = "crates/agent_settings" }
ai = { path = "crates/ai" }
anthropic = { path = "crates/anthropic" }
@@ -22,93 +22,57 @@ test-support = [
agent_settings.workspace = true
anyhow.workspace = true
assistant_context_editor.workspace = true
-assistant_slash_command.workspace = true
-assistant_slash_commands.workspace = true
assistant_tool.workspace = true
-audio.workspace = true
-buffer_diff.workspace = true
chrono.workspace = true
client.workspace = true
collections.workspace = true
component.workspace = true
context_server.workspace = true
convert_case.workspace = true
-db.workspace = true
-editor.workspace = true
-extension.workspace = true
-extension_host.workspace = true
feature_flags.workspace = true
-file_icons.workspace = true
fs.workspace = true
futures.workspace = true
-fuzzy.workspace = true
git.workspace = true
gpui.workspace = true
heed.workspace = true
-html_to_markdown.workspace = true
+icons.workspace = true
indoc.workspace = true
http_client.workspace = true
-indexed_docs.workspace = true
-inventory.workspace = true
itertools.workspace = true
-jsonschema.workspace = true
language.workspace = true
language_model.workspace = true
log.workspace = true
-lsp.workspace = true
-markdown.workspace = true
-menu.workspace = true
-multi_buffer.workspace = true
-notifications.workspace = true
-ordered-float.workspace = true
-parking_lot.workspace = true
paths.workspace = true
-picker.workspace = true
postage.workspace = true
project.workspace = true
prompt_store.workspace = true
proto.workspace = true
ref-cast.workspace = true
-release_channel.workspace = true
rope.workspace = true
-rules_library.workspace = true
schemars.workspace = true
-search.workspace = true
serde.workspace = true
serde_json.workspace = true
-serde_json_lenient.workspace = true
settings.workspace = true
smol.workspace = true
sqlez.workspace = true
-streaming_diff.workspace = true
telemetry.workspace = true
-telemetry_events.workspace = true
-terminal.workspace = true
-terminal_view.workspace = true
text.workspace = true
theme.workspace = true
thiserror.workspace = true
time.workspace = true
-time_format.workspace = true
-ui.workspace = true
-urlencoding.workspace = true
util.workspace = true
uuid.workspace = true
-watch.workspace = true
workspace-hack.workspace = true
-workspace.workspace = true
-zed_actions.workspace = true
zed_llm_client.workspace = true
zstd.workspace = true
[dev-dependencies]
assistant_tools.workspace = true
-buffer_diff = { workspace = true, features = ["test-support"] }
-editor = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, "features" = ["test-support"] }
indoc.workspace = true
language = { workspace = true, "features" = ["test-support"] }
language_model = { workspace = true, "features" = ["test-support"] }
pretty_assertions.workspace = true
project = { workspace = true, features = ["test-support"] }
+workspace = { workspace = true, features = ["test-support"] }
rand.workspace = true
@@ -1,297 +1,20 @@
-mod active_thread;
-mod agent_configuration;
-mod agent_diff;
-mod agent_model_selector;
-mod agent_panel;
-mod agent_profile;
-mod buffer_codegen;
-mod context;
-mod context_picker;
-mod context_server_configuration;
-mod context_server_tool;
-mod context_store;
-mod context_strip;
-mod debug;
-mod history_store;
-mod inline_assistant;
-mod inline_prompt_editor;
-mod message_editor;
-mod profile_selector;
-mod slash_command_settings;
-mod terminal_codegen;
-mod terminal_inline_assistant;
-mod thread;
-mod thread_history;
-mod thread_store;
-mod tool_compatibility;
-mod tool_use;
-mod ui;
-
-use std::sync::Arc;
-
-use agent_settings::{AgentProfileId, AgentSettings, LanguageModelSelection};
-use assistant_slash_command::SlashCommandRegistry;
-use client::Client;
-use feature_flags::FeatureFlagAppExt as _;
-use fs::Fs;
-use gpui::{App, Entity, actions, impl_actions};
-use language::LanguageRegistry;
-use language_model::{
- ConfiguredModel, LanguageModel, LanguageModelId, LanguageModelProviderId, LanguageModelRegistry,
-};
-use prompt_store::PromptBuilder;
-use schemars::JsonSchema;
-use serde::Deserialize;
-use settings::{Settings as _, SettingsStore};
-use thread::ThreadId;
-
-pub use crate::active_thread::ActiveThread;
-use crate::agent_configuration::{ConfigureContextServerModal, ManageProfilesModal};
-pub use crate::agent_panel::{AgentPanel, ConcreteAssistantPanelDelegate};
-pub use crate::context::{ContextLoadResult, LoadedContext};
-pub use crate::inline_assistant::InlineAssistant;
-use crate::slash_command_settings::SlashCommandSettings;
-pub use crate::thread::{Message, MessageSegment, Thread, ThreadEvent};
-pub use crate::thread_store::{SerializedThread, TextThreadStore, ThreadStore};
-pub use agent_diff::{AgentDiffPane, AgentDiffToolbar};
+pub mod agent_profile;
+pub mod context;
+pub mod context_server_tool;
+pub mod context_store;
+pub mod history_store;
+pub mod thread;
+pub mod thread_store;
+pub mod tool_use;
+
+pub use context::{AgentContext, ContextId, ContextLoadResult};
pub use context_store::ContextStore;
-pub use ui::preview::{all_agent_previews, get_agent_preview};
-
-actions!(
- agent,
- [
- NewTextThread,
- ToggleContextPicker,
- ToggleNavigationMenu,
- ToggleOptionsMenu,
- DeleteRecentlyOpenThread,
- ToggleProfileSelector,
- RemoveAllContext,
- ExpandMessageEditor,
- OpenHistory,
- AddContextServer,
- RemoveSelectedThread,
- Chat,
- ChatWithFollow,
- CycleNextInlineAssist,
- CyclePreviousInlineAssist,
- FocusUp,
- FocusDown,
- FocusLeft,
- FocusRight,
- RemoveFocusedContext,
- AcceptSuggestedContext,
- OpenActiveThreadAsMarkdown,
- OpenAgentDiff,
- Keep,
- Reject,
- RejectAll,
- KeepAll,
- Follow,
- ResetTrialUpsell,
- ResetTrialEndUpsell,
- ContinueThread,
- ContinueWithBurnMode,
- ToggleBurnMode,
- ]
-);
-
-#[derive(Default, Clone, PartialEq, Deserialize, JsonSchema)]
-pub struct NewThread {
- #[serde(default)]
- from_thread_id: Option<ThreadId>,
-}
-
-#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema)]
-pub struct ManageProfiles {
- #[serde(default)]
- pub customize_tools: Option<AgentProfileId>,
-}
-
-impl ManageProfiles {
- pub fn customize_tools(profile_id: AgentProfileId) -> Self {
- Self {
- customize_tools: Some(profile_id),
- }
- }
-}
-
-impl_actions!(agent, [NewThread, ManageProfiles]);
-
-#[derive(Clone)]
-pub(crate) enum ModelUsageContext {
- Thread(Entity<Thread>),
- InlineAssistant,
-}
-
-impl ModelUsageContext {
- pub fn configured_model(&self, cx: &App) -> Option<ConfiguredModel> {
- match self {
- Self::Thread(thread) => thread.read(cx).configured_model(),
- Self::InlineAssistant => {
- LanguageModelRegistry::read_global(cx).inline_assistant_model()
- }
- }
- }
-
- pub fn language_model(&self, cx: &App) -> Option<Arc<dyn LanguageModel>> {
- self.configured_model(cx)
- .map(|configured_model| configured_model.model)
- }
-}
-
-/// Initializes the `agent` crate.
-pub fn init(
- fs: Arc<dyn Fs>,
- client: Arc<Client>,
- prompt_builder: Arc<PromptBuilder>,
- language_registry: Arc<LanguageRegistry>,
- is_eval: bool,
- cx: &mut App,
-) {
- AgentSettings::register(cx);
- SlashCommandSettings::register(cx);
+pub use thread::{
+ LastRestoreCheckpoint, Message, MessageCrease, MessageId, MessageSegment, Thread, ThreadError,
+ ThreadEvent, ThreadFeedback, ThreadId, ThreadSummary, TokenUsageRatio,
+};
+pub use thread_store::{SerializedThread, TextThreadStore, ThreadStore};
- assistant_context_editor::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
- // we're not running inside of the eval.
- init_language_model_settings(cx);
- }
- assistant_slash_command::init(cx);
+pub fn init(cx: &mut gpui::App) {
thread_store::init(cx);
- agent_panel::init(cx);
- context_server_configuration::init(language_registry.clone(), fs.clone(), cx);
-
- register_slash_commands(cx);
- inline_assistant::init(
- fs.clone(),
- prompt_builder.clone(),
- client.telemetry().clone(),
- cx,
- );
- terminal_inline_assistant::init(
- fs.clone(),
- prompt_builder.clone(),
- client.telemetry().clone(),
- cx,
- );
- indexed_docs::init(cx);
- cx.observe_new(move |workspace, window, cx| {
- ConfigureContextServerModal::register(workspace, language_registry.clone(), window, cx)
- })
- .detach();
- cx.observe_new(ManageProfilesModal::register).detach();
-}
-
-fn init_language_model_settings(cx: &mut App) {
- update_active_language_model_from_settings(cx);
-
- cx.observe_global::<SettingsStore>(update_active_language_model_from_settings)
- .detach();
- cx.subscribe(
- &LanguageModelRegistry::global(cx),
- |_, event: &language_model::Event, cx| match event {
- language_model::Event::ProviderStateChanged
- | language_model::Event::AddedProvider(_)
- | language_model::Event::RemovedProvider(_) => {
- update_active_language_model_from_settings(cx);
- }
- _ => {}
- },
- )
- .detach();
-}
-
-fn update_active_language_model_from_settings(cx: &mut App) {
- let settings = AgentSettings::get_global(cx);
-
- fn to_selected_model(selection: &LanguageModelSelection) -> language_model::SelectedModel {
- language_model::SelectedModel {
- provider: LanguageModelProviderId::from(selection.provider.0.clone()),
- model: LanguageModelId::from(selection.model.clone()),
- }
- }
-
- let default = to_selected_model(&settings.default_model);
- let inline_assistant = settings
- .inline_assistant_model
- .as_ref()
- .map(to_selected_model);
- let commit_message = settings
- .commit_message_model
- .as_ref()
- .map(to_selected_model);
- let thread_summary = settings
- .thread_summary_model
- .as_ref()
- .map(to_selected_model);
- let inline_alternatives = settings
- .inline_alternatives
- .iter()
- .map(to_selected_model)
- .collect::<Vec<_>>();
-
- LanguageModelRegistry::global(cx).update(cx, |registry, cx| {
- registry.select_default_model(Some(&default), cx);
- registry.select_inline_assistant_model(inline_assistant.as_ref(), cx);
- registry.select_commit_message_model(commit_message.as_ref(), cx);
- registry.select_thread_summary_model(thread_summary.as_ref(), cx);
- registry.select_inline_alternative_models(inline_alternatives, cx);
- });
-}
-
-fn register_slash_commands(cx: &mut App) {
- let slash_command_registry = SlashCommandRegistry::global(cx);
-
- slash_command_registry.register_command(assistant_slash_commands::FileSlashCommand, true);
- slash_command_registry.register_command(assistant_slash_commands::DeltaSlashCommand, true);
- slash_command_registry.register_command(assistant_slash_commands::OutlineSlashCommand, true);
- slash_command_registry.register_command(assistant_slash_commands::TabSlashCommand, true);
- slash_command_registry
- .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
- slash_command_registry.register_command(assistant_slash_commands::PromptSlashCommand, true);
- slash_command_registry.register_command(assistant_slash_commands::SelectionCommand, true);
- slash_command_registry.register_command(assistant_slash_commands::DefaultSlashCommand, false);
- slash_command_registry.register_command(assistant_slash_commands::NowSlashCommand, false);
- slash_command_registry
- .register_command(assistant_slash_commands::DiagnosticsSlashCommand, true);
- slash_command_registry.register_command(assistant_slash_commands::FetchSlashCommand, true);
-
- cx.observe_flag::<assistant_slash_commands::StreamingExampleSlashCommandFeatureFlag, _>({
- let slash_command_registry = slash_command_registry.clone();
- move |is_enabled, _cx| {
- if is_enabled {
- slash_command_registry.register_command(
- assistant_slash_commands::StreamingExampleSlashCommand,
- false,
- );
- }
- }
- })
- .detach();
-
- update_slash_commands_from_settings(cx);
- cx.observe_global::<SettingsStore>(update_slash_commands_from_settings)
- .detach();
-}
-
-fn update_slash_commands_from_settings(cx: &mut App) {
- let slash_command_registry = SlashCommandRegistry::global(cx);
- let settings = SlashCommandSettings::get_global(cx);
-
- if settings.docs.enabled {
- slash_command_registry.register_command(assistant_slash_commands::DocsSlashCommand, true);
- } else {
- slash_command_registry.unregister_command(assistant_slash_commands::DocsSlashCommand);
- }
-
- if settings.cargo_workspace.enabled {
- slash_command_registry
- .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
- } else {
- slash_command_registry
- .unregister_command(assistant_slash_commands::CargoWorkspaceSlashCommand);
- }
}
@@ -5,9 +5,8 @@ use assistant_tool::{Tool, ToolSource, ToolWorkingSet};
use collections::IndexMap;
use convert_case::{Case, Casing};
use fs::Fs;
-use gpui::{App, Entity};
+use gpui::{App, Entity, SharedString};
use settings::{Settings, update_settings_file};
-use ui::SharedString;
use util::ResultExt;
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -108,11 +107,11 @@ mod tests {
use agent_settings::ContextServerPreset;
use assistant_tool::ToolRegistry;
use collections::IndexMap;
+ use gpui::SharedString;
use gpui::{AppContext, TestAppContext};
use http_client::FakeHttpClient;
use project::Project;
use settings::{Settings, SettingsStore};
- use ui::SharedString;
use super::*;
@@ -302,7 +301,7 @@ mod tests {
unimplemented!()
}
- fn icon(&self) -> ui::IconName {
+ fn icon(&self) -> icons::IconName {
unimplemented!()
}
@@ -1,30 +1,25 @@
-use std::fmt::{self, Display, Formatter, Write as _};
-use std::hash::{Hash, Hasher};
-use std::path::PathBuf;
-use std::{ops::Range, path::Path, sync::Arc};
-
+use crate::thread::Thread;
use assistant_context_editor::AssistantContext;
use assistant_tool::outline;
-use collections::{HashMap, HashSet};
-use editor::display_map::CreaseId;
-use editor::{Addon, Editor};
+use collections::HashSet;
use futures::future;
use futures::{FutureExt, future::Shared};
-use gpui::{App, AppContext as _, Entity, SharedString, Subscription, Task};
+use gpui::{App, AppContext as _, ElementId, Entity, SharedString, Task};
+use icons::IconName;
use language::{Buffer, ParseStatus};
use language_model::{LanguageModelImage, LanguageModelRequestMessage, MessageContent};
use project::{Project, ProjectEntryId, ProjectPath, Worktree};
use prompt_store::{PromptStore, UserPromptId};
use ref_cast::RefCast;
use rope::Point;
+use std::fmt::{self, Display, Formatter, Write as _};
+use std::hash::{Hash, Hasher};
+use std::path::PathBuf;
+use std::{ops::Range, path::Path, sync::Arc};
use text::{Anchor, OffsetRangeExt as _};
-use ui::{Context, ElementId, IconName};
use util::markdown::MarkdownCodeBlock;
use util::{ResultExt as _, post_inc};
-use crate::context_store::{ContextStore, ContextStoreEvent};
-use crate::thread::Thread;
-
pub const RULES_ICON: IconName = IconName::Context;
pub enum ContextKind {
@@ -1117,69 +1112,6 @@ impl Hash for AgentContextKey {
}
}
-#[derive(Default)]
-pub struct ContextCreasesAddon {
- creases: HashMap<AgentContextKey, Vec<(CreaseId, SharedString)>>,
- _subscription: Option<Subscription>,
-}
-
-impl Addon for ContextCreasesAddon {
- fn to_any(&self) -> &dyn std::any::Any {
- self
- }
-
- fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
- Some(self)
- }
-}
-
-impl ContextCreasesAddon {
- pub fn new() -> Self {
- Self {
- creases: HashMap::default(),
- _subscription: None,
- }
- }
-
- pub fn add_creases(
- &mut self,
- context_store: &Entity<ContextStore>,
- key: AgentContextKey,
- creases: impl IntoIterator<Item = (CreaseId, SharedString)>,
- cx: &mut Context<Editor>,
- ) {
- self.creases.entry(key).or_default().extend(creases);
- self._subscription = Some(cx.subscribe(
- &context_store,
- |editor, _, event, cx| match event {
- ContextStoreEvent::ContextRemoved(key) => {
- let Some(this) = editor.addon_mut::<Self>() else {
- return;
- };
- let (crease_ids, replacement_texts): (Vec<_>, Vec<_>) = this
- .creases
- .remove(key)
- .unwrap_or_default()
- .into_iter()
- .unzip();
- let ranges = editor
- .remove_creases(crease_ids, cx)
- .into_iter()
- .map(|(_, range)| range)
- .collect::<Vec<_>>();
- editor.unfold_ranges(&ranges, false, false, cx);
- editor.edit(ranges.into_iter().zip(replacement_texts), cx);
- cx.notify();
- }
- },
- ))
- }
-
- pub fn into_inner(self) -> HashMap<AgentContextKey, Vec<(CreaseId, SharedString)>> {
- self.creases
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -4,9 +4,9 @@ use anyhow::{Result, anyhow, bail};
use assistant_tool::{ActionLog, Tool, ToolResult, ToolSource};
use context_server::{ContextServerId, types};
use gpui::{AnyWindowHandle, App, Entity, Task};
+use icons::IconName;
use language_model::{LanguageModel, LanguageModelRequest, LanguageModelToolSchemaFormat};
use project::{Project, context_server_store::ContextServerStore};
-use ui::IconName;
pub struct ContextServerTool {
store: Entity<ContextServerStore>,
@@ -1,7 +1,12 @@
-use std::ops::Range;
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
-
+use crate::{
+ context::{
+ AgentContextHandle, AgentContextKey, ContextId, ContextKind, DirectoryContextHandle,
+ FetchedUrlContext, FileContextHandle, ImageContext, RulesContextHandle,
+ SelectionContextHandle, SymbolContextHandle, TextThreadContextHandle, ThreadContextHandle,
+ },
+ thread::{MessageId, Thread, ThreadId},
+ thread_store::ThreadStore,
+};
use anyhow::{Context as _, Result, anyhow};
use assistant_context_editor::AssistantContext;
use collections::{HashSet, IndexSet};
@@ -9,20 +14,15 @@ use futures::{self, FutureExt};
use gpui::{App, Context, Entity, EventEmitter, Image, SharedString, Task, WeakEntity};
use language::{Buffer, File as _};
use language_model::LanguageModelImage;
-use project::image_store::is_image_file;
-use project::{Project, ProjectItem, ProjectPath, Symbol};
+use project::{Project, ProjectItem, ProjectPath, Symbol, image_store::is_image_file};
use prompt_store::UserPromptId;
use ref_cast::RefCast as _;
-use text::{Anchor, OffsetRangeExt};
-
-use crate::ThreadStore;
-use crate::context::{
- AgentContextHandle, AgentContextKey, ContextId, DirectoryContextHandle, FetchedUrlContext,
- FileContextHandle, ImageContext, RulesContextHandle, SelectionContextHandle,
- SymbolContextHandle, TextThreadContextHandle, ThreadContextHandle,
+use std::{
+ ops::Range,
+ path::{Path, PathBuf},
+ sync::Arc,
};
-use crate::context_strip::SuggestedContext;
-use crate::thread::{MessageId, Thread, ThreadId};
+use text::{Anchor, OffsetRangeExt};
pub struct ContextStore {
project: WeakEntity<Project>,
@@ -561,6 +561,49 @@ impl ContextStore {
}
}
+#[derive(Clone)]
+pub enum SuggestedContext {
+ File {
+ name: SharedString,
+ icon_path: Option<SharedString>,
+ buffer: WeakEntity<Buffer>,
+ },
+ Thread {
+ name: SharedString,
+ thread: WeakEntity<Thread>,
+ },
+ TextThread {
+ name: SharedString,
+ context: WeakEntity<AssistantContext>,
+ },
+}
+
+impl SuggestedContext {
+ pub fn name(&self) -> &SharedString {
+ match self {
+ Self::File { name, .. } => name,
+ Self::Thread { name, .. } => name,
+ Self::TextThread { name, .. } => name,
+ }
+ }
+
+ pub fn icon_path(&self) -> Option<SharedString> {
+ match self {
+ Self::File { icon_path, .. } => icon_path.clone(),
+ Self::Thread { .. } => None,
+ Self::TextThread { .. } => None,
+ }
+ }
+
+ pub fn kind(&self) -> ContextKind {
+ match self {
+ Self::File { .. } => ContextKind::File,
+ Self::Thread { .. } => ContextKind::Thread,
+ Self::TextThread { .. } => ContextKind::TextThread,
+ }
+ }
+}
+
pub enum FileInclusion {
Direct,
InDirectory { full_path: PathBuf },
@@ -1,21 +1,17 @@
-use std::{collections::VecDeque, path::Path, sync::Arc};
-
+use crate::{
+ ThreadId,
+ thread_store::{SerializedThreadMetadata, ThreadStore},
+};
use anyhow::{Context as _, Result};
use assistant_context_editor::SavedContextMetadata;
use chrono::{DateTime, Utc};
-use gpui::{AsyncApp, Entity, SharedString, Task, prelude::*};
+use gpui::{App, AsyncApp, Entity, SharedString, Task, prelude::*};
use itertools::Itertools;
use paths::contexts_dir;
use serde::{Deserialize, Serialize};
-use std::time::Duration;
-use ui::App;
+use std::{collections::VecDeque, path::Path, sync::Arc, time::Duration};
use util::ResultExt as _;
-use crate::{
- thread::ThreadId,
- thread_store::{SerializedThreadMetadata, ThreadStore},
-};
-
const MAX_RECENTLY_OPENED_ENTRIES: usize = 6;
const NAVIGATION_HISTORY_PATH: &str = "agent-navigation-history.json";
const SAVE_RECENTLY_OPENED_ENTRIES_DEBOUNCE: Duration = Duration::from_millis(50);
@@ -1,22 +1,25 @@
-use std::io::Write;
-use std::ops::Range;
-use std::sync::Arc;
-use std::time::Instant;
-
+use crate::{
+ agent_profile::AgentProfile,
+ context::{AgentContext, AgentContextHandle, ContextLoadResult, LoadedContext},
+ thread_store::{
+ SerializedCrease, SerializedLanguageModel, SerializedMessage, SerializedMessageSegment,
+ SerializedThread, SerializedToolResult, SerializedToolUse, SharedProjectContext,
+ ThreadStore,
+ },
+ tool_use::{PendingToolUse, ToolUse, ToolUseMetadata, ToolUseState},
+};
use agent_settings::{AgentProfileId, AgentSettings, CompletionMode};
use anyhow::{Result, anyhow};
use assistant_tool::{ActionLog, AnyToolCard, Tool, ToolWorkingSet};
use chrono::{DateTime, Utc};
use client::{ModelRequestUsage, RequestUsage};
use collections::{HashMap, HashSet};
-use editor::display_map::CreaseMetadata;
use feature_flags::{self, FeatureFlagAppExt};
-use futures::future::Shared;
-use futures::{FutureExt, StreamExt as _};
+use futures::{FutureExt, StreamExt as _, future::Shared};
use git::repository::DiffType;
use gpui::{
AnyWindowHandle, App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Task,
- WeakEntity,
+ WeakEntity, Window,
};
use language_model::{
ConfiguredModel, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
@@ -27,29 +30,21 @@ use language_model::{
TokenUsage,
};
use postage::stream::Stream as _;
-use project::Project;
-use project::git_store::{GitStore, GitStoreCheckpoint, RepositoryState};
+use project::{
+ Project,
+ git_store::{GitStore, GitStoreCheckpoint, RepositoryState},
+};
use prompt_store::{ModelContext, PromptBuilder};
use proto::Plan;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::Settings;
+use std::{io::Write, ops::Range, sync::Arc, time::Instant};
use thiserror::Error;
-use ui::Window;
use util::{ResultExt as _, post_inc};
-
use uuid::Uuid;
use zed_llm_client::{CompletionIntent, CompletionRequestStatus, UsageLimit};
-use crate::ThreadStore;
-use crate::agent_profile::AgentProfile;
-use crate::context::{AgentContext, AgentContextHandle, ContextLoadResult, LoadedContext};
-use crate::thread_store::{
- SerializedCrease, SerializedLanguageModel, SerializedMessage, SerializedMessageSegment,
- SerializedThread, SerializedToolResult, SerializedToolUse, SharedProjectContext,
-};
-use crate::tool_use::{PendingToolUse, ToolUse, ToolUseMetadata, ToolUseState};
-
#[derive(
Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize, JsonSchema,
)]
@@ -98,13 +93,18 @@ impl MessageId {
fn post_inc(&mut self) -> Self {
Self(post_inc(&mut self.0))
}
+
+ pub fn as_usize(&self) -> usize {
+ self.0
+ }
}
/// Stored information that can be used to resurrect a context crease when creating an editor for a past message.
#[derive(Clone, Debug)]
pub struct MessageCrease {
pub range: Range<usize>,
- pub metadata: CreaseMetadata,
+ pub icon_path: SharedString,
+ pub label: SharedString,
/// None for a deserialized message, Some otherwise.
pub context: Option<AgentContextHandle>,
}
@@ -540,10 +540,8 @@ impl Thread {
.into_iter()
.map(|crease| MessageCrease {
range: crease.start..crease.end,
- metadata: CreaseMetadata {
- icon_path: crease.icon_path,
- label: crease.label,
- },
+ icon_path: crease.icon_path,
+ label: crease.label,
context: None,
})
.collect(),
@@ -1170,8 +1168,8 @@ impl Thread {
.map(|crease| SerializedCrease {
start: crease.range.start,
end: crease.range.end,
- icon_path: crease.metadata.icon_path.clone(),
- label: crease.metadata.label.clone(),
+ icon_path: crease.icon_path.clone(),
+ label: crease.label.clone(),
})
.collect(),
is_hidden: message.is_hidden,
@@ -2997,11 +2995,13 @@ fn resolve_tool_name_conflicts(tools: &[Arc<dyn Tool>]) -> Vec<(String, Arc<dyn
#[cfg(test)]
mod tests {
use super::*;
- use crate::{ThreadStore, context::load_context, context_store::ContextStore, thread_store};
+ use crate::{
+ context::load_context, context_store::ContextStore, thread_store, thread_store::ThreadStore,
+ };
use agent_settings::{AgentProfileId, AgentSettings, LanguageModelParameters};
use assistant_tool::ToolRegistry;
- use editor::EditorSettings;
use gpui::TestAppContext;
+ use icons::IconName;
use language_model::fake_provider::{FakeLanguageModel, FakeLanguageModelProvider};
use project::{FakeFs, Project};
use prompt_store::PromptBuilder;
@@ -3009,7 +3009,6 @@ mod tests {
use settings::{Settings, SettingsStore};
use std::sync::Arc;
use theme::ThemeSettings;
- use ui::IconName;
use util::path;
use workspace::Workspace;
@@ -3837,7 +3836,6 @@ fn main() {{
workspace::init_settings(cx);
language_model::init_settings(cx);
ThemeSettings::register(cx);
- EditorSettings::register(cx);
ToolRegistry::default_global(cx);
});
}
@@ -1,22 +1,25 @@
-use std::cell::{Ref, RefCell};
-use std::path::{Path, PathBuf};
-use std::rc::Rc;
-use std::sync::{Arc, Mutex};
-
+use crate::{
+ context_server_tool::ContextServerTool,
+ thread::{
+ DetailedSummaryState, ExceededWindowError, MessageId, ProjectSnapshot, Thread, ThreadId,
+ },
+};
use agent_settings::{AgentProfileId, CompletionMode};
use anyhow::{Context as _, Result, anyhow};
use assistant_tool::{ToolId, ToolWorkingSet};
use chrono::{DateTime, Utc};
use collections::HashMap;
use context_server::ContextServerId;
-use futures::channel::{mpsc, oneshot};
-use futures::future::{self, BoxFuture, Shared};
-use futures::{FutureExt as _, StreamExt as _};
+use futures::{
+ FutureExt as _, StreamExt as _,
+ channel::{mpsc, oneshot},
+ future::{self, BoxFuture, Shared},
+};
use gpui::{
App, BackgroundExecutor, Context, Entity, EventEmitter, Global, ReadGlobal, SharedString,
- Subscription, Task, prelude::*,
+ Subscription, Task, Window, prelude::*,
};
-
+use indoc::indoc;
use language_model::{LanguageModelToolResultContent, LanguageModelToolUseId, Role, TokenUsage};
use project::context_server_store::{ContextServerStatus, ContextServerStore};
use project::{Project, ProjectItem, ProjectPath, Worktree};
@@ -25,19 +28,18 @@ use prompt_store::{
UserRulesContext, WorktreeContext,
};
use serde::{Deserialize, Serialize};
-use ui::Window;
-use util::ResultExt as _;
-
-use crate::context_server_tool::ContextServerTool;
-use crate::thread::{
- DetailedSummaryState, ExceededWindowError, MessageId, ProjectSnapshot, Thread, ThreadId,
-};
-use indoc::indoc;
use sqlez::{
bindable::{Bind, Column},
connection::Connection,
statement::Statement,
};
+use std::{
+ cell::{Ref, RefCell},
+ path::{Path, PathBuf},
+ rc::Rc,
+ sync::{Arc, Mutex},
+};
+use util::ResultExt as _;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataType {
@@ -1,24 +1,23 @@
-use std::sync::Arc;
-
+use crate::{
+ thread::{MessageId, PromptId, ThreadId},
+ thread_store::SerializedMessage,
+};
use anyhow::Result;
use assistant_tool::{
AnyToolCard, Tool, ToolResultContent, ToolResultOutput, ToolUseStatus, ToolWorkingSet,
};
use collections::HashMap;
-use futures::FutureExt as _;
-use futures::future::Shared;
-use gpui::{App, Entity, SharedString, Task};
+use futures::{FutureExt as _, future::Shared};
+use gpui::{App, Entity, SharedString, Task, Window};
+use icons::IconName;
use language_model::{
ConfiguredModel, LanguageModel, LanguageModelRequest, LanguageModelToolResult,
LanguageModelToolResultContent, LanguageModelToolUse, LanguageModelToolUseId, Role,
};
use project::Project;
-use ui::{IconName, Window};
+use std::sync::Arc;
use util::truncate_lines_to_byte_limit;
-use crate::thread::{MessageId, PromptId, ThreadId};
-use crate::thread_store::SerializedMessage;
-
#[derive(Debug)]
pub struct ToolUse {
pub id: LanguageModelToolUseId,
@@ -26,7 +25,7 @@ pub struct ToolUse {
pub ui_text: SharedString,
pub status: ToolUseStatus,
pub input: serde_json::Value,
- pub icon: ui::IconName,
+ pub icon: icons::IconName,
pub needs_confirmation: bool,
}
@@ -0,0 +1,107 @@
+[package]
+name = "agent_ui"
+version = "0.1.0"
+edition.workspace = true
+publish.workspace = true
+license = "GPL-3.0-or-later"
+
+[lints]
+workspace = true
+
+[lib]
+path = "src/agent_ui.rs"
+doctest = false
+
+[features]
+test-support = [
+ "gpui/test-support",
+ "language/test-support",
+]
+
+[dependencies]
+agent.workspace = true
+agent_settings.workspace = true
+anyhow.workspace = true
+assistant_context_editor.workspace = true
+assistant_slash_command.workspace = true
+assistant_slash_commands.workspace = true
+assistant_tool.workspace = true
+audio.workspace = true
+buffer_diff.workspace = true
+chrono.workspace = true
+client.workspace = true
+collections.workspace = true
+component.workspace = true
+context_server.workspace = true
+db.workspace = true
+editor.workspace = true
+extension.workspace = true
+extension_host.workspace = true
+feature_flags.workspace = true
+file_icons.workspace = true
+fs.workspace = true
+futures.workspace = true
+fuzzy.workspace = true
+gpui.workspace = true
+html_to_markdown.workspace = true
+indoc.workspace = true
+http_client.workspace = true
+indexed_docs.workspace = true
+inventory.workspace = true
+itertools.workspace = true
+jsonschema.workspace = true
+language.workspace = true
+language_model.workspace = true
+log.workspace = true
+lsp.workspace = true
+markdown.workspace = true
+menu.workspace = true
+multi_buffer.workspace = true
+notifications.workspace = true
+ordered-float.workspace = true
+parking_lot.workspace = true
+paths.workspace = true
+picker.workspace = true
+project.workspace = true
+prompt_store.workspace = true
+proto.workspace = true
+release_channel.workspace = true
+rope.workspace = true
+rules_library.workspace = true
+schemars.workspace = true
+search.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+serde_json_lenient.workspace = true
+settings.workspace = true
+smol.workspace = true
+streaming_diff.workspace = true
+telemetry.workspace = true
+telemetry_events.workspace = true
+terminal.workspace = true
+terminal_view.workspace = true
+text.workspace = true
+theme.workspace = true
+time.workspace = true
+time_format.workspace = true
+ui.workspace = true
+urlencoding.workspace = true
+util.workspace = true
+uuid.workspace = true
+watch.workspace = true
+workspace-hack.workspace = true
+workspace.workspace = true
+zed_actions.workspace = true
+zed_llm_client.workspace = true
+
+[dev-dependencies]
+assistant_tools.workspace = true
+buffer_diff = { workspace = true, features = ["test-support"] }
+editor = { workspace = true, features = ["test-support"] }
+gpui = { workspace = true, "features" = ["test-support"] }
+indoc.workspace = true
+language = { workspace = true, "features" = ["test-support"] }
+language_model = { workspace = true, "features" = ["test-support"] }
+pretty_assertions.workspace = true
+project = { workspace = true, features = ["test-support"] }
+rand.workspace = true
@@ -0,0 +1 @@
+../../LICENSE-GPL
@@ -1,18 +1,17 @@
-use crate::context::{AgentContextHandle, RULES_ICON};
use crate::context_picker::{ContextPicker, MentionLink};
-use crate::context_store::ContextStore;
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
use crate::message_editor::{extract_message_creases, insert_message_creases};
-use crate::thread::{
- LastRestoreCheckpoint, MessageCrease, MessageId, MessageSegment, Thread, ThreadError,
- ThreadEvent, ThreadFeedback, ThreadSummary,
-};
-use crate::thread_store::{RulesLoadingError, TextThreadStore, ThreadStore};
-use crate::tool_use::{PendingToolUseStatus, ToolUse};
use crate::ui::{
AddedContext, AgentNotification, AgentNotificationEvent, AnimatedLabel, ContextPill,
};
use crate::{AgentPanel, ModelUsageContext};
+use agent::{
+ ContextStore, LastRestoreCheckpoint, MessageCrease, MessageId, MessageSegment, TextThreadStore,
+ Thread, ThreadError, ThreadEvent, ThreadFeedback, ThreadStore, ThreadSummary,
+ context::{self, AgentContextHandle, RULES_ICON},
+ thread_store::RulesLoadingError,
+ tool_use::{PendingToolUseStatus, ToolUse},
+};
use agent_settings::{AgentSettings, NotifyWhenAgentWaiting};
use anyhow::Context as _;
use assistant_tool::ToolUseStatus;
@@ -1583,8 +1582,7 @@ impl ActiveThread {
let git_store = project.read(cx).git_store().clone();
let checkpoint = git_store.update(cx, |git_store, cx| git_store.checkpoint(cx));
- let load_context_task =
- crate::context::load_context(new_context, &project, &prompt_store, cx);
+ let load_context_task = context::load_context(new_context, &project, &prompt_store, cx);
self._load_edited_message_context_task =
Some(cx.spawn_in(window, async move |this, cx| {
let (context, checkpoint) =
@@ -1737,7 +1735,7 @@ impl ActiveThread {
telemetry::event!(
"Assistant Thread Feedback Comments",
thread_id,
- message_id = message_id.0,
+ message_id = message_id.as_usize(),
message_content,
comments = comments_value
);
@@ -3723,8 +3721,10 @@ fn open_editor_at_position(
#[cfg(test)]
mod tests {
+ use super::*;
+ use agent::{MessageSegment, context::ContextLoadResult, thread_store};
use assistant_tool::{ToolRegistry, ToolWorkingSet};
- use editor::{EditorSettings, display_map::CreaseMetadata};
+ use editor::EditorSettings;
use fs::FakeFs;
use gpui::{AppContext, TestAppContext, VisualTestContext};
use language_model::{
@@ -3738,10 +3738,6 @@ mod tests {
use util::path;
use workspace::CollaboratorId;
- use crate::{ContextLoadResult, thread::MessageSegment, thread_store};
-
- use super::*;
-
#[gpui::test]
async fn test_agent_is_unfollowed_after_cancelling_completion(cx: &mut TestAppContext) {
init_test_settings(cx);
@@ -3813,10 +3809,8 @@ mod tests {
let creases = vec![MessageCrease {
range: 14..22,
- metadata: CreaseMetadata {
- icon_path: "icon".into(),
- label: "foo.txt".into(),
- },
+ icon_path: "icon".into(),
+ label: "foo.txt".into(),
context: None,
}];
@@ -15,8 +15,8 @@ use workspace::{ModalView, Workspace};
use crate::agent_configuration::manage_profiles_modal::profile_modal_header::ProfileModalHeader;
use crate::agent_configuration::tool_picker::{ToolPicker, ToolPickerDelegate};
-use crate::agent_profile::AgentProfile;
use crate::{AgentPanel, ManageProfiles};
+use agent::agent_profile::AgentProfile;
use super::tool_picker::ToolPickerMode;
@@ -1,4 +1,5 @@
-use crate::{Keep, KeepAll, OpenAgentDiff, Reject, RejectAll, Thread, ThreadEvent};
+use crate::{Keep, KeepAll, OpenAgentDiff, Reject, RejectAll};
+use agent::{Thread, ThreadEvent};
use agent_settings::AgentSettings;
use anyhow::Result;
use buffer_diff::DiffHunkStatus;
@@ -1748,7 +1749,8 @@ impl editor::Addon for EditorAgentDiffAddon {
#[cfg(test)]
mod tests {
use super::*;
- use crate::{Keep, ThreadStore, thread_store};
+ use crate::Keep;
+ use agent::thread_store::{self, ThreadStore};
use agent_settings::AgentSettings;
use assistant_tool::ToolWorkingSet;
use editor::EditorSettings;
@@ -45,30 +45,34 @@ use ui::{
PopoverMenuHandle, ProgressBar, Tab, Tooltip, Vector, VectorName, prelude::*,
};
use util::ResultExt as _;
-use workspace::dock::{DockPosition, Panel, PanelEvent};
use workspace::{
CollaboratorId, DraggedSelection, DraggedTab, ToggleZoom, ToolbarItemView, Workspace,
+ dock::{DockPosition, Panel, PanelEvent},
+};
+use zed_actions::{
+ DecreaseBufferFontSize, IncreaseBufferFontSize, ResetBufferFontSize,
+ agent::{OpenConfiguration, OpenOnboardingModal, ResetOnboarding},
+ assistant::{OpenRulesLibrary, ToggleFocus},
};
-use zed_actions::agent::{OpenConfiguration, OpenOnboardingModal, ResetOnboarding};
-use zed_actions::assistant::{OpenRulesLibrary, ToggleFocus};
-use zed_actions::{DecreaseBufferFontSize, IncreaseBufferFontSize, ResetBufferFontSize};
use zed_llm_client::{CompletionIntent, UsageLimit};
-use crate::active_thread::{self, ActiveThread, ActiveThreadEvent};
-use crate::agent_configuration::{AgentConfiguration, AssistantConfigurationEvent};
-use crate::agent_diff::AgentDiff;
-use crate::history_store::{HistoryEntryId, HistoryStore};
-use crate::message_editor::{MessageEditor, MessageEditorEvent};
-use crate::thread::{Thread, ThreadError, ThreadId, ThreadSummary, TokenUsageRatio};
-use crate::thread_history::{HistoryEntryElement, ThreadHistory};
-use crate::thread_store::ThreadStore;
-use crate::ui::AgentOnboardingModal;
use crate::{
- AddContextServer, AgentDiffPane, ContextStore, ContinueThread, ContinueWithBurnMode,
+ AddContextServer, AgentDiffPane, ContinueThread, ContinueWithBurnMode,
DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread,
NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell,
- ResetTrialUpsell, TextThreadStore, ThreadEvent, ToggleBurnMode, ToggleContextPicker,
- ToggleNavigationMenu, ToggleOptionsMenu,
+ ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu, ToggleOptionsMenu,
+ active_thread::{self, ActiveThread, ActiveThreadEvent},
+ agent_configuration::{AgentConfiguration, AssistantConfigurationEvent},
+ agent_diff::AgentDiff,
+ message_editor::{MessageEditor, MessageEditorEvent},
+ thread_history::{HistoryEntryElement, ThreadHistory},
+ ui::AgentOnboardingModal,
+};
+use agent::{
+ Thread, ThreadError, ThreadEvent, ThreadId, ThreadSummary, TokenUsageRatio,
+ context_store::ContextStore,
+ history_store::{HistoryEntryId, HistoryStore},
+ thread_store::{TextThreadStore, ThreadStore},
};
const AGENT_PANEL_KEY: &str = "agent_panel";
@@ -369,7 +373,7 @@ pub struct AgentPanel {
_default_model_subscription: Subscription,
context_store: Entity<TextThreadStore>,
prompt_store: Option<Entity<PromptStore>>,
- inline_assist_context_store: Entity<crate::context_store::ContextStore>,
+ inline_assist_context_store: Entity<ContextStore>,
configuration: Option<Entity<AgentConfiguration>>,
configuration_subscription: Option<Subscription>,
local_timezone: UtcOffset,
@@ -490,18 +494,10 @@ impl AgentPanel {
let workspace = workspace.weak_handle();
let weak_self = cx.entity().downgrade();
- let message_editor_context_store = cx.new(|_cx| {
- crate::context_store::ContextStore::new(
- project.downgrade(),
- Some(thread_store.downgrade()),
- )
- });
- let inline_assist_context_store = cx.new(|_cx| {
- crate::context_store::ContextStore::new(
- project.downgrade(),
- Some(thread_store.downgrade()),
- )
- });
+ let message_editor_context_store =
+ cx.new(|_cx| ContextStore::new(project.downgrade(), Some(thread_store.downgrade())));
+ let inline_assist_context_store =
+ cx.new(|_cx| ContextStore::new(project.downgrade(), Some(thread_store.downgrade())));
let message_editor = cx.new(|cx| {
MessageEditor::new(
@@ -708,9 +704,7 @@ impl AgentPanel {
&self.prompt_store
}
- pub(crate) fn inline_assist_context_store(
- &self,
- ) -> &Entity<crate::context_store::ContextStore> {
+ pub(crate) fn inline_assist_context_store(&self) -> &Entity<ContextStore> {
&self.inline_assist_context_store
}
@@ -742,7 +736,7 @@ impl AgentPanel {
self.set_active_view(thread_view, window, cx);
let context_store = cx.new(|_cx| {
- crate::context_store::ContextStore::new(
+ ContextStore::new(
self.project.downgrade(),
Some(self.thread_store.downgrade()),
)
@@ -990,7 +984,7 @@ impl AgentPanel {
let thread_view = ActiveView::thread(thread.clone(), window, cx);
self.set_active_view(thread_view, window, cx);
let context_store = cx.new(|_cx| {
- crate::context_store::ContextStore::new(
+ ContextStore::new(
self.project.downgrade(),
Some(self.thread_store.downgrade()),
)
@@ -0,0 +1,285 @@
+mod active_thread;
+mod agent_configuration;
+mod agent_diff;
+mod agent_model_selector;
+mod agent_panel;
+mod buffer_codegen;
+mod context_picker;
+mod context_server_configuration;
+mod context_strip;
+mod debug;
+mod inline_assistant;
+mod inline_prompt_editor;
+mod message_editor;
+mod profile_selector;
+mod slash_command_settings;
+mod terminal_codegen;
+mod terminal_inline_assistant;
+mod thread_history;
+mod tool_compatibility;
+mod ui;
+
+use std::sync::Arc;
+
+use agent::{Thread, ThreadId};
+use agent_settings::{AgentProfileId, AgentSettings, LanguageModelSelection};
+use assistant_slash_command::SlashCommandRegistry;
+use client::Client;
+use feature_flags::FeatureFlagAppExt as _;
+use fs::Fs;
+use gpui::{App, Entity, actions, impl_actions};
+use language::LanguageRegistry;
+use language_model::{
+ ConfiguredModel, LanguageModel, LanguageModelId, LanguageModelProviderId, LanguageModelRegistry,
+};
+use prompt_store::PromptBuilder;
+use schemars::JsonSchema;
+use serde::Deserialize;
+use settings::{Settings as _, SettingsStore};
+
+pub use crate::active_thread::ActiveThread;
+use crate::agent_configuration::{ConfigureContextServerModal, ManageProfilesModal};
+pub use crate::agent_panel::{AgentPanel, ConcreteAssistantPanelDelegate};
+pub use crate::inline_assistant::InlineAssistant;
+use crate::slash_command_settings::SlashCommandSettings;
+pub use agent_diff::{AgentDiffPane, AgentDiffToolbar};
+pub use ui::preview::{all_agent_previews, get_agent_preview};
+
+actions!(
+ agent,
+ [
+ NewTextThread,
+ ToggleContextPicker,
+ ToggleNavigationMenu,
+ ToggleOptionsMenu,
+ DeleteRecentlyOpenThread,
+ ToggleProfileSelector,
+ RemoveAllContext,
+ ExpandMessageEditor,
+ OpenHistory,
+ AddContextServer,
+ RemoveSelectedThread,
+ Chat,
+ ChatWithFollow,
+ CycleNextInlineAssist,
+ CyclePreviousInlineAssist,
+ FocusUp,
+ FocusDown,
+ FocusLeft,
+ FocusRight,
+ RemoveFocusedContext,
+ AcceptSuggestedContext,
+ OpenActiveThreadAsMarkdown,
+ OpenAgentDiff,
+ Keep,
+ Reject,
+ RejectAll,
+ KeepAll,
+ Follow,
+ ResetTrialUpsell,
+ ResetTrialEndUpsell,
+ ContinueThread,
+ ContinueWithBurnMode,
+ ToggleBurnMode,
+ ]
+);
+
+#[derive(Default, Clone, PartialEq, Deserialize, JsonSchema)]
+pub struct NewThread {
+ #[serde(default)]
+ from_thread_id: Option<ThreadId>,
+}
+
+#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema)]
+pub struct ManageProfiles {
+ #[serde(default)]
+ pub customize_tools: Option<AgentProfileId>,
+}
+
+impl ManageProfiles {
+ pub fn customize_tools(profile_id: AgentProfileId) -> Self {
+ Self {
+ customize_tools: Some(profile_id),
+ }
+ }
+}
+
+impl_actions!(agent, [NewThread, ManageProfiles]);
+
+#[derive(Clone)]
+pub(crate) enum ModelUsageContext {
+ Thread(Entity<Thread>),
+ InlineAssistant,
+}
+
+impl ModelUsageContext {
+ pub fn configured_model(&self, cx: &App) -> Option<ConfiguredModel> {
+ match self {
+ Self::Thread(thread) => thread.read(cx).configured_model(),
+ Self::InlineAssistant => {
+ LanguageModelRegistry::read_global(cx).inline_assistant_model()
+ }
+ }
+ }
+
+ pub fn language_model(&self, cx: &App) -> Option<Arc<dyn LanguageModel>> {
+ self.configured_model(cx)
+ .map(|configured_model| configured_model.model)
+ }
+}
+
+/// Initializes the `agent` crate.
+pub fn init(
+ fs: Arc<dyn Fs>,
+ client: Arc<Client>,
+ prompt_builder: Arc<PromptBuilder>,
+ language_registry: Arc<LanguageRegistry>,
+ is_eval: bool,
+ cx: &mut App,
+) {
+ AgentSettings::register(cx);
+ SlashCommandSettings::register(cx);
+
+ assistant_context_editor::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
+ // we're not running inside of the eval.
+ init_language_model_settings(cx);
+ }
+ assistant_slash_command::init(cx);
+ agent::init(cx);
+ agent_panel::init(cx);
+ context_server_configuration::init(language_registry.clone(), fs.clone(), cx);
+
+ register_slash_commands(cx);
+ inline_assistant::init(
+ fs.clone(),
+ prompt_builder.clone(),
+ client.telemetry().clone(),
+ cx,
+ );
+ terminal_inline_assistant::init(
+ fs.clone(),
+ prompt_builder.clone(),
+ client.telemetry().clone(),
+ cx,
+ );
+ indexed_docs::init(cx);
+ cx.observe_new(move |workspace, window, cx| {
+ ConfigureContextServerModal::register(workspace, language_registry.clone(), window, cx)
+ })
+ .detach();
+ cx.observe_new(ManageProfilesModal::register).detach();
+}
+
+fn init_language_model_settings(cx: &mut App) {
+ update_active_language_model_from_settings(cx);
+
+ cx.observe_global::<SettingsStore>(update_active_language_model_from_settings)
+ .detach();
+ cx.subscribe(
+ &LanguageModelRegistry::global(cx),
+ |_, event: &language_model::Event, cx| match event {
+ language_model::Event::ProviderStateChanged
+ | language_model::Event::AddedProvider(_)
+ | language_model::Event::RemovedProvider(_) => {
+ update_active_language_model_from_settings(cx);
+ }
+ _ => {}
+ },
+ )
+ .detach();
+}
+
+fn update_active_language_model_from_settings(cx: &mut App) {
+ let settings = AgentSettings::get_global(cx);
+
+ fn to_selected_model(selection: &LanguageModelSelection) -> language_model::SelectedModel {
+ language_model::SelectedModel {
+ provider: LanguageModelProviderId::from(selection.provider.0.clone()),
+ model: LanguageModelId::from(selection.model.clone()),
+ }
+ }
+
+ let default = to_selected_model(&settings.default_model);
+ let inline_assistant = settings
+ .inline_assistant_model
+ .as_ref()
+ .map(to_selected_model);
+ let commit_message = settings
+ .commit_message_model
+ .as_ref()
+ .map(to_selected_model);
+ let thread_summary = settings
+ .thread_summary_model
+ .as_ref()
+ .map(to_selected_model);
+ let inline_alternatives = settings
+ .inline_alternatives
+ .iter()
+ .map(to_selected_model)
+ .collect::<Vec<_>>();
+
+ LanguageModelRegistry::global(cx).update(cx, |registry, cx| {
+ registry.select_default_model(Some(&default), cx);
+ registry.select_inline_assistant_model(inline_assistant.as_ref(), cx);
+ registry.select_commit_message_model(commit_message.as_ref(), cx);
+ registry.select_thread_summary_model(thread_summary.as_ref(), cx);
+ registry.select_inline_alternative_models(inline_alternatives, cx);
+ });
+}
+
+fn register_slash_commands(cx: &mut App) {
+ let slash_command_registry = SlashCommandRegistry::global(cx);
+
+ slash_command_registry.register_command(assistant_slash_commands::FileSlashCommand, true);
+ slash_command_registry.register_command(assistant_slash_commands::DeltaSlashCommand, true);
+ slash_command_registry.register_command(assistant_slash_commands::OutlineSlashCommand, true);
+ slash_command_registry.register_command(assistant_slash_commands::TabSlashCommand, true);
+ slash_command_registry
+ .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
+ slash_command_registry.register_command(assistant_slash_commands::PromptSlashCommand, true);
+ slash_command_registry.register_command(assistant_slash_commands::SelectionCommand, true);
+ slash_command_registry.register_command(assistant_slash_commands::DefaultSlashCommand, false);
+ slash_command_registry.register_command(assistant_slash_commands::NowSlashCommand, false);
+ slash_command_registry
+ .register_command(assistant_slash_commands::DiagnosticsSlashCommand, true);
+ slash_command_registry.register_command(assistant_slash_commands::FetchSlashCommand, true);
+
+ cx.observe_flag::<assistant_slash_commands::StreamingExampleSlashCommandFeatureFlag, _>({
+ let slash_command_registry = slash_command_registry.clone();
+ move |is_enabled, _cx| {
+ if is_enabled {
+ slash_command_registry.register_command(
+ assistant_slash_commands::StreamingExampleSlashCommand,
+ false,
+ );
+ }
+ }
+ })
+ .detach();
+
+ update_slash_commands_from_settings(cx);
+ cx.observe_global::<SettingsStore>(update_slash_commands_from_settings)
+ .detach();
+}
+
+fn update_slash_commands_from_settings(cx: &mut App) {
+ let slash_command_registry = SlashCommandRegistry::global(cx);
+ let settings = SlashCommandSettings::get_global(cx);
+
+ if settings.docs.enabled {
+ slash_command_registry.register_command(assistant_slash_commands::DocsSlashCommand, true);
+ } else {
+ slash_command_registry.unregister_command(assistant_slash_commands::DocsSlashCommand);
+ }
+
+ if settings.cargo_workspace.enabled {
+ slash_command_registry
+ .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
+ } else {
+ slash_command_registry
+ .unregister_command(assistant_slash_commands::CargoWorkspaceSlashCommand);
+ }
+}
@@ -1,6 +1,8 @@
-use crate::context::ContextLoadResult;
use crate::inline_prompt_editor::CodegenStatus;
-use crate::{context::load_context, context_store::ContextStore};
+use agent::{
+ ContextStore,
+ context::{ContextLoadResult, load_context},
+};
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result};
use client::telemetry::Telemetry;
@@ -18,8 +20,7 @@ use language_model::{
use multi_buffer::MultiBufferRow;
use parking_lot::Mutex;
use project::Project;
-use prompt_store::PromptBuilder;
-use prompt_store::PromptStore;
+use prompt_store::{PromptBuilder, PromptStore};
use rope::Rope;
use smol::future::FutureExt;
use std::{
@@ -37,10 +37,12 @@ use uuid::Uuid;
use workspace::{Workspace, notifications::NotifyResultExt};
use crate::AgentPanel;
-use crate::context::RULES_ICON;
-use crate::context_store::ContextStore;
-use crate::thread::ThreadId;
-use crate::thread_store::{TextThreadStore, ThreadStore};
+use agent::{
+ ThreadId,
+ context::RULES_ICON,
+ context_store::ContextStore,
+ thread_store::{TextThreadStore, ThreadStore},
+};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ContextPickerEntry {
@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
+use agent::context_store::ContextStore;
use anyhow::Result;
use editor::{CompletionProvider, Editor, ExcerptId, ToOffset as _};
use file_icons::FileIcons;
@@ -20,10 +21,11 @@ use ui::prelude::*;
use util::ResultExt as _;
use workspace::Workspace;
-use crate::Thread;
-use crate::context::{AgentContextHandle, AgentContextKey, ContextCreasesAddon, RULES_ICON};
-use crate::context_store::ContextStore;
-use crate::thread_store::{TextThreadStore, ThreadStore};
+use agent::{
+ Thread,
+ context::{AgentContextHandle, AgentContextKey, RULES_ICON},
+ thread_store::{TextThreadStore, ThreadStore},
+};
use super::fetch_context_picker::fetch_url_content;
use super::file_context_picker::{FileMatch, search_files};
@@ -35,6 +37,7 @@ use super::{
ContextPickerAction, ContextPickerEntry, ContextPickerMode, MentionLink, RecentEntry,
available_context_picker_entries, recent_context_picker_entries, selection_ranges,
};
+use crate::message_editor::ContextCreasesAddon;
pub(crate) enum Match {
File(FileMatch),
@@ -2,6 +2,7 @@ use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
+use agent::context_store::ContextStore;
use anyhow::{Context as _, Result, bail};
use futures::AsyncReadExt as _;
use gpui::{App, DismissEvent, Entity, FocusHandle, Focusable, Task, WeakEntity};
@@ -12,7 +13,6 @@ use ui::{Context, ListItem, Window, prelude::*};
use workspace::Workspace;
use crate::context_picker::ContextPicker;
-use crate::context_store::ContextStore;
pub struct FetchContextPicker {
picker: Entity<Picker<FetchContextPickerDelegate>>,
@@ -14,7 +14,7 @@ use util::ResultExt as _;
use workspace::Workspace;
use crate::context_picker::ContextPicker;
-use crate::context_store::{ContextStore, FileInclusion};
+use agent::context_store::{ContextStore, FileInclusion};
pub struct FileContextPicker {
picker: Entity<Picker<FileContextPickerDelegate>>,
@@ -7,9 +7,9 @@ use prompt_store::{PromptId, PromptStore, UserPromptId};
use ui::{ListItem, prelude::*};
use util::ResultExt as _;
-use crate::context::RULES_ICON;
use crate::context_picker::ContextPicker;
-use crate::context_store::{self, ContextStore};
+use agent::context::RULES_ICON;
+use agent::context_store::{self, ContextStore};
pub struct RulesContextPicker {
picker: Entity<Picker<RulesContextPickerDelegate>>,
@@ -14,9 +14,9 @@ use ui::{ListItem, prelude::*};
use util::ResultExt as _;
use workspace::Workspace;
-use crate::context::AgentContextHandle;
use crate::context_picker::ContextPicker;
-use crate::context_store::ContextStore;
+use agent::context::AgentContextHandle;
+use agent::context_store::ContextStore;
pub struct SymbolContextPicker {
picker: Entity<Picker<SymbolContextPickerDelegate>>,
@@ -9,9 +9,11 @@ use picker::{Picker, PickerDelegate};
use ui::{ListItem, prelude::*};
use crate::context_picker::ContextPicker;
-use crate::context_store::{self, ContextStore};
-use crate::thread::ThreadId;
-use crate::thread_store::{TextThreadStore, ThreadStore};
+use agent::{
+ ThreadId,
+ context_store::{self, ContextStore},
+ thread_store::{TextThreadStore, ThreadStore},
+};
pub struct ThreadContextPicker {
picker: Entity<Picker<ThreadContextPickerDelegate>>,
@@ -1,7 +1,15 @@
-use std::path::Path;
-use std::rc::Rc;
-
-use assistant_context_editor::AssistantContext;
+use crate::{
+ AcceptSuggestedContext, AgentPanel, FocusDown, FocusLeft, FocusRight, FocusUp,
+ ModelUsageContext, RemoveAllContext, RemoveFocusedContext, ToggleContextPicker,
+ context_picker::ContextPicker,
+ ui::{AddedContext, ContextPill},
+};
+use agent::context_store::SuggestedContext;
+use agent::{
+ context::AgentContextHandle,
+ context_store::ContextStore,
+ thread_store::{TextThreadStore, ThreadStore},
+};
use collections::HashSet;
use editor::Editor;
use file_icons::FileIcons;
@@ -10,22 +18,11 @@ use gpui::{
Subscription, WeakEntity,
};
use itertools::Itertools;
-use language::Buffer;
use project::ProjectItem;
+use std::{path::Path, rc::Rc};
use ui::{PopoverMenu, PopoverMenuHandle, Tooltip, prelude::*};
use workspace::Workspace;
-use crate::context::{AgentContextHandle, ContextKind};
-use crate::context_picker::ContextPicker;
-use crate::context_store::ContextStore;
-use crate::thread::Thread;
-use crate::thread_store::{TextThreadStore, ThreadStore};
-use crate::ui::{AddedContext, ContextPill};
-use crate::{
- AcceptSuggestedContext, AgentPanel, FocusDown, FocusLeft, FocusRight, FocusUp,
- ModelUsageContext, RemoveAllContext, RemoveFocusedContext, ToggleContextPicker,
-};
-
pub struct ContextStrip {
context_store: Entity<ContextStore>,
context_picker: Entity<ContextPicker>,
@@ -575,46 +572,3 @@ pub enum SuggestContextKind {
File,
Thread,
}
-
-#[derive(Clone)]
-pub enum SuggestedContext {
- File {
- name: SharedString,
- icon_path: Option<SharedString>,
- buffer: WeakEntity<Buffer>,
- },
- Thread {
- name: SharedString,
- thread: WeakEntity<Thread>,
- },
- TextThread {
- name: SharedString,
- context: WeakEntity<AssistantContext>,
- },
-}
-
-impl SuggestedContext {
- pub fn name(&self) -> &SharedString {
- match self {
- Self::File { name, .. } => name,
- Self::Thread { name, .. } => name,
- Self::TextThread { name, .. } => name,
- }
- }
-
- pub fn icon_path(&self) -> Option<SharedString> {
- match self {
- Self::File { icon_path, .. } => icon_path.clone(),
- Self::Thread { .. } => None,
- Self::TextThread { .. } => None,
- }
- }
-
- pub fn kind(&self) -> ContextKind {
- match self {
- Self::File { .. } => ContextKind::File,
- Self::Thread { .. } => ContextKind::Thread,
- Self::TextThread { .. } => ContextKind::TextThread,
- }
- }
-}
@@ -4,18 +4,27 @@ use std::ops::Range;
use std::rc::Rc;
use std::sync::Arc;
+use crate::{
+ AgentPanel,
+ buffer_codegen::{BufferCodegen, CodegenAlternative, CodegenEvent},
+ inline_prompt_editor::{CodegenStatus, InlineAssistId, PromptEditor, PromptEditorEvent},
+ terminal_inline_assistant::TerminalInlineAssistant,
+};
+use agent::{
+ context_store::ContextStore,
+ thread_store::{TextThreadStore, ThreadStore},
+};
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result};
use client::telemetry::Telemetry;
use collections::{HashMap, HashSet, VecDeque, hash_map};
-use editor::display_map::EditorMargins;
use editor::{
Anchor, AnchorRangeExt, CodeActionProvider, Editor, EditorEvent, ExcerptId, ExcerptRange,
MultiBuffer, MultiBufferSnapshot, ToOffset as _, ToPoint,
actions::SelectAll,
display_map::{
- BlockContext, BlockPlacement, BlockProperties, BlockStyle, CustomBlockId, RenderBlock,
- ToDisplayPoint,
+ BlockContext, BlockPlacement, BlockProperties, BlockStyle, CustomBlockId, EditorMargins,
+ RenderBlock, ToDisplayPoint,
},
};
use fs::Fs;
@@ -24,16 +33,13 @@ use gpui::{
WeakEntity, Window, point,
};
use language::{Buffer, Point, Selection, TransactionId};
-use language_model::ConfigurationError;
-use language_model::ConfiguredModel;
-use language_model::{LanguageModelRegistry, report_assistant_event};
+use language_model::{
+ ConfigurationError, ConfiguredModel, LanguageModelRegistry, report_assistant_event,
+};
use multi_buffer::MultiBufferRow;
use parking_lot::Mutex;
-use project::LspAction;
-use project::Project;
-use project::{CodeAction, ProjectTransaction};
-use prompt_store::PromptBuilder;
-use prompt_store::PromptStore;
+use project::{CodeAction, LspAction, Project, ProjectTransaction};
+use prompt_store::{PromptBuilder, PromptStore};
use settings::{Settings, SettingsStore};
use telemetry_events::{AssistantEventData, AssistantKind, AssistantPhase};
use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
@@ -43,14 +49,6 @@ use util::{RangeExt, ResultExt, maybe};
use workspace::{ItemHandle, Toast, Workspace, dock::Panel, notifications::NotificationId};
use zed_actions::agent::OpenConfiguration;
-use crate::AgentPanel;
-use crate::buffer_codegen::{BufferCodegen, CodegenAlternative, CodegenEvent};
-use crate::context_store::ContextStore;
-use crate::inline_prompt_editor::{CodegenStatus, InlineAssistId, PromptEditor, PromptEditorEvent};
-use crate::terminal_inline_assistant::TerminalInlineAssistant;
-use crate::thread_store::TextThreadStore;
-use crate::thread_store::ThreadStore;
-
pub fn init(
fs: Arc<dyn Fs>,
prompt_builder: Arc<PromptBuilder>,
@@ -1,14 +1,15 @@
use crate::agent_model_selector::AgentModelSelector;
use crate::buffer_codegen::BufferCodegen;
-use crate::context::ContextCreasesAddon;
use crate::context_picker::{ContextPicker, ContextPickerCompletionProvider};
-use crate::context_store::ContextStore;
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
-use crate::message_editor::{extract_message_creases, insert_message_creases};
+use crate::message_editor::{ContextCreasesAddon, extract_message_creases, insert_message_creases};
use crate::terminal_codegen::TerminalCodegen;
-use crate::thread_store::{TextThreadStore, ThreadStore};
use crate::{CycleNextInlineAssist, CyclePreviousInlineAssist, ModelUsageContext};
use crate::{RemoveAllContext, ToggleContextPicker};
+use agent::{
+ context_store::ContextStore,
+ thread_store::{TextThreadStore, ThreadStore},
+};
use assistant_context_editor::language_model_selector::ToggleModelSelector;
use client::ErrorExt;
use collections::VecDeque;
@@ -3,21 +3,25 @@ use std::rc::Rc;
use std::sync::Arc;
use crate::agent_model_selector::AgentModelSelector;
-use crate::context::{AgentContextKey, ContextCreasesAddon, ContextLoadResult, load_context};
use crate::tool_compatibility::{IncompatibleToolsState, IncompatibleToolsTooltip};
use crate::ui::{
MaxModeTooltip,
preview::{AgentPreview, UsageCallout},
};
+use agent::{
+ context::{AgentContextKey, ContextLoadResult, load_context},
+ context_store::ContextStoreEvent,
+};
use agent_settings::{AgentSettings, CompletionMode};
use assistant_context_editor::language_model_selector::ToggleModelSelector;
use buffer_diff::BufferDiff;
use client::UserStore;
use collections::{HashMap, HashSet};
use editor::actions::{MoveUp, Paste};
+use editor::display_map::CreaseId;
use editor::{
- AnchorRangeExt, ContextMenuOptions, ContextMenuPlacement, Editor, EditorElement, EditorEvent,
- EditorMode, EditorStyle, MultiBuffer,
+ Addon, AnchorRangeExt, ContextMenuOptions, ContextMenuPlacement, Editor, EditorElement,
+ EditorEvent, EditorMode, EditorStyle, MultiBuffer,
};
use file_icons::FileIcons;
use fs::Fs;
@@ -46,16 +50,18 @@ use workspace::{CollaboratorId, Workspace};
use zed_llm_client::CompletionIntent;
use crate::context_picker::{ContextPicker, ContextPickerCompletionProvider, crease_for_mention};
-use crate::context_store::ContextStore;
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
use crate::profile_selector::ProfileSelector;
-use crate::thread::{MessageCrease, Thread, TokenUsageRatio};
-use crate::thread_store::{TextThreadStore, ThreadStore};
use crate::{
ActiveThread, AgentDiffPane, Chat, ChatWithFollow, ExpandMessageEditor, Follow, KeepAll,
ModelUsageContext, NewThread, OpenAgentDiff, RejectAll, RemoveAllContext, ToggleBurnMode,
ToggleContextPicker, ToggleProfileSelector, register_agent_preview,
};
+use agent::{
+ MessageCrease, Thread, TokenUsageRatio,
+ context_store::ContextStore,
+ thread_store::{TextThreadStore, ThreadStore},
+};
#[derive(RegisterComponent)]
pub struct MessageEditor {
@@ -1466,6 +1472,69 @@ impl MessageEditor {
}
}
+#[derive(Default)]
+pub struct ContextCreasesAddon {
+ creases: HashMap<AgentContextKey, Vec<(CreaseId, SharedString)>>,
+ _subscription: Option<Subscription>,
+}
+
+impl Addon for ContextCreasesAddon {
+ fn to_any(&self) -> &dyn std::any::Any {
+ self
+ }
+
+ fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
+ Some(self)
+ }
+}
+
+impl ContextCreasesAddon {
+ pub fn new() -> Self {
+ Self {
+ creases: HashMap::default(),
+ _subscription: None,
+ }
+ }
+
+ pub fn add_creases(
+ &mut self,
+ context_store: &Entity<ContextStore>,
+ key: AgentContextKey,
+ creases: impl IntoIterator<Item = (CreaseId, SharedString)>,
+ cx: &mut Context<Editor>,
+ ) {
+ self.creases.entry(key).or_default().extend(creases);
+ self._subscription = Some(cx.subscribe(
+ &context_store,
+ |editor, _, event, cx| match event {
+ ContextStoreEvent::ContextRemoved(key) => {
+ let Some(this) = editor.addon_mut::<Self>() else {
+ return;
+ };
+ let (crease_ids, replacement_texts): (Vec<_>, Vec<_>) = this
+ .creases
+ .remove(key)
+ .unwrap_or_default()
+ .into_iter()
+ .unzip();
+ let ranges = editor
+ .remove_creases(crease_ids, cx)
+ .into_iter()
+ .map(|(_, range)| range)
+ .collect::<Vec<_>>();
+ editor.unfold_ranges(&ranges, false, false, cx);
+ editor.edit(ranges.into_iter().zip(replacement_texts), cx);
+ cx.notify();
+ }
+ },
+ ))
+ }
+
+ pub fn into_inner(self) -> HashMap<AgentContextKey, Vec<(CreaseId, SharedString)>> {
+ self.creases
+ }
+}
+
pub fn extract_message_creases(
editor: &mut Editor,
cx: &mut Context<'_, Editor>,
@@ -1504,8 +1573,9 @@ pub fn extract_message_creases(
let context = contexts_by_crease_id.remove(&id);
MessageCrease {
range,
- metadata,
context,
+ label: metadata.label,
+ icon_path: metadata.icon_path,
}
})
.collect()
@@ -1577,8 +1647,8 @@ pub fn insert_message_creases(
let start = buffer_snapshot.anchor_after(crease.range.start);
let end = buffer_snapshot.anchor_before(crease.range.end);
crease_for_mention(
- crease.metadata.label.clone(),
- crease.metadata.icon_path.clone(),
+ crease.label.clone(),
+ crease.icon_path.clone(),
start..end,
cx.weak_entity(),
)
@@ -1590,12 +1660,7 @@ pub fn insert_message_creases(
for (crease, id) in message_creases.iter().zip(ids) {
if let Some(context) = crease.context.as_ref() {
let key = AgentContextKey(context.clone());
- addon.add_creases(
- context_store,
- key,
- vec![(id, crease.metadata.label.clone())],
- cx,
- );
+ addon.add_creases(context_store, key, vec![(id, crease.label.clone())], cx);
}
}
}
@@ -1,20 +1,19 @@
-use std::sync::Arc;
-
+use crate::{ManageProfiles, ToggleProfileSelector};
+use agent::{
+ Thread,
+ agent_profile::{AgentProfile, AvailableProfiles},
+};
use agent_settings::{AgentDockPosition, AgentProfileId, AgentSettings, builtin_profiles};
use fs::Fs;
use gpui::{Action, Empty, Entity, FocusHandle, Subscription, prelude::*};
use language_model::LanguageModelRegistry;
use settings::{Settings as _, SettingsStore, update_settings_file};
+use std::sync::Arc;
use ui::{
ContextMenu, ContextMenuEntry, DocumentationSide, PopoverMenu, PopoverMenuHandle, Tooltip,
prelude::*,
};
-use crate::{
- ManageProfiles, Thread, ToggleProfileSelector,
- agent_profile::{AgentProfile, AvailableProfiles},
-};
-
pub struct ProfileSelector {
profiles: AvailableProfiles,
fs: Arc<dyn Fs>,
@@ -1,10 +1,12 @@
-use crate::context::load_context;
-use crate::context_store::ContextStore;
use crate::inline_prompt_editor::{
CodegenStatus, PromptEditor, PromptEditorEvent, TerminalInlineAssistId,
};
use crate::terminal_codegen::{CLEAR_INPUT, CodegenEvent, TerminalCodegen};
-use crate::thread_store::{TextThreadStore, ThreadStore};
+use agent::{
+ context::load_context,
+ context_store::ContextStore,
+ thread_store::{TextThreadStore, ThreadStore},
+};
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result};
use client::telemetry::Telemetry;
@@ -1,7 +1,5 @@
-use std::fmt::Display;
-use std::ops::Range;
-use std::sync::Arc;
-
+use crate::{AgentPanel, RemoveSelectedThread};
+use agent::history_store::{HistoryEntry, HistoryStore};
use chrono::{Datelike as _, Local, NaiveDate, TimeDelta};
use editor::{Editor, EditorEvent};
use fuzzy::{StringMatch, StringMatchCandidate};
@@ -9,6 +7,7 @@ use gpui::{
App, ClickEvent, Empty, Entity, FocusHandle, Focusable, ScrollStrategy, Stateful, Task,
UniformListScrollHandle, WeakEntity, Window, uniform_list,
};
+use std::{fmt::Display, ops::Range, sync::Arc};
use time::{OffsetDateTime, UtcOffset};
use ui::{
HighlightedLabel, IconButtonShape, ListItem, ListItemSpacing, Scrollbar, ScrollbarState,
@@ -16,9 +15,6 @@ use ui::{
};
use util::ResultExt;
-use crate::history_store::{HistoryEntry, HistoryStore};
-use crate::{AgentPanel, RemoveSelectedThread};
-
pub struct ThreadHistory {
agent_panel: WeakEntity<AgentPanel>,
history_store: Entity<HistoryStore>,
@@ -1,13 +1,11 @@
-use std::sync::Arc;
-
+use agent::{Thread, ThreadEvent};
use assistant_tool::{Tool, ToolSource};
use collections::HashMap;
use gpui::{App, Context, Entity, IntoElement, Render, Subscription, Window};
use language_model::{LanguageModel, LanguageModelToolSchemaFormat};
+use std::sync::Arc;
use ui::prelude::*;
-use crate::{Thread, ThreadEvent};
-
pub struct IncompatibleToolsState {
cache: HashMap<LanguageModelToolSchemaFormat, Vec<Arc<dyn Tool>>>,
thread: Entity<Thread>,
@@ -12,7 +12,7 @@ use prompt_store::PromptStore;
use rope::Point;
use ui::{IconButtonShape, Tooltip, prelude::*, tooltip_container};
-use crate::context::{
+use agent::context::{
AgentContext, AgentContextHandle, ContextId, ContextKind, DirectoryContext,
DirectoryContextHandle, FetchedUrlContext, FileContext, FileContextHandle, ImageContext,
ImageStatus, RulesContext, RulesContextHandle, SelectionContext, SelectionContextHandle,
@@ -19,6 +19,7 @@ path = "src/explorer.rs"
[dependencies]
agent.workspace = true
+agent_ui.workspace = true
agent_settings.workspace = true
anyhow.workspace = true
assistant_tool.workspace = true
@@ -423,7 +423,7 @@ pub fn init(cx: &mut App) -> Arc<AgentAppState> {
terminal_view::init(cx);
let stdout_is_a_pty = false;
let prompt_builder = PromptBuilder::load(fs.clone(), stdout_is_a_pty, cx);
- agent::init(
+ agent_ui::init(
fs.clone(),
client.clone(),
prompt_builder.clone(),
@@ -100,7 +100,7 @@ impl ExampleContext {
pub fn new(
meta: ExampleMetadata,
log_prefix: String,
- agent_thread: Entity<agent::Thread>,
+ agent_thread: Entity<Thread>,
model: Arc<dyn LanguageModel>,
app: AsyncApp,
) -> Self {
@@ -21,6 +21,7 @@ path = "src/main.rs"
[dependencies]
activity_indicator.workspace = true
agent.workspace = true
+agent_ui.workspace = true
agent_settings.workspace = true
anyhow.workspace = true
askpass.workspace = true
@@ -531,7 +531,7 @@ pub fn main() {
cx,
);
let prompt_builder = PromptBuilder::load(app_state.fs.clone(), stdout_is_a_pty(), cx);
- agent::init(
+ agent_ui::init(
app_state.fs.clone(),
app_state.client.clone(),
prompt_builder.clone(),
@@ -9,7 +9,7 @@ mod quick_action_bar;
#[cfg(target_os = "windows")]
pub(crate) mod windows_only_instance;
-use agent::AgentDiffToolbar;
+use agent_ui::AgentDiffToolbar;
use anyhow::Context as _;
pub use app_menus::*;
use assets::Assets;
@@ -515,7 +515,7 @@ fn initialize_panels(
let is_assistant2_enabled = !cfg!(test);
let agent_panel = if is_assistant2_enabled {
let agent_panel =
- agent::AgentPanel::load(workspace_handle.clone(), prompt_builder, cx.clone())
+ agent_ui::AgentPanel::load(workspace_handle.clone(), prompt_builder, cx.clone())
.await?;
Some(agent_panel)
@@ -536,13 +536,13 @@ fn initialize_panels(
// Once we ship `assistant2` we can push this back down into `agent::agent_panel::init`.
if is_assistant2_enabled {
<dyn AgentPanelDelegate>::set_global(
- Arc::new(agent::ConcreteAssistantPanelDelegate),
+ Arc::new(agent_ui::ConcreteAssistantPanelDelegate),
cx,
);
workspace
- .register_action(agent::AgentPanel::toggle_focus)
- .register_action(agent::InlineAssistant::inline_assist);
+ .register_action(agent_ui::AgentPanel::toggle_focus)
+ .register_action(agent_ui::InlineAssistant::inline_assist);
}
})?;
@@ -4320,7 +4320,7 @@ mod tests {
web_search::init(cx);
web_search_providers::init(app_state.client.clone(), cx);
let prompt_builder = PromptBuilder::load(app_state.fs.clone(), false, cx);
- agent::init(
+ agent_ui::init(
app_state.fs.clone(),
app_state.client.clone(),
prompt_builder.clone(),
@@ -5,20 +5,14 @@
mod persistence;
mod preview_support;
-use std::ops::Range;
-use std::sync::Arc;
-
-use std::iter::Iterator;
-
-use agent::{ActiveThread, TextThreadStore, ThreadStore};
+use agent::{TextThreadStore, ThreadStore};
+use agent_ui::ActiveThread;
use client::UserStore;
+use collections::HashMap;
use component::{ComponentId, ComponentMetadata, ComponentStatus, components};
use gpui::{
App, Entity, EventEmitter, FocusHandle, Focusable, Task, WeakEntity, Window, list, prelude::*,
};
-
-use collections::HashMap;
-
use gpui::{ListState, ScrollHandle, ScrollStrategy, UniformListScrollHandle};
use languages::LanguageRegistry;
use notifications::status_toast::{StatusToast, ToastIcon};
@@ -27,11 +21,14 @@ use preview_support::active_thread::{
load_preview_text_thread_store, load_preview_thread_store, static_active_thread,
};
use project::Project;
+use std::{iter::Iterator, ops::Range, sync::Arc};
use ui::{ButtonLike, Divider, HighlightedLabel, ListItem, ListSubHeader, Tooltip, prelude::*};
use ui_input::SingleLineInput;
use util::ResultExt as _;
-use workspace::{AppState, ItemId, SerializableItem, delete_unloaded_items};
-use workspace::{Item, Workspace, WorkspaceId, item::ItemEvent};
+use workspace::{
+ AppState, Item, ItemId, SerializableItem, Workspace, WorkspaceId, delete_unloaded_items,
+ item::ItemEvent,
+};
pub fn init(app_state: Arc<AppState>, cx: &mut App) {
workspace::register_serializable_item::<ComponentPreview>(cx);
@@ -642,7 +639,7 @@ impl ComponentPreview {
// Check if the component's scope is Agent
if scope == ComponentScope::Agent {
if let Some(active_thread) = self.active_thread.clone() {
- if let Some(element) = agent::get_agent_preview(
+ if let Some(element) = agent_ui::get_agent_preview(
&component.id(),
self.workspace.clone(),
active_thread,
@@ -1140,7 +1137,7 @@ impl ComponentPreviewPage {
fn render_preview(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
// Try to get agent preview first if we have an active thread
let maybe_agent_preview = if let Some(active_thread) = self.active_thread.as_ref() {
- agent::get_agent_preview(
+ agent_ui::get_agent_preview(
&self.component.id(),
self.workspace.clone(),
active_thread.clone(),
@@ -1,4 +1,5 @@
-use agent::{ActiveThread, ContextStore, MessageSegment, TextThreadStore, ThreadStore};
+use agent::{ContextStore, MessageSegment, TextThreadStore, ThreadStore};
+use agent_ui::ActiveThread;
use anyhow::{Result, anyhow};
use assistant_tool::ToolWorkingSet;
use gpui::{AppContext, AsyncApp, Entity, Task, WeakEntity};