Factor tool definitions out of assistant (#21189)

This PR factors the tool definitions out of the `assistant` crate so
that they can be shared between `assistant` and `assistant2`.

`ToolWorkingSet` now lives in `assistant_tool`. The tool definitions
themselves live in `assistant_tools`, with the exception of the
`ContextServerTool`, which has been moved to the `context_server` crate.

As part of this refactoring I needed to extract the
`ContextServerSettings` to a separate `context_server_settings` crate so
that the `extension_host`—which is referenced by the `remote_server`—can
name the `ContextServerSettings` type without pulling in some undesired
dependencies.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-11-25 18:26:34 -05:00 committed by GitHub
parent 321fd19763
commit 3901d46101
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 219 additions and 113 deletions

42
Cargo.lock generated
View file

@ -383,7 +383,7 @@ dependencies = [
"clock",
"collections",
"command_palette_hooks",
"context_servers",
"context_server",
"ctor",
"db",
"editor",
@ -506,6 +506,20 @@ dependencies = [
"workspace",
]
[[package]]
name = "assistant_tools"
version = "0.1.0"
dependencies = [
"anyhow",
"assistant_tool",
"chrono",
"gpui",
"schemars",
"serde",
"serde_json",
"workspace",
]
[[package]]
name = "async-attributes"
version = "1.1.2"
@ -2613,6 +2627,7 @@ dependencies = [
"anthropic",
"anyhow",
"assistant",
"assistant_tool",
"async-stripe",
"async-trait",
"async-tungstenite 0.28.0",
@ -2631,7 +2646,7 @@ dependencies = [
"clock",
"collab_ui",
"collections",
"context_servers",
"context_server",
"ctor",
"dashmap 6.1.0",
"derive_more",
@ -2874,12 +2889,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
[[package]]
name = "context_servers"
name = "context_server"
version = "0.1.0"
dependencies = [
"anyhow",
"assistant_tool",
"collections",
"command_palette_hooks",
"context_server_settings",
"extension",
"futures 0.3.31",
"gpui",
@ -2887,13 +2904,27 @@ dependencies = [
"parking_lot",
"postage",
"project",
"schemars",
"serde",
"serde_json",
"settings",
"smol",
"ui",
"url",
"util",
"workspace",
]
[[package]]
name = "context_server_settings"
version = "0.1.0"
dependencies = [
"anyhow",
"collections",
"gpui",
"schemars",
"serde",
"serde_json",
"settings",
]
[[package]]
@ -4209,7 +4240,7 @@ dependencies = [
"async-trait",
"client",
"collections",
"context_servers",
"context_server_settings",
"ctor",
"env_logger 0.11.5",
"extension",
@ -15586,6 +15617,7 @@ dependencies = [
"assets",
"assistant",
"assistant2",
"assistant_tools",
"async-watch",
"audio",
"auto_update",

View file

@ -8,6 +8,7 @@ members = [
"crates/assistant2",
"crates/assistant_slash_command",
"crates/assistant_tool",
"crates/assistant_tools",
"crates/audio",
"crates/auto_update",
"crates/auto_update_ui",
@ -22,7 +23,8 @@ members = [
"crates/collections",
"crates/command_palette",
"crates/command_palette_hooks",
"crates/context_servers",
"crates/context_server",
"crates/context_server_settings",
"crates/copilot",
"crates/db",
"crates/diagnostics",
@ -191,6 +193,7 @@ assistant = { path = "crates/assistant" }
assistant2 = { path = "crates/assistant2" }
assistant_slash_command = { path = "crates/assistant_slash_command" }
assistant_tool = { path = "crates/assistant_tool" }
assistant_tools = { path = "crates/assistant_tools" }
audio = { path = "crates/audio" }
auto_update = { path = "crates/auto_update" }
auto_update_ui = { path = "crates/auto_update_ui" }
@ -205,7 +208,8 @@ collab_ui = { path = "crates/collab_ui" }
collections = { path = "crates/collections" }
command_palette = { path = "crates/command_palette" }
command_palette_hooks = { path = "crates/command_palette_hooks" }
context_servers = { path = "crates/context_servers" }
context_server = { path = "crates/context_server" }
context_server_settings = { path = "crates/context_server_settings" }
copilot = { path = "crates/copilot" }
db = { path = "crates/db" }
diagnostics = { path = "crates/diagnostics" }

View file

@ -33,7 +33,7 @@ client.workspace = true
clock.workspace = true
collections.workspace = true
command_palette_hooks.workspace = true
context_servers.workspace = true
context_server.workspace = true
db.workspace = true
editor.workspace = true
feature_flags.workspace = true

View file

@ -14,16 +14,12 @@ pub mod slash_command_settings;
mod slash_command_working_set;
mod streaming_diff;
mod terminal_inline_assistant;
mod tool_working_set;
mod tools;
use crate::slash_command::project_command::ProjectSlashCommandFeatureFlag;
pub use crate::slash_command_working_set::{SlashCommandId, SlashCommandWorkingSet};
pub use crate::tool_working_set::{ToolId, ToolWorkingSet};
pub use assistant_panel::{AssistantPanel, AssistantPanelEvent};
use assistant_settings::AssistantSettings;
use assistant_slash_command::SlashCommandRegistry;
use assistant_tool::ToolRegistry;
use client::{proto, Client};
use command_palette_hooks::CommandPaletteFilter;
pub use context::*;
@ -246,7 +242,7 @@ pub fn init(
assistant_slash_command::init(cx);
assistant_tool::init(cx);
assistant_panel::init(cx);
context_servers::init(cx);
context_server::init(cx);
let prompt_builder = prompts::PromptBuilder::new(Some(PromptLoadingParams {
fs: fs.clone(),
@ -259,7 +255,6 @@ pub fn init(
.map(Arc::new)
.unwrap_or_else(|| Arc::new(prompts::PromptBuilder::new(None).unwrap()));
register_slash_commands(Some(prompt_builder.clone()), cx);
register_tools(cx);
inline_assistant::init(
fs.clone(),
prompt_builder.clone(),
@ -423,11 +418,6 @@ fn update_slash_commands_from_settings(cx: &mut AppContext) {
}
}
fn register_tools(cx: &mut AppContext) {
let tool_registry = ToolRegistry::global(cx);
tool_registry.register_tool(tools::now_tool::NowTool);
}
pub fn humanize_token_count(count: usize) -> String {
match count {
0..=999 => count.to_string(),

View file

@ -1,6 +1,5 @@
use crate::slash_command::file_command::codeblock_fence_for_path;
use crate::slash_command_working_set::SlashCommandWorkingSet;
use crate::ToolWorkingSet;
use crate::{
assistant_settings::{AssistantDockPosition, AssistantSettings},
humanize_token_count,
@ -23,6 +22,7 @@ use crate::{
};
use anyhow::Result;
use assistant_slash_command::{SlashCommand, SlashCommandOutputSection};
use assistant_tool::ToolWorkingSet;
use client::{proto, zed_urls, Client, Status};
use collections::{hash_map, BTreeSet, HashMap, HashSet};
use editor::{
@ -1316,7 +1316,7 @@ impl AssistantPanel {
fn restart_context_servers(
workspace: &mut Workspace,
_action: &context_servers::Restart,
_action: &context_server::Restart,
cx: &mut ViewContext<Workspace>,
) {
let Some(assistant_panel) = workspace.panel::<AssistantPanel>(cx) else {

View file

@ -2,7 +2,6 @@
mod context_tests;
use crate::slash_command_working_set::SlashCommandWorkingSet;
use crate::ToolWorkingSet;
use crate::{
prompts::PromptBuilder,
slash_command::{file_command::FileCommandMetadata, SlashCommandLine},
@ -12,6 +11,7 @@ use anyhow::{anyhow, Context as _, Result};
use assistant_slash_command::{
SlashCommandContent, SlashCommandEvent, SlashCommandOutputSection, SlashCommandResult,
};
use assistant_tool::ToolWorkingSet;
use client::{self, proto, telemetry::Telemetry};
use clock::ReplicaId;
use collections::{HashMap, HashSet};

View file

@ -1,6 +1,5 @@
use super::{AssistantEdit, MessageCacheMetadata};
use crate::slash_command_working_set::SlashCommandWorkingSet;
use crate::ToolWorkingSet;
use crate::{
assistant_panel, prompt_library, slash_command::file_command, AssistantEditKind, CacheStatus,
Context, ContextEvent, ContextId, ContextOperation, InvokedSlashCommandId, MessageId,
@ -11,6 +10,7 @@ use assistant_slash_command::{
ArgumentCompletion, SlashCommand, SlashCommandContent, SlashCommandEvent, SlashCommandOutput,
SlashCommandOutputSection, SlashCommandRegistry, SlashCommandResult,
};
use assistant_tool::ToolWorkingSet;
use collections::{HashMap, HashSet};
use fs::FakeFs;
use futures::{

View file

@ -1,15 +1,16 @@
use crate::slash_command::context_server_command;
use crate::SlashCommandId;
use crate::{
prompts::PromptBuilder, slash_command_working_set::SlashCommandWorkingSet, Context,
ContextEvent, ContextId, ContextOperation, ContextVersion, SavedContext, SavedContextMetadata,
};
use crate::{tools, SlashCommandId, ToolId, ToolWorkingSet};
use anyhow::{anyhow, Context as _, Result};
use assistant_tool::{ToolId, ToolWorkingSet};
use client::{proto, telemetry::Telemetry, Client, TypedEnvelope};
use clock::ReplicaId;
use collections::HashMap;
use context_servers::manager::ContextServerManager;
use context_servers::ContextServerFactoryRegistry;
use context_server::manager::ContextServerManager;
use context_server::{ContextServerFactoryRegistry, ContextServerTool};
use fs::Fs;
use futures::StreamExt;
use fuzzy::StringMatchCandidate;
@ -808,13 +809,13 @@ impl ContextStore {
fn handle_context_server_event(
&mut self,
context_server_manager: Model<ContextServerManager>,
event: &context_servers::manager::Event,
event: &context_server::manager::Event,
cx: &mut ModelContext<Self>,
) {
let slash_command_working_set = self.slash_commands.clone();
let tool_working_set = self.tools.clone();
match event {
context_servers::manager::Event::ServerStarted { server_id } => {
context_server::manager::Event::ServerStarted { server_id } => {
if let Some(server) = context_server_manager.read(cx).get_server(server_id) {
let context_server_manager = context_server_manager.clone();
cx.spawn({
@ -825,7 +826,7 @@ impl ContextStore {
return;
};
if protocol.capable(context_servers::protocol::ServerCapability::Prompts) {
if protocol.capable(context_server::protocol::ServerCapability::Prompts) {
if let Some(prompts) = protocol.list_prompts().await.log_err() {
let slash_command_ids = prompts
.into_iter()
@ -853,12 +854,12 @@ impl ContextStore {
}
}
if protocol.capable(context_servers::protocol::ServerCapability::Tools) {
if protocol.capable(context_server::protocol::ServerCapability::Tools) {
if let Some(tools) = protocol.list_tools().await.log_err() {
let tool_ids = tools.tools.into_iter().map(|tool| {
log::info!("registering context server tool: {:?}", tool.name);
tool_working_set.insert(
Arc::new(tools::context_server_tool::ContextServerTool::new(
Arc::new(ContextServerTool::new(
context_server_manager.clone(),
server.id(),
tool,
@ -880,7 +881,7 @@ impl ContextStore {
.detach();
}
}
context_servers::manager::Event::ServerStopped { server_id } => {
context_server::manager::Event::ServerStopped { server_id } => {
if let Some(slash_command_ids) =
self.context_server_slash_command_ids.remove(server_id)
{

View file

@ -4,7 +4,7 @@ use assistant_slash_command::{
SlashCommandOutputSection, SlashCommandResult,
};
use collections::HashMap;
use context_servers::{
use context_server::{
manager::{ContextServer, ContextServerManager},
types::Prompt,
};
@ -95,9 +95,9 @@ impl SlashCommand for ContextServerSlashCommand {
let completion_result = protocol
.completion(
context_servers::types::CompletionReference::Prompt(
context_servers::types::PromptReference {
r#type: context_servers::types::PromptReferenceType::Prompt,
context_server::types::CompletionReference::Prompt(
context_server::types::PromptReference {
r#type: context_server::types::PromptReferenceType::Prompt,
name: prompt_name,
},
),
@ -152,7 +152,7 @@ impl SlashCommand for ContextServerSlashCommand {
if result
.messages
.iter()
.any(|msg| !matches!(msg.role, context_servers::types::Role::User))
.any(|msg| !matches!(msg.role, context_server::types::Role::User))
{
return Err(anyhow!(
"Prompt contains non-user roles, which is not supported"
@ -164,7 +164,7 @@ impl SlashCommand for ContextServerSlashCommand {
.messages
.into_iter()
.filter_map(|msg| match msg.content {
context_servers::types::MessageContent::Text { text } => Some(text),
context_server::types::MessageContent::Text { text } => Some(text),
_ => None,
})
.collect::<Vec<String>>()

View file

@ -1,2 +0,0 @@
pub mod context_server_tool;
pub mod now_tool;

View file

@ -1,4 +1,5 @@
mod tool_registry;
mod tool_working_set;
use std::sync::Arc;
@ -6,7 +7,8 @@ use anyhow::Result;
use gpui::{AppContext, Task, WeakView, WindowContext};
use workspace::Workspace;
pub use tool_registry::*;
pub use crate::tool_registry::*;
pub use crate::tool_working_set::*;
pub fn init(cx: &mut AppContext) {
ToolRegistry::default_global(cx);

View file

@ -1,8 +1,10 @@
use assistant_tool::{Tool, ToolRegistry};
use std::sync::Arc;
use collections::HashMap;
use gpui::AppContext;
use parking_lot::Mutex;
use std::sync::Arc;
use crate::{Tool, ToolRegistry};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Default)]
pub struct ToolId(usize);

View file

@ -0,0 +1,22 @@
[package]
name = "assistant_tools"
version = "0.1.0"
edition = "2021"
publish = false
license = "GPL-3.0-or-later"
[lints]
workspace = true
[lib]
path = "src/assistant_tools.rs"
[dependencies]
anyhow.workspace = true
assistant_tool.workspace = true
chrono.workspace = true
gpui.workspace = true
schemars.workspace = true
serde.workspace = true
serde_json.workspace = true
workspace.workspace = true

View file

@ -0,0 +1,13 @@
mod now_tool;
use assistant_tool::ToolRegistry;
use gpui::AppContext;
use crate::now_tool::NowTool;
pub fn init(cx: &mut AppContext) {
assistant_tool::init(cx);
let registry = ToolRegistry::global(cx);
registry.register_tool(NowTool);
}

View file

@ -79,7 +79,8 @@ uuid.workspace = true
[dev-dependencies]
assistant = { workspace = true, features = ["test-support"] }
context_servers.workspace = true
assistant_tool.workspace = true
context_server.workspace = true
async-trait.workspace = true
audio.workspace = true
call = { workspace = true, features = ["test-support"] }

View file

@ -6,7 +6,8 @@ use crate::{
},
};
use anyhow::{anyhow, Result};
use assistant::{ContextStore, PromptBuilder, SlashCommandWorkingSet, ToolWorkingSet};
use assistant::{ContextStore, PromptBuilder, SlashCommandWorkingSet};
use assistant_tool::ToolWorkingSet;
use call::{room, ActiveCall, ParticipantLocation, Room};
use client::{User, RECEIVE_TIMEOUT};
use collections::{HashMap, HashSet};
@ -6486,8 +6487,8 @@ async fn test_context_collaboration_with_reconnect(
assert_eq!(project.collaborators().len(), 1);
});
cx_a.update(context_servers::init);
cx_b.update(context_servers::init);
cx_a.update(context_server::init);
cx_b.update(context_server::init);
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
let context_store_a = cx_a
.update(|cx| {

View file

@ -1,5 +1,5 @@
[package]
name = "context_servers"
name = "context_server"
version = "0.1.0"
edition = "2021"
publish = false
@ -9,12 +9,14 @@ license = "GPL-3.0-or-later"
workspace = true
[lib]
path = "src/context_servers.rs"
path = "src/context_server.rs"
[dependencies]
anyhow.workspace = true
assistant_tool.workspace = true
collections.workspace = true
command_palette_hooks.workspace = true
context_server_settings.workspace = true
extension.workspace = true
futures.workspace = true
gpui.workspace = true
@ -22,10 +24,11 @@ log.workspace = true
parking_lot.workspace = true
postage.workspace = true
project.workspace = true
schemars.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
smol.workspace = true
ui.workspace = true
url = { workspace = true, features = ["serde"] }
util.workspace = true
workspace.workspace = true

View file

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

View file

@ -1,4 +1,5 @@
pub mod client;
mod context_server_tool;
mod extension_context_server;
pub mod manager;
pub mod protocol;
@ -6,10 +7,10 @@ mod registry;
pub mod types;
use command_palette_hooks::CommandPaletteFilter;
pub use context_server_settings::{ContextServerSettings, ServerCommand, ServerConfig};
use gpui::{actions, AppContext};
use settings::Settings;
use crate::manager::ContextServerSettings;
pub use crate::context_server_tool::ContextServerTool;
pub use crate::registry::ContextServerFactoryRegistry;
actions!(context_servers, [Restart]);
@ -18,7 +19,7 @@ actions!(context_servers, [Restart]);
pub const CONTEXT_SERVERS_NAMESPACE: &'static str = "context_servers";
pub fn init(cx: &mut AppContext) {
ContextServerSettings::register(cx);
context_server_settings::init(cx);
ContextServerFactoryRegistry::default_global(cx);
extension_context_server::init(cx);

View file

@ -2,10 +2,11 @@ use std::sync::Arc;
use anyhow::{anyhow, bail};
use assistant_tool::Tool;
use context_servers::manager::ContextServerManager;
use context_servers::types;
use gpui::{Model, Task};
use crate::manager::ContextServerManager;
use crate::types;
pub struct ContextServerTool {
server_manager: Model<ContextServerManager>,
server_id: Arc<str>,

View file

@ -3,8 +3,7 @@ use std::sync::Arc;
use extension::{Extension, ExtensionContextServerProxy, ExtensionHostProxy, ProjectDelegate};
use gpui::{AppContext, Model};
use crate::manager::ServerCommand;
use crate::ContextServerFactoryRegistry;
use crate::{ContextServerFactoryRegistry, ServerCommand};
struct ExtensionProject {
worktree_ids: Vec<u64>,

View file

@ -24,66 +24,16 @@ use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, Subscription, Tas
use log;
use parking_lot::RwLock;
use project::Project;
use schemars::gen::SchemaGenerator;
use schemars::schema::{InstanceType, Schema, SchemaObject};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources, SettingsStore};
use settings::{Settings, SettingsStore};
use util::ResultExt as _;
use crate::{ContextServerSettings, ServerConfig};
use crate::{
client::{self, Client},
types, ContextServerFactoryRegistry, CONTEXT_SERVERS_NAMESPACE,
};
#[derive(Deserialize, Serialize, Default, Clone, PartialEq, Eq, JsonSchema, Debug)]
pub struct ContextServerSettings {
/// Settings for context servers used in the Assistant.
#[serde(default)]
pub context_servers: HashMap<Arc<str>, ServerConfig>,
}
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug, Default)]
pub struct ServerConfig {
/// The command to run this context server.
///
/// This will override the command set by an extension.
pub command: Option<ServerCommand>,
/// The settings for this context server.
///
/// Consult the documentation for the context server to see what settings
/// are supported.
#[schemars(schema_with = "server_config_settings_json_schema")]
pub settings: Option<serde_json::Value>,
}
fn server_config_settings_json_schema(_generator: &mut SchemaGenerator) -> Schema {
Schema::Object(SchemaObject {
instance_type: Some(InstanceType::Object.into()),
..Default::default()
})
}
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
pub struct ServerCommand {
pub path: String,
pub args: Vec<String>,
pub env: Option<HashMap<String, String>>,
}
impl Settings for ContextServerSettings {
const KEY: Option<&'static str> = None;
type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
sources.json_merge()
}
}
pub struct ContextServer {
pub id: Arc<str>,
pub config: Arc<ServerConfig>,

View file

@ -5,7 +5,7 @@ use collections::HashMap;
use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ReadGlobal, Task};
use project::Project;
use crate::manager::ServerCommand;
use crate::ServerCommand;
pub type ContextServerFactory = Arc<
dyn Fn(Model<Project>, &AsyncAppContext) -> Task<Result<ServerCommand>> + Send + Sync + 'static,

View file

@ -0,0 +1,21 @@
[package]
name = "context_server_settings"
version = "0.1.0"
edition = "2021"
publish = false
license = "GPL-3.0-or-later"
[lints]
workspace = true
[lib]
path = "src/context_server_settings.rs"
[dependencies]
anyhow.workspace = true
collections.workspace = true
gpui.workspace = true
schemars.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true

View file

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

View file

@ -0,0 +1,61 @@
use std::sync::Arc;
use collections::HashMap;
use gpui::AppContext;
use schemars::gen::SchemaGenerator;
use schemars::schema::{InstanceType, Schema, SchemaObject};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
pub fn init(cx: &mut AppContext) {
ContextServerSettings::register(cx);
}
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug, Default)]
pub struct ServerConfig {
/// The command to run this context server.
///
/// This will override the command set by an extension.
pub command: Option<ServerCommand>,
/// The settings for this context server.
///
/// Consult the documentation for the context server to see what settings
/// are supported.
#[schemars(schema_with = "server_config_settings_json_schema")]
pub settings: Option<serde_json::Value>,
}
fn server_config_settings_json_schema(_generator: &mut SchemaGenerator) -> Schema {
Schema::Object(SchemaObject {
instance_type: Some(InstanceType::Object.into()),
..Default::default()
})
}
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
pub struct ServerCommand {
pub path: String,
pub args: Vec<String>,
pub env: Option<HashMap<String, String>>,
}
#[derive(Deserialize, Serialize, Default, Clone, PartialEq, Eq, JsonSchema, Debug)]
pub struct ContextServerSettings {
/// Settings for context servers used in the Assistant.
#[serde(default)]
pub context_servers: HashMap<Arc<str>, ServerConfig>,
}
impl Settings for ContextServerSettings {
const KEY: Option<&'static str> = None;
type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
sources.json_merge()
}
}

View file

@ -22,7 +22,7 @@ async-tar.workspace = true
async-trait.workspace = true
client.workspace = true
collections.workspace = true
context_servers.workspace = true
context_server_settings.workspace = true
extension.workspace = true
fs.workspace = true
futures.workspace = true

View file

@ -7,7 +7,7 @@ use anyhow::{anyhow, bail, Context, Result};
use async_compression::futures::bufread::GzipDecoder;
use async_tar::Archive;
use async_trait::async_trait;
use context_servers::manager::ContextServerSettings;
use context_server_settings::ContextServerSettings;
use extension::{
ExtensionLanguageServerProxy, KeyValueStoreDelegate, ProjectDelegate, WorktreeDelegate,
};

View file

@ -20,6 +20,7 @@ anyhow.workspace = true
assets.workspace = true
assistant.workspace = true
assistant2.workspace = true
assistant_tools.workspace = true
async-watch.workspace = true
audio.workspace = true
auto_update.workspace = true

View file

@ -407,6 +407,7 @@ fn main() {
cx,
);
assistant2::init(cx);
assistant_tools::init(cx);
repl::init(
app_state.fs.clone(),
app_state.client.telemetry().clone(),