Extract an agent_ui crate from agent (#33284)

This PR moves the UI-dependent logic in the `agent` crate into its own
crate, `agent_ui`. The remaining `agent` crate no longer depends on
`editor`, `picker`, `ui`, `workspace`, etc.

This has compile time benefits, but the main motivation is to isolate
our core agentic logic, so that we can make agents more
pluggable/configurable.

Release Notes:

- N/A
This commit is contained in:
Max Brunsfeld 2025-06-23 18:00:28 -07:00 committed by GitHub
parent 371b7355d3
commit 2283ec5de2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 865 additions and 752 deletions

121
Cargo.lock generated
View file

@ -56,49 +56,28 @@ dependencies = [
"agent_settings", "agent_settings",
"anyhow", "anyhow",
"assistant_context_editor", "assistant_context_editor",
"assistant_slash_command",
"assistant_slash_commands",
"assistant_tool", "assistant_tool",
"assistant_tools", "assistant_tools",
"audio",
"buffer_diff",
"chrono", "chrono",
"client", "client",
"collections", "collections",
"component", "component",
"context_server", "context_server",
"convert_case 0.8.0", "convert_case 0.8.0",
"db",
"editor",
"extension",
"extension_host",
"feature_flags", "feature_flags",
"file_icons",
"fs", "fs",
"futures 0.3.31", "futures 0.3.31",
"fuzzy",
"git", "git",
"gpui", "gpui",
"heed", "heed",
"html_to_markdown",
"http_client", "http_client",
"indexed_docs", "icons",
"indoc", "indoc",
"inventory",
"itertools 0.14.0", "itertools 0.14.0",
"jsonschema",
"language", "language",
"language_model", "language_model",
"log", "log",
"lsp",
"markdown",
"menu",
"multi_buffer",
"notifications",
"ordered-float 2.10.1",
"parking_lot",
"paths", "paths",
"picker",
"postage", "postage",
"pretty_assertions", "pretty_assertions",
"project", "project",
@ -106,35 +85,22 @@ dependencies = [
"proto", "proto",
"rand 0.8.5", "rand 0.8.5",
"ref-cast", "ref-cast",
"release_channel",
"rope", "rope",
"rules_library",
"schemars", "schemars",
"search",
"serde", "serde",
"serde_json", "serde_json",
"serde_json_lenient",
"settings", "settings",
"smol", "smol",
"sqlez", "sqlez",
"streaming_diff",
"telemetry", "telemetry",
"telemetry_events",
"terminal",
"terminal_view",
"text", "text",
"theme", "theme",
"thiserror 2.0.12", "thiserror 2.0.12",
"time", "time",
"time_format",
"ui",
"urlencoding",
"util", "util",
"uuid", "uuid",
"watch",
"workspace", "workspace",
"workspace-hack", "workspace-hack",
"zed_actions",
"zed_llm_client", "zed_llm_client",
"zstd", "zstd",
] ]
@ -165,6 +131,89 @@ dependencies = [
"zed_llm_client", "zed_llm_client",
] ]
[[package]]
name = "agent_ui"
version = "0.1.0"
dependencies = [
"agent",
"agent_settings",
"anyhow",
"assistant_context_editor",
"assistant_slash_command",
"assistant_slash_commands",
"assistant_tool",
"assistant_tools",
"audio",
"buffer_diff",
"chrono",
"client",
"collections",
"component",
"context_server",
"db",
"editor",
"extension",
"extension_host",
"feature_flags",
"file_icons",
"fs",
"futures 0.3.31",
"fuzzy",
"gpui",
"html_to_markdown",
"http_client",
"indexed_docs",
"indoc",
"inventory",
"itertools 0.14.0",
"jsonschema",
"language",
"language_model",
"log",
"lsp",
"markdown",
"menu",
"multi_buffer",
"notifications",
"ordered-float 2.10.1",
"parking_lot",
"paths",
"picker",
"pretty_assertions",
"project",
"prompt_store",
"proto",
"rand 0.8.5",
"release_channel",
"rope",
"rules_library",
"schemars",
"search",
"serde",
"serde_json",
"serde_json_lenient",
"settings",
"smol",
"streaming_diff",
"telemetry",
"telemetry_events",
"terminal",
"terminal_view",
"text",
"theme",
"time",
"time_format",
"ui",
"urlencoding",
"util",
"uuid",
"watch",
"workspace",
"workspace-hack",
"zed_actions",
"zed_llm_client",
]
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.7.8" version = "0.7.8"
@ -5062,6 +5111,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"agent", "agent",
"agent_settings", "agent_settings",
"agent_ui",
"anyhow", "anyhow",
"assistant_tool", "assistant_tool",
"assistant_tools", "assistant_tools",
@ -19868,6 +19918,7 @@ dependencies = [
"activity_indicator", "activity_indicator",
"agent", "agent",
"agent_settings", "agent_settings",
"agent_ui",
"anyhow", "anyhow",
"ashpd", "ashpd",
"askpass", "askpass",

View file

@ -2,6 +2,7 @@
resolver = "2" resolver = "2"
members = [ members = [
"crates/activity_indicator", "crates/activity_indicator",
"crates/agent_ui",
"crates/agent", "crates/agent",
"crates/agent_settings", "crates/agent_settings",
"crates/anthropic", "crates/anthropic",
@ -214,6 +215,7 @@ edition = "2024"
activity_indicator = { path = "crates/activity_indicator" } activity_indicator = { path = "crates/activity_indicator" }
agent = { path = "crates/agent" } agent = { path = "crates/agent" }
agent_ui = { path = "crates/agent_ui" }
agent_settings = { path = "crates/agent_settings" } agent_settings = { path = "crates/agent_settings" }
ai = { path = "crates/ai" } ai = { path = "crates/ai" }
anthropic = { path = "crates/anthropic" } anthropic = { path = "crates/anthropic" }

View file

@ -22,93 +22,57 @@ test-support = [
agent_settings.workspace = true agent_settings.workspace = true
anyhow.workspace = true anyhow.workspace = true
assistant_context_editor.workspace = true assistant_context_editor.workspace = true
assistant_slash_command.workspace = true
assistant_slash_commands.workspace = true
assistant_tool.workspace = true assistant_tool.workspace = true
audio.workspace = true
buffer_diff.workspace = true
chrono.workspace = true chrono.workspace = true
client.workspace = true client.workspace = true
collections.workspace = true collections.workspace = true
component.workspace = true component.workspace = true
context_server.workspace = true context_server.workspace = true
convert_case.workspace = true convert_case.workspace = true
db.workspace = true
editor.workspace = true
extension.workspace = true
extension_host.workspace = true
feature_flags.workspace = true feature_flags.workspace = true
file_icons.workspace = true
fs.workspace = true fs.workspace = true
futures.workspace = true futures.workspace = true
fuzzy.workspace = true
git.workspace = true git.workspace = true
gpui.workspace = true gpui.workspace = true
heed.workspace = true heed.workspace = true
html_to_markdown.workspace = true icons.workspace = true
indoc.workspace = true indoc.workspace = true
http_client.workspace = true http_client.workspace = true
indexed_docs.workspace = true
inventory.workspace = true
itertools.workspace = true itertools.workspace = true
jsonschema.workspace = true
language.workspace = true language.workspace = true
language_model.workspace = true language_model.workspace = true
log.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 paths.workspace = true
picker.workspace = true
postage.workspace = true postage.workspace = true
project.workspace = true project.workspace = true
prompt_store.workspace = true prompt_store.workspace = true
proto.workspace = true proto.workspace = true
ref-cast.workspace = true ref-cast.workspace = true
release_channel.workspace = true
rope.workspace = true rope.workspace = true
rules_library.workspace = true
schemars.workspace = true schemars.workspace = true
search.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
serde_json_lenient.workspace = true
settings.workspace = true settings.workspace = true
smol.workspace = true smol.workspace = true
sqlez.workspace = true sqlez.workspace = true
streaming_diff.workspace = true
telemetry.workspace = true telemetry.workspace = true
telemetry_events.workspace = true
terminal.workspace = true
terminal_view.workspace = true
text.workspace = true text.workspace = true
theme.workspace = true theme.workspace = true
thiserror.workspace = true thiserror.workspace = true
time.workspace = true time.workspace = true
time_format.workspace = true
ui.workspace = true
urlencoding.workspace = true
util.workspace = true util.workspace = true
uuid.workspace = true uuid.workspace = true
watch.workspace = true
workspace-hack.workspace = true workspace-hack.workspace = true
workspace.workspace = true
zed_actions.workspace = true
zed_llm_client.workspace = true zed_llm_client.workspace = true
zstd.workspace = true zstd.workspace = true
[dev-dependencies] [dev-dependencies]
assistant_tools.workspace = true assistant_tools.workspace = true
buffer_diff = { workspace = true, features = ["test-support"] }
editor = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, "features" = ["test-support"] } gpui = { workspace = true, "features" = ["test-support"] }
indoc.workspace = true indoc.workspace = true
language = { workspace = true, "features" = ["test-support"] } language = { workspace = true, "features" = ["test-support"] }
language_model = { workspace = true, "features" = ["test-support"] } language_model = { workspace = true, "features" = ["test-support"] }
pretty_assertions.workspace = true pretty_assertions.workspace = true
project = { workspace = true, features = ["test-support"] } project = { workspace = true, features = ["test-support"] }
workspace = { workspace = true, features = ["test-support"] }
rand.workspace = true rand.workspace = true

View file

@ -1,297 +1,20 @@
mod active_thread; pub mod agent_profile;
mod agent_configuration; pub mod context;
mod agent_diff; pub mod context_server_tool;
mod agent_model_selector; pub mod context_store;
mod agent_panel; pub mod history_store;
mod agent_profile; pub mod thread;
mod buffer_codegen; pub mod thread_store;
mod context; pub mod tool_use;
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; pub use context::{AgentContext, ContextId, ContextLoadResult};
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 use context_store::ContextStore; pub use context_store::ContextStore;
pub use ui::preview::{all_agent_previews, get_agent_preview}; pub use thread::{
LastRestoreCheckpoint, Message, MessageCrease, MessageId, MessageSegment, Thread, ThreadError,
ThreadEvent, ThreadFeedback, ThreadId, ThreadSummary, TokenUsageRatio,
};
pub use thread_store::{SerializedThread, TextThreadStore, ThreadStore};
actions!( pub fn init(cx: &mut gpui::App) {
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);
thread_store::init(cx); 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);
}
} }

View file

@ -5,9 +5,8 @@ use assistant_tool::{Tool, ToolSource, ToolWorkingSet};
use collections::IndexMap; use collections::IndexMap;
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use fs::Fs; use fs::Fs;
use gpui::{App, Entity}; use gpui::{App, Entity, SharedString};
use settings::{Settings, update_settings_file}; use settings::{Settings, update_settings_file};
use ui::SharedString;
use util::ResultExt; use util::ResultExt;
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
@ -108,11 +107,11 @@ mod tests {
use agent_settings::ContextServerPreset; use agent_settings::ContextServerPreset;
use assistant_tool::ToolRegistry; use assistant_tool::ToolRegistry;
use collections::IndexMap; use collections::IndexMap;
use gpui::SharedString;
use gpui::{AppContext, TestAppContext}; use gpui::{AppContext, TestAppContext};
use http_client::FakeHttpClient; use http_client::FakeHttpClient;
use project::Project; use project::Project;
use settings::{Settings, SettingsStore}; use settings::{Settings, SettingsStore};
use ui::SharedString;
use super::*; use super::*;
@ -302,7 +301,7 @@ mod tests {
unimplemented!() unimplemented!()
} }
fn icon(&self) -> ui::IconName { fn icon(&self) -> icons::IconName {
unimplemented!() unimplemented!()
} }

View file

@ -1,30 +1,25 @@
use std::fmt::{self, Display, Formatter, Write as _}; use crate::thread::Thread;
use std::hash::{Hash, Hasher};
use std::path::PathBuf;
use std::{ops::Range, path::Path, sync::Arc};
use assistant_context_editor::AssistantContext; use assistant_context_editor::AssistantContext;
use assistant_tool::outline; use assistant_tool::outline;
use collections::{HashMap, HashSet}; use collections::HashSet;
use editor::display_map::CreaseId;
use editor::{Addon, Editor};
use futures::future; use futures::future;
use futures::{FutureExt, future::Shared}; 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::{Buffer, ParseStatus};
use language_model::{LanguageModelImage, LanguageModelRequestMessage, MessageContent}; use language_model::{LanguageModelImage, LanguageModelRequestMessage, MessageContent};
use project::{Project, ProjectEntryId, ProjectPath, Worktree}; use project::{Project, ProjectEntryId, ProjectPath, Worktree};
use prompt_store::{PromptStore, UserPromptId}; use prompt_store::{PromptStore, UserPromptId};
use ref_cast::RefCast; use ref_cast::RefCast;
use rope::Point; 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 text::{Anchor, OffsetRangeExt as _};
use ui::{Context, ElementId, IconName};
use util::markdown::MarkdownCodeBlock; use util::markdown::MarkdownCodeBlock;
use util::{ResultExt as _, post_inc}; use util::{ResultExt as _, post_inc};
use crate::context_store::{ContextStore, ContextStoreEvent};
use crate::thread::Thread;
pub const RULES_ICON: IconName = IconName::Context; pub const RULES_ICON: IconName = IconName::Context;
pub enum ContextKind { 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -4,9 +4,9 @@ use anyhow::{Result, anyhow, bail};
use assistant_tool::{ActionLog, Tool, ToolResult, ToolSource}; use assistant_tool::{ActionLog, Tool, ToolResult, ToolSource};
use context_server::{ContextServerId, types}; use context_server::{ContextServerId, types};
use gpui::{AnyWindowHandle, App, Entity, Task}; use gpui::{AnyWindowHandle, App, Entity, Task};
use icons::IconName;
use language_model::{LanguageModel, LanguageModelRequest, LanguageModelToolSchemaFormat}; use language_model::{LanguageModel, LanguageModelRequest, LanguageModelToolSchemaFormat};
use project::{Project, context_server_store::ContextServerStore}; use project::{Project, context_server_store::ContextServerStore};
use ui::IconName;
pub struct ContextServerTool { pub struct ContextServerTool {
store: Entity<ContextServerStore>, store: Entity<ContextServerStore>,

View file

@ -1,7 +1,12 @@
use std::ops::Range; use crate::{
use std::path::{Path, PathBuf}; context::{
use std::sync::Arc; 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 anyhow::{Context as _, Result, anyhow};
use assistant_context_editor::AssistantContext; use assistant_context_editor::AssistantContext;
use collections::{HashSet, IndexSet}; use collections::{HashSet, IndexSet};
@ -9,20 +14,15 @@ use futures::{self, FutureExt};
use gpui::{App, Context, Entity, EventEmitter, Image, SharedString, Task, WeakEntity}; use gpui::{App, Context, Entity, EventEmitter, Image, SharedString, Task, WeakEntity};
use language::{Buffer, File as _}; use language::{Buffer, File as _};
use language_model::LanguageModelImage; use language_model::LanguageModelImage;
use project::image_store::is_image_file; use project::{Project, ProjectItem, ProjectPath, Symbol, image_store::is_image_file};
use project::{Project, ProjectItem, ProjectPath, Symbol};
use prompt_store::UserPromptId; use prompt_store::UserPromptId;
use ref_cast::RefCast as _; use ref_cast::RefCast as _;
use text::{Anchor, OffsetRangeExt}; use std::{
ops::Range,
use crate::ThreadStore; path::{Path, PathBuf},
use crate::context::{ sync::Arc,
AgentContextHandle, AgentContextKey, ContextId, DirectoryContextHandle, FetchedUrlContext,
FileContextHandle, ImageContext, RulesContextHandle, SelectionContextHandle,
SymbolContextHandle, TextThreadContextHandle, ThreadContextHandle,
}; };
use crate::context_strip::SuggestedContext; use text::{Anchor, OffsetRangeExt};
use crate::thread::{MessageId, Thread, ThreadId};
pub struct ContextStore { pub struct ContextStore {
project: WeakEntity<Project>, 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 { pub enum FileInclusion {
Direct, Direct,
InDirectory { full_path: PathBuf }, InDirectory { full_path: PathBuf },

View file

@ -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 anyhow::{Context as _, Result};
use assistant_context_editor::SavedContextMetadata; use assistant_context_editor::SavedContextMetadata;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use gpui::{AsyncApp, Entity, SharedString, Task, prelude::*}; use gpui::{App, AsyncApp, Entity, SharedString, Task, prelude::*};
use itertools::Itertools; use itertools::Itertools;
use paths::contexts_dir; use paths::contexts_dir;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::{collections::VecDeque, path::Path, sync::Arc, time::Duration};
use ui::App;
use util::ResultExt as _; use util::ResultExt as _;
use crate::{
thread::ThreadId,
thread_store::{SerializedThreadMetadata, ThreadStore},
};
const MAX_RECENTLY_OPENED_ENTRIES: usize = 6; const MAX_RECENTLY_OPENED_ENTRIES: usize = 6;
const NAVIGATION_HISTORY_PATH: &str = "agent-navigation-history.json"; const NAVIGATION_HISTORY_PATH: &str = "agent-navigation-history.json";
const SAVE_RECENTLY_OPENED_ENTRIES_DEBOUNCE: Duration = Duration::from_millis(50); const SAVE_RECENTLY_OPENED_ENTRIES_DEBOUNCE: Duration = Duration::from_millis(50);

View file

@ -1,22 +1,25 @@
use std::io::Write; use crate::{
use std::ops::Range; agent_profile::AgentProfile,
use std::sync::Arc; context::{AgentContext, AgentContextHandle, ContextLoadResult, LoadedContext},
use std::time::Instant; thread_store::{
SerializedCrease, SerializedLanguageModel, SerializedMessage, SerializedMessageSegment,
SerializedThread, SerializedToolResult, SerializedToolUse, SharedProjectContext,
ThreadStore,
},
tool_use::{PendingToolUse, ToolUse, ToolUseMetadata, ToolUseState},
};
use agent_settings::{AgentProfileId, AgentSettings, CompletionMode}; use agent_settings::{AgentProfileId, AgentSettings, CompletionMode};
use anyhow::{Result, anyhow}; use anyhow::{Result, anyhow};
use assistant_tool::{ActionLog, AnyToolCard, Tool, ToolWorkingSet}; use assistant_tool::{ActionLog, AnyToolCard, Tool, ToolWorkingSet};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use client::{ModelRequestUsage, RequestUsage}; use client::{ModelRequestUsage, RequestUsage};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use editor::display_map::CreaseMetadata;
use feature_flags::{self, FeatureFlagAppExt}; use feature_flags::{self, FeatureFlagAppExt};
use futures::future::Shared; use futures::{FutureExt, StreamExt as _, future::Shared};
use futures::{FutureExt, StreamExt as _};
use git::repository::DiffType; use git::repository::DiffType;
use gpui::{ use gpui::{
AnyWindowHandle, App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Task, AnyWindowHandle, App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Task,
WeakEntity, WeakEntity, Window,
}; };
use language_model::{ use language_model::{
ConfiguredModel, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent, ConfiguredModel, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent,
@ -27,29 +30,21 @@ use language_model::{
TokenUsage, TokenUsage,
}; };
use postage::stream::Stream as _; use postage::stream::Stream as _;
use project::Project; use project::{
use project::git_store::{GitStore, GitStoreCheckpoint, RepositoryState}; Project,
git_store::{GitStore, GitStoreCheckpoint, RepositoryState},
};
use prompt_store::{ModelContext, PromptBuilder}; use prompt_store::{ModelContext, PromptBuilder};
use proto::Plan; use proto::Plan;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::Settings; use settings::Settings;
use std::{io::Write, ops::Range, sync::Arc, time::Instant};
use thiserror::Error; use thiserror::Error;
use ui::Window;
use util::{ResultExt as _, post_inc}; use util::{ResultExt as _, post_inc};
use uuid::Uuid; use uuid::Uuid;
use zed_llm_client::{CompletionIntent, CompletionRequestStatus, UsageLimit}; 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( #[derive(
Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize, JsonSchema, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize, JsonSchema,
)] )]
@ -98,13 +93,18 @@ impl MessageId {
fn post_inc(&mut self) -> Self { fn post_inc(&mut self) -> Self {
Self(post_inc(&mut self.0)) 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. /// Stored information that can be used to resurrect a context crease when creating an editor for a past message.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MessageCrease { pub struct MessageCrease {
pub range: Range<usize>, pub range: Range<usize>,
pub metadata: CreaseMetadata, pub icon_path: SharedString,
pub label: SharedString,
/// None for a deserialized message, Some otherwise. /// None for a deserialized message, Some otherwise.
pub context: Option<AgentContextHandle>, pub context: Option<AgentContextHandle>,
} }
@ -540,10 +540,8 @@ impl Thread {
.into_iter() .into_iter()
.map(|crease| MessageCrease { .map(|crease| MessageCrease {
range: crease.start..crease.end, range: crease.start..crease.end,
metadata: CreaseMetadata { icon_path: crease.icon_path,
icon_path: crease.icon_path, label: crease.label,
label: crease.label,
},
context: None, context: None,
}) })
.collect(), .collect(),
@ -1170,8 +1168,8 @@ impl Thread {
.map(|crease| SerializedCrease { .map(|crease| SerializedCrease {
start: crease.range.start, start: crease.range.start,
end: crease.range.end, end: crease.range.end,
icon_path: crease.metadata.icon_path.clone(), icon_path: crease.icon_path.clone(),
label: crease.metadata.label.clone(), label: crease.label.clone(),
}) })
.collect(), .collect(),
is_hidden: message.is_hidden, is_hidden: message.is_hidden,
@ -2997,11 +2995,13 @@ fn resolve_tool_name_conflicts(tools: &[Arc<dyn Tool>]) -> Vec<(String, Arc<dyn
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; 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 agent_settings::{AgentProfileId, AgentSettings, LanguageModelParameters};
use assistant_tool::ToolRegistry; use assistant_tool::ToolRegistry;
use editor::EditorSettings;
use gpui::TestAppContext; use gpui::TestAppContext;
use icons::IconName;
use language_model::fake_provider::{FakeLanguageModel, FakeLanguageModelProvider}; use language_model::fake_provider::{FakeLanguageModel, FakeLanguageModelProvider};
use project::{FakeFs, Project}; use project::{FakeFs, Project};
use prompt_store::PromptBuilder; use prompt_store::PromptBuilder;
@ -3009,7 +3009,6 @@ mod tests {
use settings::{Settings, SettingsStore}; use settings::{Settings, SettingsStore};
use std::sync::Arc; use std::sync::Arc;
use theme::ThemeSettings; use theme::ThemeSettings;
use ui::IconName;
use util::path; use util::path;
use workspace::Workspace; use workspace::Workspace;
@ -3837,7 +3836,6 @@ fn main() {{
workspace::init_settings(cx); workspace::init_settings(cx);
language_model::init_settings(cx); language_model::init_settings(cx);
ThemeSettings::register(cx); ThemeSettings::register(cx);
EditorSettings::register(cx);
ToolRegistry::default_global(cx); ToolRegistry::default_global(cx);
}); });
} }

View file

@ -1,22 +1,25 @@
use std::cell::{Ref, RefCell}; use crate::{
use std::path::{Path, PathBuf}; context_server_tool::ContextServerTool,
use std::rc::Rc; thread::{
use std::sync::{Arc, Mutex}; DetailedSummaryState, ExceededWindowError, MessageId, ProjectSnapshot, Thread, ThreadId,
},
};
use agent_settings::{AgentProfileId, CompletionMode}; use agent_settings::{AgentProfileId, CompletionMode};
use anyhow::{Context as _, Result, anyhow}; use anyhow::{Context as _, Result, anyhow};
use assistant_tool::{ToolId, ToolWorkingSet}; use assistant_tool::{ToolId, ToolWorkingSet};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use collections::HashMap; use collections::HashMap;
use context_server::ContextServerId; use context_server::ContextServerId;
use futures::channel::{mpsc, oneshot}; use futures::{
use futures::future::{self, BoxFuture, Shared}; FutureExt as _, StreamExt as _,
use futures::{FutureExt as _, StreamExt as _}; channel::{mpsc, oneshot},
future::{self, BoxFuture, Shared},
};
use gpui::{ use gpui::{
App, BackgroundExecutor, Context, Entity, EventEmitter, Global, ReadGlobal, SharedString, 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 language_model::{LanguageModelToolResultContent, LanguageModelToolUseId, Role, TokenUsage};
use project::context_server_store::{ContextServerStatus, ContextServerStore}; use project::context_server_store::{ContextServerStatus, ContextServerStore};
use project::{Project, ProjectItem, ProjectPath, Worktree}; use project::{Project, ProjectItem, ProjectPath, Worktree};
@ -25,19 +28,18 @@ use prompt_store::{
UserRulesContext, WorktreeContext, UserRulesContext, WorktreeContext,
}; };
use serde::{Deserialize, Serialize}; 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::{ use sqlez::{
bindable::{Bind, Column}, bindable::{Bind, Column},
connection::Connection, connection::Connection,
statement::Statement, 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)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataType { pub enum DataType {

View file

@ -1,24 +1,23 @@
use std::sync::Arc; use crate::{
thread::{MessageId, PromptId, ThreadId},
thread_store::SerializedMessage,
};
use anyhow::Result; use anyhow::Result;
use assistant_tool::{ use assistant_tool::{
AnyToolCard, Tool, ToolResultContent, ToolResultOutput, ToolUseStatus, ToolWorkingSet, AnyToolCard, Tool, ToolResultContent, ToolResultOutput, ToolUseStatus, ToolWorkingSet,
}; };
use collections::HashMap; use collections::HashMap;
use futures::FutureExt as _; use futures::{FutureExt as _, future::Shared};
use futures::future::Shared; use gpui::{App, Entity, SharedString, Task, Window};
use gpui::{App, Entity, SharedString, Task}; use icons::IconName;
use language_model::{ use language_model::{
ConfiguredModel, LanguageModel, LanguageModelRequest, LanguageModelToolResult, ConfiguredModel, LanguageModel, LanguageModelRequest, LanguageModelToolResult,
LanguageModelToolResultContent, LanguageModelToolUse, LanguageModelToolUseId, Role, LanguageModelToolResultContent, LanguageModelToolUse, LanguageModelToolUseId, Role,
}; };
use project::Project; use project::Project;
use ui::{IconName, Window}; use std::sync::Arc;
use util::truncate_lines_to_byte_limit; use util::truncate_lines_to_byte_limit;
use crate::thread::{MessageId, PromptId, ThreadId};
use crate::thread_store::SerializedMessage;
#[derive(Debug)] #[derive(Debug)]
pub struct ToolUse { pub struct ToolUse {
pub id: LanguageModelToolUseId, pub id: LanguageModelToolUseId,
@ -26,7 +25,7 @@ pub struct ToolUse {
pub ui_text: SharedString, pub ui_text: SharedString,
pub status: ToolUseStatus, pub status: ToolUseStatus,
pub input: serde_json::Value, pub input: serde_json::Value,
pub icon: ui::IconName, pub icon: icons::IconName,
pub needs_confirmation: bool, pub needs_confirmation: bool,
} }

107
crates/agent_ui/Cargo.toml Normal file
View file

@ -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

1
crates/agent_ui/LICENSE-GPL Symbolic link
View file

@ -0,0 +1 @@
../../LICENSE-GPL

View file

@ -1,18 +1,17 @@
use crate::context::{AgentContextHandle, RULES_ICON};
use crate::context_picker::{ContextPicker, MentionLink}; use crate::context_picker::{ContextPicker, MentionLink};
use crate::context_store::ContextStore;
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind}; use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
use crate::message_editor::{extract_message_creases, insert_message_creases}; 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::{ use crate::ui::{
AddedContext, AgentNotification, AgentNotificationEvent, AnimatedLabel, ContextPill, AddedContext, AgentNotification, AgentNotificationEvent, AnimatedLabel, ContextPill,
}; };
use crate::{AgentPanel, ModelUsageContext}; 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 agent_settings::{AgentSettings, NotifyWhenAgentWaiting};
use anyhow::Context as _; use anyhow::Context as _;
use assistant_tool::ToolUseStatus; use assistant_tool::ToolUseStatus;
@ -1583,8 +1582,7 @@ impl ActiveThread {
let git_store = project.read(cx).git_store().clone(); let git_store = project.read(cx).git_store().clone();
let checkpoint = git_store.update(cx, |git_store, cx| git_store.checkpoint(cx)); let checkpoint = git_store.update(cx, |git_store, cx| git_store.checkpoint(cx));
let load_context_task = let load_context_task = context::load_context(new_context, &project, &prompt_store, cx);
crate::context::load_context(new_context, &project, &prompt_store, cx);
self._load_edited_message_context_task = self._load_edited_message_context_task =
Some(cx.spawn_in(window, async move |this, cx| { Some(cx.spawn_in(window, async move |this, cx| {
let (context, checkpoint) = let (context, checkpoint) =
@ -1737,7 +1735,7 @@ impl ActiveThread {
telemetry::event!( telemetry::event!(
"Assistant Thread Feedback Comments", "Assistant Thread Feedback Comments",
thread_id, thread_id,
message_id = message_id.0, message_id = message_id.as_usize(),
message_content, message_content,
comments = comments_value comments = comments_value
); );
@ -3723,8 +3721,10 @@ fn open_editor_at_position(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use agent::{MessageSegment, context::ContextLoadResult, thread_store};
use assistant_tool::{ToolRegistry, ToolWorkingSet}; use assistant_tool::{ToolRegistry, ToolWorkingSet};
use editor::{EditorSettings, display_map::CreaseMetadata}; use editor::EditorSettings;
use fs::FakeFs; use fs::FakeFs;
use gpui::{AppContext, TestAppContext, VisualTestContext}; use gpui::{AppContext, TestAppContext, VisualTestContext};
use language_model::{ use language_model::{
@ -3738,10 +3738,6 @@ mod tests {
use util::path; use util::path;
use workspace::CollaboratorId; use workspace::CollaboratorId;
use crate::{ContextLoadResult, thread::MessageSegment, thread_store};
use super::*;
#[gpui::test] #[gpui::test]
async fn test_agent_is_unfollowed_after_cancelling_completion(cx: &mut TestAppContext) { async fn test_agent_is_unfollowed_after_cancelling_completion(cx: &mut TestAppContext) {
init_test_settings(cx); init_test_settings(cx);
@ -3813,10 +3809,8 @@ mod tests {
let creases = vec![MessageCrease { let creases = vec![MessageCrease {
range: 14..22, range: 14..22,
metadata: CreaseMetadata { icon_path: "icon".into(),
icon_path: "icon".into(), label: "foo.txt".into(),
label: "foo.txt".into(),
},
context: None, context: None,
}]; }];

View file

@ -15,8 +15,8 @@ use workspace::{ModalView, Workspace};
use crate::agent_configuration::manage_profiles_modal::profile_modal_header::ProfileModalHeader; use crate::agent_configuration::manage_profiles_modal::profile_modal_header::ProfileModalHeader;
use crate::agent_configuration::tool_picker::{ToolPicker, ToolPickerDelegate}; use crate::agent_configuration::tool_picker::{ToolPicker, ToolPickerDelegate};
use crate::agent_profile::AgentProfile;
use crate::{AgentPanel, ManageProfiles}; use crate::{AgentPanel, ManageProfiles};
use agent::agent_profile::AgentProfile;
use super::tool_picker::ToolPickerMode; use super::tool_picker::ToolPickerMode;

View file

@ -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 agent_settings::AgentSettings;
use anyhow::Result; use anyhow::Result;
use buffer_diff::DiffHunkStatus; use buffer_diff::DiffHunkStatus;
@ -1748,7 +1749,8 @@ impl editor::Addon for EditorAgentDiffAddon {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{Keep, ThreadStore, thread_store}; use crate::Keep;
use agent::thread_store::{self, ThreadStore};
use agent_settings::AgentSettings; use agent_settings::AgentSettings;
use assistant_tool::ToolWorkingSet; use assistant_tool::ToolWorkingSet;
use editor::EditorSettings; use editor::EditorSettings;

View file

@ -45,30 +45,34 @@ use ui::{
PopoverMenuHandle, ProgressBar, Tab, Tooltip, Vector, VectorName, prelude::*, PopoverMenuHandle, ProgressBar, Tab, Tooltip, Vector, VectorName, prelude::*,
}; };
use util::ResultExt as _; use util::ResultExt as _;
use workspace::dock::{DockPosition, Panel, PanelEvent};
use workspace::{ use workspace::{
CollaboratorId, DraggedSelection, DraggedTab, ToggleZoom, ToolbarItemView, 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 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::{ use crate::{
AddContextServer, AgentDiffPane, ContextStore, ContinueThread, ContinueWithBurnMode, AddContextServer, AgentDiffPane, ContinueThread, ContinueWithBurnMode,
DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread, DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread,
NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell, NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell,
ResetTrialUpsell, TextThreadStore, ThreadEvent, ToggleBurnMode, ToggleContextPicker, ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu, ToggleOptionsMenu,
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"; const AGENT_PANEL_KEY: &str = "agent_panel";
@ -369,7 +373,7 @@ pub struct AgentPanel {
_default_model_subscription: Subscription, _default_model_subscription: Subscription,
context_store: Entity<TextThreadStore>, context_store: Entity<TextThreadStore>,
prompt_store: Option<Entity<PromptStore>>, 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: Option<Entity<AgentConfiguration>>,
configuration_subscription: Option<Subscription>, configuration_subscription: Option<Subscription>,
local_timezone: UtcOffset, local_timezone: UtcOffset,
@ -490,18 +494,10 @@ impl AgentPanel {
let workspace = workspace.weak_handle(); let workspace = workspace.weak_handle();
let weak_self = cx.entity().downgrade(); let weak_self = cx.entity().downgrade();
let message_editor_context_store = cx.new(|_cx| { let message_editor_context_store =
crate::context_store::ContextStore::new( cx.new(|_cx| ContextStore::new(project.downgrade(), Some(thread_store.downgrade())));
project.downgrade(), let inline_assist_context_store =
Some(thread_store.downgrade()), cx.new(|_cx| 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 = cx.new(|cx| { let message_editor = cx.new(|cx| {
MessageEditor::new( MessageEditor::new(
@ -708,9 +704,7 @@ impl AgentPanel {
&self.prompt_store &self.prompt_store
} }
pub(crate) fn inline_assist_context_store( pub(crate) fn inline_assist_context_store(&self) -> &Entity<ContextStore> {
&self,
) -> &Entity<crate::context_store::ContextStore> {
&self.inline_assist_context_store &self.inline_assist_context_store
} }
@ -742,7 +736,7 @@ impl AgentPanel {
self.set_active_view(thread_view, window, cx); self.set_active_view(thread_view, window, cx);
let context_store = cx.new(|_cx| { let context_store = cx.new(|_cx| {
crate::context_store::ContextStore::new( ContextStore::new(
self.project.downgrade(), self.project.downgrade(),
Some(self.thread_store.downgrade()), Some(self.thread_store.downgrade()),
) )
@ -990,7 +984,7 @@ impl AgentPanel {
let thread_view = ActiveView::thread(thread.clone(), window, cx); let thread_view = ActiveView::thread(thread.clone(), window, cx);
self.set_active_view(thread_view, window, cx); self.set_active_view(thread_view, window, cx);
let context_store = cx.new(|_cx| { let context_store = cx.new(|_cx| {
crate::context_store::ContextStore::new( ContextStore::new(
self.project.downgrade(), self.project.downgrade(),
Some(self.thread_store.downgrade()), Some(self.thread_store.downgrade()),
) )

View file

@ -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);
}
}

View file

@ -1,6 +1,8 @@
use crate::context::ContextLoadResult;
use crate::inline_prompt_editor::CodegenStatus; 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 agent_settings::AgentSettings;
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use client::telemetry::Telemetry; use client::telemetry::Telemetry;
@ -18,8 +20,7 @@ use language_model::{
use multi_buffer::MultiBufferRow; use multi_buffer::MultiBufferRow;
use parking_lot::Mutex; use parking_lot::Mutex;
use project::Project; use project::Project;
use prompt_store::PromptBuilder; use prompt_store::{PromptBuilder, PromptStore};
use prompt_store::PromptStore;
use rope::Rope; use rope::Rope;
use smol::future::FutureExt; use smol::future::FutureExt;
use std::{ use std::{

View file

@ -37,10 +37,12 @@ use uuid::Uuid;
use workspace::{Workspace, notifications::NotifyResultExt}; use workspace::{Workspace, notifications::NotifyResultExt};
use crate::AgentPanel; use crate::AgentPanel;
use crate::context::RULES_ICON; use agent::{
use crate::context_store::ContextStore; ThreadId,
use crate::thread::ThreadId; context::RULES_ICON,
use crate::thread_store::{TextThreadStore, ThreadStore}; context_store::ContextStore,
thread_store::{TextThreadStore, ThreadStore},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ContextPickerEntry { enum ContextPickerEntry {

View file

@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use agent::context_store::ContextStore;
use anyhow::Result; use anyhow::Result;
use editor::{CompletionProvider, Editor, ExcerptId, ToOffset as _}; use editor::{CompletionProvider, Editor, ExcerptId, ToOffset as _};
use file_icons::FileIcons; use file_icons::FileIcons;
@ -20,10 +21,11 @@ use ui::prelude::*;
use util::ResultExt as _; use util::ResultExt as _;
use workspace::Workspace; use workspace::Workspace;
use crate::Thread; use agent::{
use crate::context::{AgentContextHandle, AgentContextKey, ContextCreasesAddon, RULES_ICON}; Thread,
use crate::context_store::ContextStore; context::{AgentContextHandle, AgentContextKey, RULES_ICON},
use crate::thread_store::{TextThreadStore, ThreadStore}; thread_store::{TextThreadStore, ThreadStore},
};
use super::fetch_context_picker::fetch_url_content; use super::fetch_context_picker::fetch_url_content;
use super::file_context_picker::{FileMatch, search_files}; use super::file_context_picker::{FileMatch, search_files};
@ -35,6 +37,7 @@ use super::{
ContextPickerAction, ContextPickerEntry, ContextPickerMode, MentionLink, RecentEntry, ContextPickerAction, ContextPickerEntry, ContextPickerMode, MentionLink, RecentEntry,
available_context_picker_entries, recent_context_picker_entries, selection_ranges, available_context_picker_entries, recent_context_picker_entries, selection_ranges,
}; };
use crate::message_editor::ContextCreasesAddon;
pub(crate) enum Match { pub(crate) enum Match {
File(FileMatch), File(FileMatch),

View file

@ -2,6 +2,7 @@ use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use agent::context_store::ContextStore;
use anyhow::{Context as _, Result, bail}; use anyhow::{Context as _, Result, bail};
use futures::AsyncReadExt as _; use futures::AsyncReadExt as _;
use gpui::{App, DismissEvent, Entity, FocusHandle, Focusable, Task, WeakEntity}; use gpui::{App, DismissEvent, Entity, FocusHandle, Focusable, Task, WeakEntity};
@ -12,7 +13,6 @@ use ui::{Context, ListItem, Window, prelude::*};
use workspace::Workspace; use workspace::Workspace;
use crate::context_picker::ContextPicker; use crate::context_picker::ContextPicker;
use crate::context_store::ContextStore;
pub struct FetchContextPicker { pub struct FetchContextPicker {
picker: Entity<Picker<FetchContextPickerDelegate>>, picker: Entity<Picker<FetchContextPickerDelegate>>,

View file

@ -14,7 +14,7 @@ use util::ResultExt as _;
use workspace::Workspace; use workspace::Workspace;
use crate::context_picker::ContextPicker; use crate::context_picker::ContextPicker;
use crate::context_store::{ContextStore, FileInclusion}; use agent::context_store::{ContextStore, FileInclusion};
pub struct FileContextPicker { pub struct FileContextPicker {
picker: Entity<Picker<FileContextPickerDelegate>>, picker: Entity<Picker<FileContextPickerDelegate>>,

View file

@ -7,9 +7,9 @@ use prompt_store::{PromptId, PromptStore, UserPromptId};
use ui::{ListItem, prelude::*}; use ui::{ListItem, prelude::*};
use util::ResultExt as _; use util::ResultExt as _;
use crate::context::RULES_ICON;
use crate::context_picker::ContextPicker; 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 { pub struct RulesContextPicker {
picker: Entity<Picker<RulesContextPickerDelegate>>, picker: Entity<Picker<RulesContextPickerDelegate>>,

View file

@ -14,9 +14,9 @@ use ui::{ListItem, prelude::*};
use util::ResultExt as _; use util::ResultExt as _;
use workspace::Workspace; use workspace::Workspace;
use crate::context::AgentContextHandle;
use crate::context_picker::ContextPicker; use crate::context_picker::ContextPicker;
use crate::context_store::ContextStore; use agent::context::AgentContextHandle;
use agent::context_store::ContextStore;
pub struct SymbolContextPicker { pub struct SymbolContextPicker {
picker: Entity<Picker<SymbolContextPickerDelegate>>, picker: Entity<Picker<SymbolContextPickerDelegate>>,

View file

@ -9,9 +9,11 @@ use picker::{Picker, PickerDelegate};
use ui::{ListItem, prelude::*}; use ui::{ListItem, prelude::*};
use crate::context_picker::ContextPicker; use crate::context_picker::ContextPicker;
use crate::context_store::{self, ContextStore}; use agent::{
use crate::thread::ThreadId; ThreadId,
use crate::thread_store::{TextThreadStore, ThreadStore}; context_store::{self, ContextStore},
thread_store::{TextThreadStore, ThreadStore},
};
pub struct ThreadContextPicker { pub struct ThreadContextPicker {
picker: Entity<Picker<ThreadContextPickerDelegate>>, picker: Entity<Picker<ThreadContextPickerDelegate>>,

View file

@ -1,7 +1,15 @@
use std::path::Path; use crate::{
use std::rc::Rc; AcceptSuggestedContext, AgentPanel, FocusDown, FocusLeft, FocusRight, FocusUp,
ModelUsageContext, RemoveAllContext, RemoveFocusedContext, ToggleContextPicker,
use assistant_context_editor::AssistantContext; 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 collections::HashSet;
use editor::Editor; use editor::Editor;
use file_icons::FileIcons; use file_icons::FileIcons;
@ -10,22 +18,11 @@ use gpui::{
Subscription, WeakEntity, Subscription, WeakEntity,
}; };
use itertools::Itertools; use itertools::Itertools;
use language::Buffer;
use project::ProjectItem; use project::ProjectItem;
use std::{path::Path, rc::Rc};
use ui::{PopoverMenu, PopoverMenuHandle, Tooltip, prelude::*}; use ui::{PopoverMenu, PopoverMenuHandle, Tooltip, prelude::*};
use workspace::Workspace; 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 { pub struct ContextStrip {
context_store: Entity<ContextStore>, context_store: Entity<ContextStore>,
context_picker: Entity<ContextPicker>, context_picker: Entity<ContextPicker>,
@ -575,46 +572,3 @@ pub enum SuggestContextKind {
File, File,
Thread, 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,
}
}
}

View file

@ -4,18 +4,27 @@ use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; 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 agent_settings::AgentSettings;
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use client::telemetry::Telemetry; use client::telemetry::Telemetry;
use collections::{HashMap, HashSet, VecDeque, hash_map}; use collections::{HashMap, HashSet, VecDeque, hash_map};
use editor::display_map::EditorMargins;
use editor::{ use editor::{
Anchor, AnchorRangeExt, CodeActionProvider, Editor, EditorEvent, ExcerptId, ExcerptRange, Anchor, AnchorRangeExt, CodeActionProvider, Editor, EditorEvent, ExcerptId, ExcerptRange,
MultiBuffer, MultiBufferSnapshot, ToOffset as _, ToPoint, MultiBuffer, MultiBufferSnapshot, ToOffset as _, ToPoint,
actions::SelectAll, actions::SelectAll,
display_map::{ display_map::{
BlockContext, BlockPlacement, BlockProperties, BlockStyle, CustomBlockId, RenderBlock, BlockContext, BlockPlacement, BlockProperties, BlockStyle, CustomBlockId, EditorMargins,
ToDisplayPoint, RenderBlock, ToDisplayPoint,
}, },
}; };
use fs::Fs; use fs::Fs;
@ -24,16 +33,13 @@ use gpui::{
WeakEntity, Window, point, WeakEntity, Window, point,
}; };
use language::{Buffer, Point, Selection, TransactionId}; use language::{Buffer, Point, Selection, TransactionId};
use language_model::ConfigurationError; use language_model::{
use language_model::ConfiguredModel; ConfigurationError, ConfiguredModel, LanguageModelRegistry, report_assistant_event,
use language_model::{LanguageModelRegistry, report_assistant_event}; };
use multi_buffer::MultiBufferRow; use multi_buffer::MultiBufferRow;
use parking_lot::Mutex; use parking_lot::Mutex;
use project::LspAction; use project::{CodeAction, LspAction, Project, ProjectTransaction};
use project::Project; use prompt_store::{PromptBuilder, PromptStore};
use project::{CodeAction, ProjectTransaction};
use prompt_store::PromptBuilder;
use prompt_store::PromptStore;
use settings::{Settings, SettingsStore}; use settings::{Settings, SettingsStore};
use telemetry_events::{AssistantEventData, AssistantKind, AssistantPhase}; use telemetry_events::{AssistantEventData, AssistantKind, AssistantPhase};
use terminal_view::{TerminalView, terminal_panel::TerminalPanel}; 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 workspace::{ItemHandle, Toast, Workspace, dock::Panel, notifications::NotificationId};
use zed_actions::agent::OpenConfiguration; 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( pub fn init(
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
prompt_builder: Arc<PromptBuilder>, prompt_builder: Arc<PromptBuilder>,

View file

@ -1,14 +1,15 @@
use crate::agent_model_selector::AgentModelSelector; use crate::agent_model_selector::AgentModelSelector;
use crate::buffer_codegen::BufferCodegen; use crate::buffer_codegen::BufferCodegen;
use crate::context::ContextCreasesAddon;
use crate::context_picker::{ContextPicker, ContextPickerCompletionProvider}; use crate::context_picker::{ContextPicker, ContextPickerCompletionProvider};
use crate::context_store::ContextStore;
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind}; 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::terminal_codegen::TerminalCodegen;
use crate::thread_store::{TextThreadStore, ThreadStore};
use crate::{CycleNextInlineAssist, CyclePreviousInlineAssist, ModelUsageContext}; use crate::{CycleNextInlineAssist, CyclePreviousInlineAssist, ModelUsageContext};
use crate::{RemoveAllContext, ToggleContextPicker}; use crate::{RemoveAllContext, ToggleContextPicker};
use agent::{
context_store::ContextStore,
thread_store::{TextThreadStore, ThreadStore},
};
use assistant_context_editor::language_model_selector::ToggleModelSelector; use assistant_context_editor::language_model_selector::ToggleModelSelector;
use client::ErrorExt; use client::ErrorExt;
use collections::VecDeque; use collections::VecDeque;

View file

@ -3,21 +3,25 @@ use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use crate::agent_model_selector::AgentModelSelector; use crate::agent_model_selector::AgentModelSelector;
use crate::context::{AgentContextKey, ContextCreasesAddon, ContextLoadResult, load_context};
use crate::tool_compatibility::{IncompatibleToolsState, IncompatibleToolsTooltip}; use crate::tool_compatibility::{IncompatibleToolsState, IncompatibleToolsTooltip};
use crate::ui::{ use crate::ui::{
MaxModeTooltip, MaxModeTooltip,
preview::{AgentPreview, UsageCallout}, preview::{AgentPreview, UsageCallout},
}; };
use agent::{
context::{AgentContextKey, ContextLoadResult, load_context},
context_store::ContextStoreEvent,
};
use agent_settings::{AgentSettings, CompletionMode}; use agent_settings::{AgentSettings, CompletionMode};
use assistant_context_editor::language_model_selector::ToggleModelSelector; use assistant_context_editor::language_model_selector::ToggleModelSelector;
use buffer_diff::BufferDiff; use buffer_diff::BufferDiff;
use client::UserStore; use client::UserStore;
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use editor::actions::{MoveUp, Paste}; use editor::actions::{MoveUp, Paste};
use editor::display_map::CreaseId;
use editor::{ use editor::{
AnchorRangeExt, ContextMenuOptions, ContextMenuPlacement, Editor, EditorElement, EditorEvent, Addon, AnchorRangeExt, ContextMenuOptions, ContextMenuPlacement, Editor, EditorElement,
EditorMode, EditorStyle, MultiBuffer, EditorEvent, EditorMode, EditorStyle, MultiBuffer,
}; };
use file_icons::FileIcons; use file_icons::FileIcons;
use fs::Fs; use fs::Fs;
@ -46,16 +50,18 @@ use workspace::{CollaboratorId, Workspace};
use zed_llm_client::CompletionIntent; use zed_llm_client::CompletionIntent;
use crate::context_picker::{ContextPicker, ContextPickerCompletionProvider, crease_for_mention}; use crate::context_picker::{ContextPicker, ContextPickerCompletionProvider, crease_for_mention};
use crate::context_store::ContextStore;
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind}; use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
use crate::profile_selector::ProfileSelector; use crate::profile_selector::ProfileSelector;
use crate::thread::{MessageCrease, Thread, TokenUsageRatio};
use crate::thread_store::{TextThreadStore, ThreadStore};
use crate::{ use crate::{
ActiveThread, AgentDiffPane, Chat, ChatWithFollow, ExpandMessageEditor, Follow, KeepAll, ActiveThread, AgentDiffPane, Chat, ChatWithFollow, ExpandMessageEditor, Follow, KeepAll,
ModelUsageContext, NewThread, OpenAgentDiff, RejectAll, RemoveAllContext, ToggleBurnMode, ModelUsageContext, NewThread, OpenAgentDiff, RejectAll, RemoveAllContext, ToggleBurnMode,
ToggleContextPicker, ToggleProfileSelector, register_agent_preview, ToggleContextPicker, ToggleProfileSelector, register_agent_preview,
}; };
use agent::{
MessageCrease, Thread, TokenUsageRatio,
context_store::ContextStore,
thread_store::{TextThreadStore, ThreadStore},
};
#[derive(RegisterComponent)] #[derive(RegisterComponent)]
pub struct MessageEditor { 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( pub fn extract_message_creases(
editor: &mut Editor, editor: &mut Editor,
cx: &mut Context<'_, Editor>, cx: &mut Context<'_, Editor>,
@ -1504,8 +1573,9 @@ pub fn extract_message_creases(
let context = contexts_by_crease_id.remove(&id); let context = contexts_by_crease_id.remove(&id);
MessageCrease { MessageCrease {
range, range,
metadata,
context, context,
label: metadata.label,
icon_path: metadata.icon_path,
} }
}) })
.collect() .collect()
@ -1577,8 +1647,8 @@ pub fn insert_message_creases(
let start = buffer_snapshot.anchor_after(crease.range.start); let start = buffer_snapshot.anchor_after(crease.range.start);
let end = buffer_snapshot.anchor_before(crease.range.end); let end = buffer_snapshot.anchor_before(crease.range.end);
crease_for_mention( crease_for_mention(
crease.metadata.label.clone(), crease.label.clone(),
crease.metadata.icon_path.clone(), crease.icon_path.clone(),
start..end, start..end,
cx.weak_entity(), cx.weak_entity(),
) )
@ -1590,12 +1660,7 @@ pub fn insert_message_creases(
for (crease, id) in message_creases.iter().zip(ids) { for (crease, id) in message_creases.iter().zip(ids) {
if let Some(context) = crease.context.as_ref() { if let Some(context) = crease.context.as_ref() {
let key = AgentContextKey(context.clone()); let key = AgentContextKey(context.clone());
addon.add_creases( addon.add_creases(context_store, key, vec![(id, crease.label.clone())], cx);
context_store,
key,
vec![(id, crease.metadata.label.clone())],
cx,
);
} }
} }
} }

View file

@ -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 agent_settings::{AgentDockPosition, AgentProfileId, AgentSettings, builtin_profiles};
use fs::Fs; use fs::Fs;
use gpui::{Action, Empty, Entity, FocusHandle, Subscription, prelude::*}; use gpui::{Action, Empty, Entity, FocusHandle, Subscription, prelude::*};
use language_model::LanguageModelRegistry; use language_model::LanguageModelRegistry;
use settings::{Settings as _, SettingsStore, update_settings_file}; use settings::{Settings as _, SettingsStore, update_settings_file};
use std::sync::Arc;
use ui::{ use ui::{
ContextMenu, ContextMenuEntry, DocumentationSide, PopoverMenu, PopoverMenuHandle, Tooltip, ContextMenu, ContextMenuEntry, DocumentationSide, PopoverMenu, PopoverMenuHandle, Tooltip,
prelude::*, prelude::*,
}; };
use crate::{
ManageProfiles, Thread, ToggleProfileSelector,
agent_profile::{AgentProfile, AvailableProfiles},
};
pub struct ProfileSelector { pub struct ProfileSelector {
profiles: AvailableProfiles, profiles: AvailableProfiles,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,

View file

@ -1,10 +1,12 @@
use crate::context::load_context;
use crate::context_store::ContextStore;
use crate::inline_prompt_editor::{ use crate::inline_prompt_editor::{
CodegenStatus, PromptEditor, PromptEditorEvent, TerminalInlineAssistId, CodegenStatus, PromptEditor, PromptEditorEvent, TerminalInlineAssistId,
}; };
use crate::terminal_codegen::{CLEAR_INPUT, CodegenEvent, TerminalCodegen}; 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 agent_settings::AgentSettings;
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use client::telemetry::Telemetry; use client::telemetry::Telemetry;

View file

@ -1,7 +1,5 @@
use std::fmt::Display; use crate::{AgentPanel, RemoveSelectedThread};
use std::ops::Range; use agent::history_store::{HistoryEntry, HistoryStore};
use std::sync::Arc;
use chrono::{Datelike as _, Local, NaiveDate, TimeDelta}; use chrono::{Datelike as _, Local, NaiveDate, TimeDelta};
use editor::{Editor, EditorEvent}; use editor::{Editor, EditorEvent};
use fuzzy::{StringMatch, StringMatchCandidate}; use fuzzy::{StringMatch, StringMatchCandidate};
@ -9,6 +7,7 @@ use gpui::{
App, ClickEvent, Empty, Entity, FocusHandle, Focusable, ScrollStrategy, Stateful, Task, App, ClickEvent, Empty, Entity, FocusHandle, Focusable, ScrollStrategy, Stateful, Task,
UniformListScrollHandle, WeakEntity, Window, uniform_list, UniformListScrollHandle, WeakEntity, Window, uniform_list,
}; };
use std::{fmt::Display, ops::Range, sync::Arc};
use time::{OffsetDateTime, UtcOffset}; use time::{OffsetDateTime, UtcOffset};
use ui::{ use ui::{
HighlightedLabel, IconButtonShape, ListItem, ListItemSpacing, Scrollbar, ScrollbarState, HighlightedLabel, IconButtonShape, ListItem, ListItemSpacing, Scrollbar, ScrollbarState,
@ -16,9 +15,6 @@ use ui::{
}; };
use util::ResultExt; use util::ResultExt;
use crate::history_store::{HistoryEntry, HistoryStore};
use crate::{AgentPanel, RemoveSelectedThread};
pub struct ThreadHistory { pub struct ThreadHistory {
agent_panel: WeakEntity<AgentPanel>, agent_panel: WeakEntity<AgentPanel>,
history_store: Entity<HistoryStore>, history_store: Entity<HistoryStore>,

View file

@ -1,13 +1,11 @@
use std::sync::Arc; use agent::{Thread, ThreadEvent};
use assistant_tool::{Tool, ToolSource}; use assistant_tool::{Tool, ToolSource};
use collections::HashMap; use collections::HashMap;
use gpui::{App, Context, Entity, IntoElement, Render, Subscription, Window}; use gpui::{App, Context, Entity, IntoElement, Render, Subscription, Window};
use language_model::{LanguageModel, LanguageModelToolSchemaFormat}; use language_model::{LanguageModel, LanguageModelToolSchemaFormat};
use std::sync::Arc;
use ui::prelude::*; use ui::prelude::*;
use crate::{Thread, ThreadEvent};
pub struct IncompatibleToolsState { pub struct IncompatibleToolsState {
cache: HashMap<LanguageModelToolSchemaFormat, Vec<Arc<dyn Tool>>>, cache: HashMap<LanguageModelToolSchemaFormat, Vec<Arc<dyn Tool>>>,
thread: Entity<Thread>, thread: Entity<Thread>,

View file

@ -12,7 +12,7 @@ use prompt_store::PromptStore;
use rope::Point; use rope::Point;
use ui::{IconButtonShape, Tooltip, prelude::*, tooltip_container}; use ui::{IconButtonShape, Tooltip, prelude::*, tooltip_container};
use crate::context::{ use agent::context::{
AgentContext, AgentContextHandle, ContextId, ContextKind, DirectoryContext, AgentContext, AgentContextHandle, ContextId, ContextKind, DirectoryContext,
DirectoryContextHandle, FetchedUrlContext, FileContext, FileContextHandle, ImageContext, DirectoryContextHandle, FetchedUrlContext, FileContext, FileContextHandle, ImageContext,
ImageStatus, RulesContext, RulesContextHandle, SelectionContext, SelectionContextHandle, ImageStatus, RulesContext, RulesContextHandle, SelectionContext, SelectionContextHandle,

View file

@ -19,6 +19,7 @@ path = "src/explorer.rs"
[dependencies] [dependencies]
agent.workspace = true agent.workspace = true
agent_ui.workspace = true
agent_settings.workspace = true agent_settings.workspace = true
anyhow.workspace = true anyhow.workspace = true
assistant_tool.workspace = true assistant_tool.workspace = true

View file

@ -423,7 +423,7 @@ pub fn init(cx: &mut App) -> Arc<AgentAppState> {
terminal_view::init(cx); terminal_view::init(cx);
let stdout_is_a_pty = false; let stdout_is_a_pty = false;
let prompt_builder = PromptBuilder::load(fs.clone(), stdout_is_a_pty, cx); let prompt_builder = PromptBuilder::load(fs.clone(), stdout_is_a_pty, cx);
agent::init( agent_ui::init(
fs.clone(), fs.clone(),
client.clone(), client.clone(),
prompt_builder.clone(), prompt_builder.clone(),

View file

@ -100,7 +100,7 @@ impl ExampleContext {
pub fn new( pub fn new(
meta: ExampleMetadata, meta: ExampleMetadata,
log_prefix: String, log_prefix: String,
agent_thread: Entity<agent::Thread>, agent_thread: Entity<Thread>,
model: Arc<dyn LanguageModel>, model: Arc<dyn LanguageModel>,
app: AsyncApp, app: AsyncApp,
) -> Self { ) -> Self {

View file

@ -21,6 +21,7 @@ path = "src/main.rs"
[dependencies] [dependencies]
activity_indicator.workspace = true activity_indicator.workspace = true
agent.workspace = true agent.workspace = true
agent_ui.workspace = true
agent_settings.workspace = true agent_settings.workspace = true
anyhow.workspace = true anyhow.workspace = true
askpass.workspace = true askpass.workspace = true

View file

@ -531,7 +531,7 @@ pub fn main() {
cx, cx,
); );
let prompt_builder = PromptBuilder::load(app_state.fs.clone(), stdout_is_a_pty(), 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.fs.clone(),
app_state.client.clone(), app_state.client.clone(),
prompt_builder.clone(), prompt_builder.clone(),

View file

@ -9,7 +9,7 @@ mod quick_action_bar;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub(crate) mod windows_only_instance; pub(crate) mod windows_only_instance;
use agent::AgentDiffToolbar; use agent_ui::AgentDiffToolbar;
use anyhow::Context as _; use anyhow::Context as _;
pub use app_menus::*; pub use app_menus::*;
use assets::Assets; use assets::Assets;
@ -515,7 +515,7 @@ fn initialize_panels(
let is_assistant2_enabled = !cfg!(test); let is_assistant2_enabled = !cfg!(test);
let agent_panel = if is_assistant2_enabled { let agent_panel = if is_assistant2_enabled {
let agent_panel = 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?; .await?;
Some(agent_panel) 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`. // Once we ship `assistant2` we can push this back down into `agent::agent_panel::init`.
if is_assistant2_enabled { if is_assistant2_enabled {
<dyn AgentPanelDelegate>::set_global( <dyn AgentPanelDelegate>::set_global(
Arc::new(agent::ConcreteAssistantPanelDelegate), Arc::new(agent_ui::ConcreteAssistantPanelDelegate),
cx, cx,
); );
workspace workspace
.register_action(agent::AgentPanel::toggle_focus) .register_action(agent_ui::AgentPanel::toggle_focus)
.register_action(agent::InlineAssistant::inline_assist); .register_action(agent_ui::InlineAssistant::inline_assist);
} }
})?; })?;
@ -4320,7 +4320,7 @@ mod tests {
web_search::init(cx); web_search::init(cx);
web_search_providers::init(app_state.client.clone(), cx); web_search_providers::init(app_state.client.clone(), cx);
let prompt_builder = PromptBuilder::load(app_state.fs.clone(), false, cx); let prompt_builder = PromptBuilder::load(app_state.fs.clone(), false, cx);
agent::init( agent_ui::init(
app_state.fs.clone(), app_state.fs.clone(),
app_state.client.clone(), app_state.client.clone(),
prompt_builder.clone(), prompt_builder.clone(),

View file

@ -5,20 +5,14 @@
mod persistence; mod persistence;
mod preview_support; mod preview_support;
use std::ops::Range; use agent::{TextThreadStore, ThreadStore};
use std::sync::Arc; use agent_ui::ActiveThread;
use std::iter::Iterator;
use agent::{ActiveThread, TextThreadStore, ThreadStore};
use client::UserStore; use client::UserStore;
use collections::HashMap;
use component::{ComponentId, ComponentMetadata, ComponentStatus, components}; use component::{ComponentId, ComponentMetadata, ComponentStatus, components};
use gpui::{ use gpui::{
App, Entity, EventEmitter, FocusHandle, Focusable, Task, WeakEntity, Window, list, prelude::*, App, Entity, EventEmitter, FocusHandle, Focusable, Task, WeakEntity, Window, list, prelude::*,
}; };
use collections::HashMap;
use gpui::{ListState, ScrollHandle, ScrollStrategy, UniformListScrollHandle}; use gpui::{ListState, ScrollHandle, ScrollStrategy, UniformListScrollHandle};
use languages::LanguageRegistry; use languages::LanguageRegistry;
use notifications::status_toast::{StatusToast, ToastIcon}; 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, load_preview_text_thread_store, load_preview_thread_store, static_active_thread,
}; };
use project::Project; use project::Project;
use std::{iter::Iterator, ops::Range, sync::Arc};
use ui::{ButtonLike, Divider, HighlightedLabel, ListItem, ListSubHeader, Tooltip, prelude::*}; use ui::{ButtonLike, Divider, HighlightedLabel, ListItem, ListSubHeader, Tooltip, prelude::*};
use ui_input::SingleLineInput; use ui_input::SingleLineInput;
use util::ResultExt as _; use util::ResultExt as _;
use workspace::{AppState, ItemId, SerializableItem, delete_unloaded_items}; use workspace::{
use workspace::{Item, Workspace, WorkspaceId, item::ItemEvent}; AppState, Item, ItemId, SerializableItem, Workspace, WorkspaceId, delete_unloaded_items,
item::ItemEvent,
};
pub fn init(app_state: Arc<AppState>, cx: &mut App) { pub fn init(app_state: Arc<AppState>, cx: &mut App) {
workspace::register_serializable_item::<ComponentPreview>(cx); workspace::register_serializable_item::<ComponentPreview>(cx);
@ -642,7 +639,7 @@ impl ComponentPreview {
// Check if the component's scope is Agent // Check if the component's scope is Agent
if scope == ComponentScope::Agent { if scope == ComponentScope::Agent {
if let Some(active_thread) = self.active_thread.clone() { 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(), &component.id(),
self.workspace.clone(), self.workspace.clone(),
active_thread, active_thread,
@ -1140,7 +1137,7 @@ impl ComponentPreviewPage {
fn render_preview(&self, window: &mut Window, cx: &mut App) -> impl IntoElement { fn render_preview(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
// Try to get agent preview first if we have an active thread // 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() { 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.component.id(),
self.workspace.clone(), self.workspace.clone(),
active_thread.clone(), active_thread.clone(),

View file

@ -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 anyhow::{Result, anyhow};
use assistant_tool::ToolWorkingSet; use assistant_tool::ToolWorkingSet;
use gpui::{AppContext, AsyncApp, Entity, Task, WeakEntity}; use gpui::{AppContext, AsyncApp, Entity, Task, WeakEntity};