Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 4 additions & 98 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["crates/code_assistant", "crates/command_executor", "crates/fs_explorer", "crates/git", "crates/llm", "crates/sandbox", "crates/terminal", "crates/terminal_test_app", "crates/terminal_view", "crates/web"]
members = ["crates/code_assistant", "crates/command_executor", "crates/fs_explorer", "crates/git", "crates/llm", "crates/sandbox", "crates/web"]

resolver = "2"

Expand Down
16 changes: 9 additions & 7 deletions crates/code_assistant/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ edition = "2021"
[features]
default = ["document-conversion"]
document-conversion = ["transmutation", "fs_explorer/document-conversion"]
# Enable the GPUI desktop UI. Requires Xcode / Metal on macOS.
# Without this flag the binary is TUI-only and compiles without Metal tools.
gpui-ui = ["dep:gpui", "dep:gpui_platform", "dep:gpui-component", "dep:terminal", "dep:terminal_view"]

[dependencies]
command_executor = { path = "../command_executor" }
fs_explorer = { path = "../fs_explorer" }
git = { path = "../git" }
llm = { path = "../llm" }
sandbox = { path = "../sandbox" }
terminal = { path = "../terminal" }
terminal_view = { path = "../terminal_view" }
terminal = { path = "../terminal", optional = true }
terminal_view = { path = "../terminal_view", optional = true }
web = { path = "../web" }

glob = "0.3"
Expand Down Expand Up @@ -42,10 +45,10 @@ textwrap = "0.16"
tui-markdown = "=0.3.6"
derive_more = { version = "2", features = ["is_variant"] }

# GPUI related
gpui = "0.2.2"
gpui_platform = { version = "0.1", features = ["font-kit"] }
gpui-component = "0.5.2"
# GPUI related — only needed when the "gpui" feature is enabled
gpui = { version = "0.2.2", optional = true }
gpui_platform = { version = "0.1", features = ["font-kit"], optional = true }
gpui-component = { version = "0.5.2", optional = true }
smallvec = "1.15"
rust-embed = { version = "8.9", features = ["include-exclude"] }

Expand Down Expand Up @@ -110,6 +113,5 @@ tokio-util = { version = "0.7", features = ["compat"] }
core-text = "=21.0.0"

[dev-dependencies]
gpui = { version = "0.2.2", features = ["test-support"] }
axum = "0.7"
bytes = "1.10"
1 change: 1 addition & 0 deletions crates/code_assistant/src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod acp;
#[cfg(feature = "gpui-ui")]
pub mod gpui;
pub mod server;
pub mod terminal;
Expand Down
13 changes: 8 additions & 5 deletions crates/code_assistant/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,14 @@ impl Args {
);
}

// Check persisted default model from settings
let settings = crate::ui::gpui::shared::settings::UiSettings::load();
if let Some(ref default_model) = settings.default_model {
if config.get_model(default_model).is_some() {
return Ok(default_model.clone());
// Check persisted default model from settings (only available in GPUI builds)
#[cfg(feature = "gpui-ui")]
{
let settings = crate::ui::gpui::shared::settings::UiSettings::load();
if let Some(ref default_model) = settings.default_model {
if config.get_model(default_model).is_some() {
return Ok(default_model.clone());
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions crates/code_assistant/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ async fn main() -> Result<()> {
None => {
if args.ui {
// GPUI mode - use stderr to keep stdout clean
#[cfg(not(feature = "gpui-ui"))]
anyhow::bail!(
"This binary was compiled without the 'gpui' feature. \
Rebuild with `cargo build --features gpui` to enable the desktop UI."
);
#[cfg(feature = "gpui-ui")]
setup_logging(args.verbose, false);
} else {
// Terminal UI mode - log to file to prevent UI interference
Expand All @@ -96,6 +102,9 @@ async fn main() -> Result<()> {
// In GUI mode, allow starting without a valid model config
// (the settings screen will guide the user through setup).
let model_name = if args.ui {
#[cfg(not(feature = "gpui-ui"))]
unreachable!("--ui requires the gpui feature");
#[cfg(feature = "gpui-ui")]
args.get_model_name().unwrap_or_default()
} else {
args.get_model_name()?
Expand All @@ -116,6 +125,9 @@ async fn main() -> Result<()> {
};

if args.ui {
#[cfg(not(feature = "gpui-ui"))]
unreachable!("--ui requires the gpui feature");
#[cfg(feature = "gpui-ui")]
app::gpui::run(config)
} else {
app::terminal::run(config).await
Expand Down
5 changes: 5 additions & 0 deletions crates/code_assistant/src/ui/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ use crate::config::{save_project, DefaultProjectManager};
use crate::persistence::{ChatMetadata, DraftAttachment, SessionModelConfig};
use crate::session::SessionManager;
use crate::types::Project;
#[cfg(feature = "gpui-ui")]
use crate::ui::gpui::terminal::executor::GpuiTerminalCommandExecutor;
use crate::ui::UserInterface;
use crate::utils::content::content_blocks_from;
use command_executor::DefaultCommandExecutor;
use llm::factory::create_llm_client_from_model;
use llm::provider_config::ConfigurationSystem;
use sandbox::SandboxPolicy;
Expand Down Expand Up @@ -649,7 +651,10 @@ async fn handle_send_user_message(
// Start the agent (message already added)
let result = {
let project_manager = Box::new(DefaultProjectManager::new());
#[cfg(feature = "gpui-ui")]
let command_executor = Box::new(GpuiTerminalCommandExecutor::new(session_id.to_string()));
#[cfg(not(feature = "gpui-ui"))]
let command_executor = Box::new(DefaultCommandExecutor);
let user_interface = ui.clone();

// Check if session has stored model config, otherwise use global config
Expand Down
1 change: 1 addition & 0 deletions crates/code_assistant/src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod backend;
#[cfg(feature = "gpui-ui")]
pub mod gpui;
pub mod streaming;
pub mod terminal;
Expand Down
15 changes: 13 additions & 2 deletions crates/code_assistant/src/ui/ui_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ use crate::ui::{DisplayFragment, ToolStatus};
use sandbox::SandboxPolicy;
use std::path::PathBuf;

// When the gpui-ui feature is enabled, StyledLine comes from the `terminal` crate
// (which captures ANSI-coloured output from the interactive terminal tool).
// Without gpui-ui the field is always `None`, so we use a zero-sized stub that
// satisfies the type checker without pulling in the Metal dependency chain.
#[cfg(feature = "gpui-ui")]
pub use terminal::StyledLine;

#[cfg(not(feature = "gpui-ui"))]
#[derive(Debug, Clone)]
pub struct StyledLine;

/// Role of a message in the conversation.
#[derive(Debug, Clone, PartialEq)]
pub enum MessageRole {
Expand Down Expand Up @@ -34,7 +45,7 @@ pub struct ToolResultData {
pub message: Option<String>,
pub output: Option<String>,
/// Styled terminal output with ANSI color information preserved.
pub styled_output: Option<Vec<terminal::StyledLine>>,
pub styled_output: Option<Vec<StyledLine>>,
/// Duration of the tool execution in seconds, computed from persisted ContentBlock timestamps.
pub duration_seconds: Option<f64>,
/// Image data from tools that produce visual output (e.g. view_images).
Expand Down Expand Up @@ -79,7 +90,7 @@ pub enum UiEvent {
message: Option<String>,
output: Option<String>,
/// Styled terminal output with ANSI color information preserved.
styled_output: Option<Vec<terminal::StyledLine>>,
styled_output: Option<Vec<StyledLine>>,
/// Execution duration in seconds, set from ContentBlock timestamps on completion.
duration_seconds: Option<f64>,
/// Image data from tools that produce visual output (e.g. view_images).
Expand Down