Fix cursor focus and selection in input box, add AWS env var warning box, and remove AWS Bedrock login banner

This commit is contained in:
2026-07-02 14:54:15 -05:00
parent 4770ac06b5
commit 3769646ca6
1194 changed files with 5312 additions and 8032 deletions
+1 -1
View File
@@ -34,10 +34,10 @@ pub use execute::{
StartAgentExecutorEvent, StartAgentRequest, StartAgentRequestId,
};
use futures::future::{join_all, BoxFuture};
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use itertools::Itertools;
use parking_lot::FairMutex;
use preprocess::{PendingPreprocessedActions, PreprocessId};
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use self::execute::ask_user_question::AskUserQuestionExecutor;
use self::execute::search_codebase::SearchCodebaseExecutor;
+11 -10
View File
@@ -40,9 +40,20 @@ use futures::future::BoxFuture;
#[cfg(feature = "local_fs")]
use futures::AsyncReadExt;
use futures::FutureExt;
use galaxy_core::execution_mode::AppExecutionMode;
use galaxy_core::features::FeatureFlag;
#[cfg(feature = "local_fs")]
use galaxy_files::{FileModel, TextFileReadResult};
#[cfg(feature = "local_fs")]
use galaxy_util::file::FileLoadError;
#[cfg(feature = "local_fs")]
use galaxy_util::file_type::is_buffer_binary;
use galaxyui::r#async::{Spawnable, SpawnableOutput};
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use grep::GrepExecutor;
#[cfg(feature = "local_fs")]
use mime_guess::from_path;
use notebooks::NotebookExecutor;
use parking_lot::FairMutex;
use read_documents::ReadDocumentsExecutor;
pub(super) use read_files::ReadFilesExecutor;
@@ -69,16 +80,6 @@ pub use suggest_prompt::PromptSuggestionExecutor;
use upload_artifact::UploadArtifactExecutor;
use use_computer::UseComputerExecutor;
use wait_for_events::WaitForEventsExecutor;
use galaxy_core::execution_mode::AppExecutionMode;
use galaxy_core::features::FeatureFlag;
#[cfg(feature = "local_fs")]
use galaxy_files::{FileModel, TextFileReadResult};
#[cfg(feature = "local_fs")]
use galaxy_util::file::FileLoadError;
#[cfg(feature = "local_fs")]
use galaxy_util::file_type::is_buffer_binary;
use galaxyui::r#async::{Spawnable, SpawnableOutput};
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use self::search_codebase::SearchCodebaseExecutor;
use crate::ai::agent::conversation::AIConversationId;
@@ -5,7 +5,9 @@ use galaxyui::{Entity, EntityId, ModelContext, SingletonEntity};
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
use crate::ai::agent::{AIAgentActionResultType, AIAgentActionType};
use crate::ai::blocklist::orchestration_events::OrchestrationEventService;
use crate::ai::blocklist::BlocklistAIPermissions;
use crate::BlocklistAIHistoryModel;
pub enum AskUserQuestionDecision {
Completed(Vec<AskUserQuestionAnswerItem>),
@@ -36,6 +36,7 @@ fn build_action(action_id: &str) -> AIAgentAction {
},
task_id: TaskId::new(format!("task-{action_id}")),
requires_result: false,
tool_name: None,
}
}
@@ -1,10 +1,10 @@
use futures::future::BoxFuture;
use futures::FutureExt;
#[cfg(not(target_family = "wasm"))]
use itertools::Itertools;
#[cfg(not(target_family = "wasm"))]
use galaxyui::SingletonEntity;
use galaxyui::{Entity, EntityId, ModelContext, ModelHandle};
#[cfg(not(target_family = "wasm"))]
use itertools::Itertools;
#[cfg(not(target_family = "wasm"))]
use super::get_server_output_id;
@@ -4,10 +4,10 @@ use std::time::Duration;
use futures::future::BoxFuture;
use futures::FutureExt;
use galaxy_core::features::FeatureFlag;
use galaxyui::r#async::FutureExt as AsyncFutureExt;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use itertools::Itertools;
use galaxy_core::features::FeatureFlag;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::{
@@ -3,25 +3,22 @@
//! These tools interact with Galaxy Drive CloudNotebook objects directly,
//! as opposed to the plan tools which work through AIDocumentModel.
use futures::{future::BoxFuture, FutureExt};
use futures::future::BoxFuture;
use futures::FutureExt;
use galaxyui::{Entity, ModelContext, SingletonEntity};
use crate::{
ai::{
agent::{
AIAgentAction, AIAgentActionType, CreateDocumentsRequest, CreateDocumentsResult,
DocumentContext, EditDocumentsRequest, EditDocumentsResult, ReadDocumentsRequest,
ReadDocumentsResult,
},
document::ai_document_model::AIDocumentVersion,
},
cloud_object::model::persistence::CloudModel,
notebooks::CloudNotebookModel,
server::{cloud_objects::update_manager::UpdateManager, ids::ClientId},
workspaces::user_workspaces::UserWorkspaces,
};
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
use crate::ai::agent::{
AIAgentAction, AIAgentActionType, CreateDocumentsRequest, CreateDocumentsResult,
DocumentContext, EditDocumentsRequest, EditDocumentsResult, ReadDocumentsRequest,
ReadDocumentsResult,
};
use crate::ai::document::ai_document_model::AIDocumentVersion;
use crate::cloud_object::model::persistence::CloudModel;
use crate::notebooks::CloudNotebookModel;
use crate::server::cloud_objects::update_manager::UpdateManager;
use crate::server::ids::ClientId;
use crate::workspaces::user_workspaces::UserWorkspaces;
pub struct NotebookExecutor;
@@ -34,6 +34,7 @@ fn read_action(document_id: AIDocumentId) -> AIAgentAction {
action: AIAgentActionType::ReadDocuments(ReadDocumentsRequest {
document_ids: vec![document_id],
}),
tool_name: None,
}
}
@@ -4,16 +4,16 @@ use std::path::PathBuf;
use ai::skills::{parse_skill, ParsedSkill, SkillProvider, SkillReference, SkillScope};
use async_channel::unbounded;
use repo_metadata::repositories::DetectedRepositories;
use repo_metadata::watcher::DirectoryWatcher;
use repo_metadata::RepoMetadataModel;
use tempfile::TempDir;
use galaxy_core::features::FeatureFlag;
use galaxy_core::HostId;
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
use galaxy_util::remote_path::RemotePath;
use galaxy_util::standardized_path::StandardizedPath;
use galaxyui::{App, ModelHandle};
use repo_metadata::repositories::DetectedRepositories;
use repo_metadata::watcher::DirectoryWatcher;
use repo_metadata::RepoMetadataModel;
use tempfile::TempDir;
use watcher::HomeDirectoryWatcher;
use super::*;
@@ -36,7 +36,7 @@ fn initialize_app(app: &mut App) {
app.add_singleton_model(|_| DetectedRepositories::default());
app.add_singleton_model(RepoMetadataModel::new);
app.add_singleton_model(HomeDirectoryWatcher::new_for_test);
app.add_singleton_model(GalaxyManagedPathsWatcher::new_for_testing);
app.add_singleton_model(WarpManagedPathsWatcher::new_for_testing);
app.add_singleton_model(SkillManager::new);
}
fn add_test_read_skill_executor(app: &mut App) -> ModelHandle<ReadSkillExecutor> {
@@ -112,6 +112,7 @@ fn test_read_skill_executor_success() {
}),
task_id: TaskId::new("test-task-id".to_string()),
requires_result: false,
tool_name: None,
};
let input = ExecuteActionInput {
@@ -174,6 +175,7 @@ fn disconnected_remote_session_does_not_fall_back_to_client_global_bundled_skill
}),
task_id: TaskId::new("test-task-id".to_string()),
requires_result: false,
tool_name: None,
};
let input = ExecuteActionInput {
action: &action,
@@ -259,6 +261,7 @@ fn remote_session_reads_remote_bundled_skill_catalog() {
}),
task_id: TaskId::new("test-task-id".to_string()),
requires_result: false,
tool_name: None,
};
let input = ExecuteActionInput {
action: &action,
@@ -307,6 +310,7 @@ fn test_read_skill_executor_reads_enabled_bundled_skill() {
}),
task_id: TaskId::new("test-task-id".to_string()),
requires_result: false,
tool_name: None,
};
let input = ExecuteActionInput {
@@ -351,6 +355,7 @@ fn test_read_skill_executor_rejects_warp_control_bundled_skills_when_disabled()
}),
task_id: TaskId::new(format!("test-task-id-{skill_id}")),
requires_result: false,
tool_name: None,
};
let input = ExecuteActionInput {
@@ -386,6 +391,7 @@ fn test_read_skill_executor_file_not_found() {
}),
task_id: TaskId::new("test-task-id".to_string()),
requires_result: false,
tool_name: None,
};
let input = ExecuteActionInput {
@@ -12,6 +12,7 @@ pub(crate) use diff_application::{apply_edits, FileReadResult};
use futures::channel::oneshot;
use futures::future::BoxFuture;
use futures::FutureExt;
use galaxy_core::send_telemetry_from_ctx;
use itertools::Itertools;
pub(crate) use telemetry::MalformedFinalLineProxyEvent;
#[allow(unused_imports)]
@@ -21,7 +22,6 @@ pub use telemetry::{
RequestFileEditsTelemetryEvent,
};
use vec1::{vec1, Vec1};
use galaxy_core::send_telemetry_from_ctx;
use warp_util::file::FileSaveError;
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity as _, ViewHandle};
@@ -14,9 +14,9 @@ use ai::agent::orchestration_config::OrchestrationConfig;
use ai::skills::SkillReference;
use futures::future::BoxFuture;
use futures::FutureExt;
use galaxy_core::execution_mode::AppExecutionMode;
use settings::Setting;
use warp_cli::agent::Harness;
use galaxy_core::execution_mode::AppExecutionMode;
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use super::start_agent::{StartAgentExecutor, StartAgentOutcome};
@@ -4,9 +4,9 @@ use ai::agent::action::{RunAgentsAgentRunConfig, RunAgentsExecutionMode, RunAgen
use ai::agent::orchestration_config::{
OrchestrationConfig, OrchestrationConfigStatus, OrchestrationExecutionMode,
};
use settings::Setting;
use galaxy_core::execution_mode::ExecutionMode;
use galaxy_core::features::FeatureFlag;
use settings::Setting;
use warpui::{App, Entity, EntityId, ModelHandle};
use super::*;
@@ -239,6 +239,7 @@ fn remote_run_agents_action(harness_type: &str) -> AIAgentAction {
plan_id: String::new(),
harness_auth_secret_name: None,
}),
tool_name: None,
}
}
@@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
use futures::channel::oneshot;
use futures::future::BoxFuture;
use futures::FutureExt;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use itertools::Itertools;
use super::{
@@ -249,6 +249,8 @@ impl ShellCommandExecutor {
block_id: model.block_list().active_block().id().clone(),
output: "Error: Cannot execute command because another command is still running in the terminal.".to_string(),
exit_code: ExitCode::from(1),
start_ts: None,
completed_ts: None,
},
));
}
@@ -2,9 +2,9 @@ use std::collections::HashMap;
use futures::future::BoxFuture;
use futures::FutureExt;
use shell_words::split as split_shell_words;
use galaxy_cli::agent::Harness;
use galaxyui::{Entity, ModelContext, ModelHandle, SingletonEntity};
use shell_words::split as split_shell_words;
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
use crate::ai::agent::conversation::{AIConversationId, ConversationStatus};
@@ -485,7 +485,7 @@ impl StartAgentExecutor {
// In local mode (no parent_run_id), block until the child finishes
// so the parent model receives the child's output as the tool result.
let wait_for_completion = parent_run_id.is_none();
let _wait_for_completion = parent_run_id.is_none();
let (sender, receiver) = async_channel::bounded(1);
let request_id = self.next_request_id();
@@ -45,6 +45,7 @@ fn build_start_agent_action_with_prompt(
},
task_id: TaskId::new("start-agent-task".to_string()),
requires_result: false,
tool_name: None,
}
}
@@ -41,6 +41,7 @@ fn build_upload_artifact_action(file_path: &str) -> AIAgentAction {
}),
task_id: TaskId::new("upload-artifact-task".to_string()),
requires_result: false,
tool_name: None,
}
}
@@ -131,6 +131,7 @@ fn execute_invokes_parent_registration_and_honors_child_short_circuit() {
},
task_id: TaskId::new("wait-task".to_string()),
requires_result: false,
tool_name: None,
};
let execution = executor.update(&mut app, |executor, ctx| {
@@ -18,6 +18,7 @@ fn create_test_action(id: AIAgentActionId) -> AIAgentAction {
citations: vec![],
},
requires_result: false,
tool_name: None,
}
}
@@ -3,9 +3,9 @@
//! Uses the shared [`ChipConfigurator`] with `LeftRightZones` layout to let users
//! drag/drop chips between left, right, and unused banks.
use settings::Setting as _;
use galaxyui::keymap::FixedBinding;
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
use settings::Setting as _;
use super::toolbar_item::AgentToolbarItemKind;
use crate::appearance::AppearanceEvent;
@@ -1,8 +1,5 @@
use std::sync::Arc;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use settings::Setting;
use galaxy_core::send_telemetry_from_ctx;
use galaxy_core::ui::color::blend::Blend;
use galaxy_core::ui::theme::Fill;
@@ -14,6 +11,9 @@ use galaxyui::{
AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
ViewHandle,
};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use settings::Setting;
use super::{AgentInputButtonTheme, AmbientAgentViewModel};
use crate::ai::ambient_agents::telemetry::CloudAgentTelemetryEvent;
@@ -13,17 +13,6 @@ use std::time::Duration;
use ai::document::{AIDocumentId, AIDocumentVersion};
use chrono::{DateTime, Local};
use parking_lot::FairMutex;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::{vec2f, Vector2F};
#[cfg(feature = "voice_input")]
use settings::Setting;
use settings::ToggleableSetting;
#[cfg(not(target_family = "wasm"))]
use tokio::fs;
use toolbar_item::AgentToolbarItemKind;
#[cfg(feature = "voice_input")]
use voice_input::{StartListeningError, VoiceSessionResult};
use galaxy_cli::agent::Harness;
use galaxy_core::context_flag::ContextFlag;
use galaxy_core::report_if_error;
@@ -43,6 +32,17 @@ use galaxyui::{
AppContext, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
ViewHandle,
};
use parking_lot::FairMutex;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::{vec2f, Vector2F};
#[cfg(feature = "voice_input")]
use settings::Setting;
use settings::ToggleableSetting;
#[cfg(not(target_family = "wasm"))]
use tokio::fs;
use toolbar_item::AgentToolbarItemKind;
#[cfg(feature = "voice_input")]
use voice_input::{StartListeningError, VoiceSessionResult};
#[cfg(feature = "local_fs")]
pub(crate) use self::environment_selector::sort_environments_by_recency;
@@ -233,6 +233,9 @@ pub struct AgentInputFooter {
// `Workspace::start_local_to_cloud_handoff`.
handoff_to_cloud_button: ViewHandle<ActionButton>,
start_remote_control_button: ViewHandle<ActionButton>,
stop_remote_control_button: ViewHandle<ActionButton>,
// CLI agent voice input state (self-contained, bypasses editor voice flow).
#[cfg(feature = "voice_input")]
cli_voice_input_state: CLIVoiceInputState,
@@ -579,7 +582,7 @@ impl AgentInputFooter {
let start_remote_control_button = ctx.add_typed_action_view(|_ctx| {
ActionButton::new("/remote-control", RemoteControlButtonTheme)
.with_icon(Icon::Phone01)
.with_tooltip(START_REMOTE_CONTROL_TOOLTIP)
.with_tooltip("Start remote control")
.with_size(cli_button_size)
.with_tooltip_alignment(TooltipAlignment::Left)
.on_click(|ctx| {
@@ -845,6 +848,8 @@ impl AgentInputFooter {
display_chip_config,
fast_forward_button,
handoff_to_cloud_button,
start_remote_control_button,
stop_remote_control_button,
#[cfg(feature = "voice_input")]
cli_voice_input_state: CLIVoiceInputState::default(),
#[cfg(feature = "voice_input")]
@@ -2299,6 +2304,8 @@ pub enum AgentInputFooterAction {
ShowContextMenu {
position: Vector2F,
},
StartRemoteControl,
StopRemoteControl,
}
impl TypedActionView for AgentInputFooter {
@@ -2497,6 +2504,12 @@ impl TypedActionView for AgentInputFooter {
position: *position,
});
}
AgentInputFooterAction::StartRemoteControl => {
ctx.emit(AgentInputFooterEvent::StartRemoteControl);
}
AgentInputFooterAction::StopRemoteControl => {
ctx.emit(AgentInputFooterEvent::StopRemoteControl);
}
}
}
}
@@ -2541,6 +2554,8 @@ pub enum AgentInputFooterEvent {
/// source conversation with content) or activates `&` compose mode
/// (preserving any in-flight prompt).
HandoffChipClicked,
StartRemoteControl,
StopRemoteControl,
}
impl Entity for AgentInputFooter {
@@ -71,6 +71,9 @@ pub enum AgentToolbarItemKind {
// Agent view only "Hand off to cloud" chip.
HandoffToCloud,
// Agent view only "Share session" button.
ShareSession,
}
impl AgentToolbarItemKind {
@@ -81,7 +84,8 @@ impl AgentToolbarItemKind {
| Self::NLDToggle
| Self::ContextWindowUsage
| Self::FastForwardToggle
| Self::HandoffToCloud => ToolbarAvailability::AgentViewOnly,
| Self::HandoffToCloud
| Self::ShareSession => ToolbarAvailability::AgentViewOnly,
Self::FileExplorer | Self::RichInput | Self::Settings => {
ToolbarAvailability::CLIAgentOnly
}
@@ -102,6 +106,7 @@ impl AgentToolbarItemKind {
Self::FastForwardToggle => !status.is_viewer() || status.is_executor(),
// Handoff is host-initiated; viewers cannot hand off another user's conversation.
Self::HandoffToCloud => !status.is_viewer(),
Self::ShareSession => !status.is_viewer(),
Self::ContextChip(_)
| Self::ModelSelector
| Self::NLDToggle
@@ -124,6 +129,7 @@ impl AgentToolbarItemKind {
Self::Settings => "Settings",
Self::FastForwardToggle => "Fast Forward",
Self::HandoffToCloud => "Hand off to cloud",
Self::ShareSession => "Share Session",
}
}
@@ -142,6 +148,7 @@ impl AgentToolbarItemKind {
// The bundled `upload-cloud-01.svg` (cloud-with-upward-arrow) is the
// closest fit among the existing icons for V0; design may swap it later.
Self::HandoffToCloud => Some(Icon::UploadCloud),
Self::ShareSession => Some(Icon::Share),
}
}
@@ -7,11 +7,10 @@ use galaxyui::assets::asset_cache::AssetSource;
use galaxyui::elements::{Container, Element, Empty, MouseStateHandle};
use galaxyui::keymap::Keystroke;
use galaxyui::platform::OperatingSystem;
use galaxyui::{AppContext, Entity, ModelHandle, SingletonEntity, View, ViewContext};
use parking_lot::FairMutex;
use galaxyui::{
AppContext, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
};
use parking_lot::FairMutex;
use super::{AgentViewState, EphemeralMessageModel, EphemeralMessageModelEvent};
use crate::ai::agent::conversation::AIConversation;
@@ -1,6 +1,3 @@
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::Vector2F;
use settings::Setting;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::Icon;
use galaxyui::elements::{
@@ -16,6 +13,9 @@ use galaxyui::{
AppContext, Element, Entity, EntityId, EventContext, ModelHandle, SingletonEntity,
TypedActionView, View, ViewContext,
};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::Vector2F;
use settings::Setting;
use super::{AgentViewController, AgentViewEntryOrigin};
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
@@ -1,12 +1,12 @@
use std::sync::Arc;
use std::time::Duration;
use instant::Instant;
use parking_lot::FairMutex;
use galaxy_core::ui::appearance::Appearance;
use galaxyui::keymap::Keystroke;
use galaxyui::r#async::SpawnedFutureHandle;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use instant::Instant;
use parking_lot::FairMutex;
use super::{DismissalStrategy, EphemeralMessage, EphemeralMessageModel};
use crate::ai::agent::conversation::AIConversationId;
@@ -1021,7 +1021,6 @@ fn exit_confirmation_message(
) -> Message {
use galaxyui::SingletonEntity;
let appearance = Appearance::handle(app).as_ref(app);
let (keystroke, text) = match trigger {
@@ -1,12 +1,12 @@
use std::sync::Arc;
use ai::agent::action::{AIAgentActionType, ShellCommandDelay};
use parking_lot::FairMutex;
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::{CornerRadius, Radius};
use galaxyui::{
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, View, ViewContext,
};
use parking_lot::FairMutex;
use crate::ai::agent::icons;
use crate::ai::blocklist::block::cli_controller::LongRunningCommandControlState;
+4 -4
View File
@@ -22,15 +22,15 @@ pub use agent_view_block::*;
pub use controller::*;
pub(crate) use conversation_selection::AgentViewConversationSelection;
pub use ephemeral_message_model::*;
use galaxyui::fonts::Properties;
pub use inline_agent_view_header::*;
pub use orchestration_pill_bar::{render_orchestration_breadcrumbs, OrchestrationPillBar};
use pathfinder_color::ColorU;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::color::blend::Blend;
use galaxy_core::ui::theme::Fill;
use galaxyui::fonts::Properties;
use galaxyui::keymap::Keystroke;
use galaxyui::{AppContext, SingletonEntity};
pub use inline_agent_view_header::*;
pub use orchestration_pill_bar::{render_orchestration_breadcrumbs, OrchestrationPillBar};
use pathfinder_color::ColorU;
pub use zero_state_block::*;
use crate::terminal::model::TerminalModel;
@@ -1,5 +1,3 @@
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::Vector2F;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::Fill;
use galaxyui::elements::{
@@ -11,6 +9,8 @@ use galaxyui::fonts::Weight::Bold;
use galaxyui::platform::Cursor;
use galaxyui::text_layout::ClipConfig;
use galaxyui::{AppContext, Element, EntityId, EventContext, SingletonEntity};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::Vector2F;
use crate::ai::agent::api::ServerConversationToken;
use crate::ai::agent::conversation::{AIConversation, AIConversationId};
@@ -7,9 +7,6 @@ use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use warp_cli::agent::Harness;
use galaxy_core::channel::ChannelState;
use galaxy_core::send_telemetry_from_ctx;
use galaxy_core::ui::appearance::Appearance;
@@ -17,6 +14,9 @@ use galaxy_core::ui::color::blend::Blend;
use galaxy_core::ui::color::coloru_with_opacity;
use galaxy_core::ui::theme::color::internal_colors;
use galaxy_core::ui::theme::{Fill, WarpTheme};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use warp_cli::agent::Harness;
use warpui::elements::new_scrollable::{NewScrollable, ScrollableAppearance, SingleAxisConfig};
use warpui::elements::{
Align, AnchorPair, ChildAnchor, ChildView, ClippedScrollStateHandle, ConstrainedBox, Container,
@@ -55,6 +55,7 @@ fn pill_bar_data_layer_finds_restored_children_before_pane_creation() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
})
.expect("child conversation data should serialize"),
last_modified_at: now,
@@ -105,6 +106,7 @@ fn pill_bar_data_layer_finds_restored_children_before_pane_creation() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
})
.expect("parent conversation data should serialize"),
last_modified_at: now - chrono::Duration::seconds(1),
@@ -2,13 +2,13 @@ mod model;
use std::borrow::Cow;
pub use model::*;
use pathfinder_color::ColorU;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::{
Border, Container, CrossAxisAlignment, Expanded, Flex, ParentElement, Text,
};
pub use model::*;
use pathfinder_color::ColorU;
use warpui::keymap::Keystroke;
use warpui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
use warpui::{AppContext, Element, SingletonEntity};
@@ -259,6 +259,7 @@ pub fn render_agent_shortcuts_view(
}
pub mod styles {
use super::Appearance;
pub fn keystroke_size(appearance: &Appearance) -> f32 {
font_size(appearance) + 2.
@@ -1,3 +1,5 @@
#![allow(dead_code)]
//! Inline subagent panel rendered within the parent agent's chat flow.
//!
//! Shows a collapsible panel with the subagent's status, a mini-transcript of
@@ -11,7 +13,7 @@ use galaxyui::{AppContext, SingletonEntity};
use pathfinder_color::ColorU;
use warp_multi_agent_api as api;
use crate::ai::agent::conversation::{AIConversationId, ConversationStatus};
use crate::ai::agent::conversation::{AIConversationId, ConversationStatus, StatusColorStyle};
use crate::ai::agent::AIAgentActionId;
use crate::ai::blocklist::block::AIBlockAction;
use crate::ai::blocklist::inline_action::inline_action_header::{
@@ -127,7 +129,7 @@ fn render_panel_header(
// Left: status icon + agent name + status text
let mut left_side = Flex::row().with_cross_axis_alignment(CrossAxisAlignment::Center);
let (icon, icon_color) = status.status_icon_and_color(theme);
let (icon, icon_color) = status.status_icon_and_color(theme, StatusColorStyle::Standard);
let status_icon_element =
ConstrainedBox::new(galaxyui::elements::Icon::new(icon.into(), icon_color).finish())
.with_width(icon_size(app))
@@ -151,8 +153,10 @@ fn render_panel_header(
ConversationStatus::InProgress => "Working...",
ConversationStatus::Success => "Complete",
ConversationStatus::Error => "Error",
ConversationStatus::TransientError => "Retrying...",
ConversationStatus::Cancelled => "Cancelled",
ConversationStatus::Blocked { .. } => "Blocked",
ConversationStatus::WaitingForEvents => "Waiting...",
};
let status_text_color = blended_colors::text_disabled(theme, surface);
left_side.add_child(
@@ -1,12 +1,10 @@
#![allow(dead_code)]
use std::borrow::Cow;
use std::cmp::Reverse;
use std::path::Path;
use std::sync::Arc;
use itertools::Itertools as _;
use markdown_parser::{parse_markdown, FormattedText, FormattedTextFragment, FormattedTextLine};
use parking_lot::FairMutex;
use settings::Setting;
use galaxy_core::features::FeatureFlag;
use galaxy_core::report_if_error;
use galaxy_core::ui::Icon;
@@ -25,7 +23,9 @@ use galaxyui::{
Action, AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View,
ViewContext,
};
use std::{borrow::Cow, cmp::Reverse, path::Path, sync::Arc};
use itertools::Itertools as _;
use markdown_parser::{parse_markdown, FormattedText, FormattedTextFragment, FormattedTextLine};
use parking_lot::FairMutex;
use crate::ai::active_agent_views_model::{ActiveAgentViewsModel, ConversationOrTaskId};
use crate::ai::agent::conversation::AIConversationId;
+31 -14
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
//! Implementation of "AI blocks" used to render AI queries and outputs in the blocklist.
pub mod cli;
pub mod cli_controller;
@@ -28,6 +30,9 @@ use base64::Engine as _;
use chrono::Duration;
use cli_controller::{CLISubagentController, CLISubagentEvent};
use find::FindState;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::theme::color::internal_colors;
use galaxy_core::ui::theme::Fill;
use indexmap::IndexMap;
use itertools::Itertools;
use model::AIBlockOutputStatus;
@@ -40,9 +45,6 @@ use repo_metadata::repositories::DetectedRepositories;
use secret_redaction::*;
use serde::Serialize;
use settings::Setting as _;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::theme::color::internal_colors;
use galaxy_core::ui::theme::Fill;
use warp_editor::content::buffer::InitialBufferState;
#[cfg(feature = "local_fs")]
use warp_editor::content::edit::resolve_asset_source_relative_to_directory;
@@ -129,6 +131,7 @@ use crate::ai::blocklist::inline_action::search_codebase::{
use crate::ai::blocklist::inline_action::suggested_unit_tests::{
SuggestedUnitTestsEvent, SuggestedUnitTestsView,
};
use crate::ai::blocklist::inline_action::summarization::SummarizationView;
use crate::ai::blocklist::inline_action::web_fetch::WebFetchView;
use crate::ai::blocklist::inline_action::web_search::WebSearchView;
use crate::ai::blocklist::permissions::{
@@ -478,6 +481,9 @@ pub(super) struct AIBlockStateHandles {
/// ReadSkill and ReadFiles action banners. Keyed by action id so that
/// multiple skill banners in the same block don't share hover/click state.
skill_button_handles: HashMap<AIAgentActionId, MouseStateHandle>,
usage_button_handle: MouseStateHandle,
subagent_panel_states:
HashMap<AIAgentActionId, super::agent_view::subagent_inline_panel::SubagentPanelState>,
}
#[derive(Default, Clone, Debug)]
@@ -1067,6 +1073,7 @@ pub struct AIBlock {
terminal_view_handle: WeakViewHandle<TerminalView>,
ask_user_question_view: Option<ViewHandle<AskUserQuestionView>>,
is_usage_footer_expanded: bool,
}
struct EmbeddedCodeEditorView {
@@ -1512,6 +1519,7 @@ impl AIBlock {
resolved_blocklist_image_sources: Default::default(),
terminal_view_handle,
ask_user_question_view: None,
is_usage_footer_expanded: false,
};
me.run_secret_redaction_on_user_query(me.client_ids.conversation_id, ctx);
me.spawn_link_detection(ctx);
@@ -2638,16 +2646,14 @@ impl AIBlock {
base_branch,
},
..
} => {
if self.model.is_restored() && FeatureFlag::PRCommentsV2.is_enabled() {
self.handle_insert_code_review_comments(
id.clone(),
repo_path,
comments,
base_branch.as_deref(),
ctx,
);
}
} if self.model.is_restored() && FeatureFlag::PRCommentsV2.is_enabled() => {
self.handle_insert_code_review_comments(
id.clone(),
repo_path,
comments,
base_branch.as_deref(),
ctx,
);
}
_ => (),
}
@@ -3995,7 +4001,7 @@ impl AIBlock {
return;
}
let view = ctx.add_view(|ctx| SummarizationView::new(ctx));
let view = ctx.add_view(SummarizationView::new);
self.summarization_views.insert(key, view);
ctx.notify();
}
@@ -6328,6 +6334,7 @@ pub enum AIBlockAction {
ToggleSubagentPanel {
action_id: AIAgentActionId,
},
ToggleIsUsageFooterExpanded,
}
impl TypedActionView for AIBlock {
@@ -6335,6 +6342,16 @@ impl TypedActionView for AIBlock {
fn handle_action(&mut self, action: &Self::Action, ctx: &mut ViewContext<Self>) {
match action {
AIBlockAction::ToggleIsUsageFooterExpanded => {
self.is_usage_footer_expanded = !self.is_usage_footer_expanded;
ctx.notify();
}
AIBlockAction::ToggleSubagentPanel { action_id } => {
if let Some(state) = self.state_handles.subagent_panel_states.get_mut(action_id) {
state.is_expanded = !state.is_expanded;
ctx.notify();
}
}
AIBlockAction::SetCollapsibleBlockPinnedToBottom {
message_id,
pinned_to_bottom,
+46 -50
View File
@@ -4,12 +4,6 @@ use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
use lazy_static::lazy_static;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use parking_lot::{FairMutex, RwLock};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use settings::Setting as _;
use galaxy_core::features::FeatureFlag;
use galaxy_core::report_error;
use galaxy_core::semantic_selection::SemanticSelection;
@@ -37,6 +31,12 @@ use galaxyui::{
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
ViewContext, ViewHandle,
};
use lazy_static::lazy_static;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use parking_lot::{FairMutex, RwLock};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use settings::Setting as _;
use super::cli_controller::{CLISubagentController, CLISubagentEvent, UserTakeOverReason};
use super::model::{AIBlockModel, AIBlockModelHelper, AIBlockModelImpl, AIBlockOutputStatus};
@@ -628,25 +628,25 @@ impl CLISubagentView {
AIAgentActionType::SearchCodebase(_)
| AIAgentActionType::ReadFiles(_)
| AIAgentActionType::Grep { .. }
| AIAgentActionType::FileGlobV2 { .. } => {
if should_show_read_files_speedbump(ctx) {
AISettings::handle(ctx).update(ctx, |settings, ctx| {
let _ = settings
.should_show_agent_mode_autoread_files_speedbump
.set_value(false, ctx);
});
| AIAgentActionType::FileGlobV2 { .. }
if should_show_read_files_speedbump(ctx) =>
{
AISettings::handle(ctx).update(ctx, |settings, ctx| {
let _ = settings
.should_show_agent_mode_autoread_files_speedbump
.set_value(false, ctx);
});
BlocklistAIPermissions::handle(ctx).update(ctx, |permissions, ctx| {
if let Err(e) = permissions.set_always_allow_read_files(
self.always_allow_read_files_checked,
self.terminal_view_id,
ctx,
) {
report_error!(e);
}
});
ctx.notify();
}
BlocklistAIPermissions::handle(ctx).update(ctx, |permissions, ctx| {
if let Err(e) = permissions.set_always_allow_read_files(
self.always_allow_read_files_checked,
self.terminal_view_id,
ctx,
) {
report_error!(e);
}
});
ctx.notify();
}
_ => {}
}
@@ -1153,32 +1153,28 @@ impl View for CLISubagentView {
}
}
}
AIAgentOutputMessageType::WebSearch(WebSearchStatus::Searching { query }) => {
if !should_hide_responses {
result.add_child(
render_scrollable_container(
ScrollableContainerProps {
scroll_state: self
.state_handles
.action_scroll_state
.clone(),
child: render_web_search(query.clone(), app),
background_color: internal_colors::neutral_2(
appearance.theme(),
),
border: Some(
Border::all(1.).with_border_fill(
internal_colors::neutral_3(theme),
),
),
max_height: resizable_height,
},
app,
)
.with_margin_bottom(8.)
.finish(),
);
}
AIAgentOutputMessageType::WebSearch(WebSearchStatus::Searching { query })
if !should_hide_responses =>
{
result.add_child(
render_scrollable_container(
ScrollableContainerProps {
scroll_state: self.state_handles.action_scroll_state.clone(),
child: render_web_search(query.clone(), app),
background_color: internal_colors::neutral_2(
appearance.theme(),
),
border: Some(
Border::all(1.)
.with_border_fill(internal_colors::neutral_3(theme)),
),
max_height: resizable_height,
},
app,
)
.with_margin_bottom(8.)
.finish(),
);
}
_ => (),
}
@@ -1,6 +1,7 @@
use std::collections::HashMap;
use std::sync::Arc;
use galaxyui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use instant::Instant;
use parking_lot::FairMutex;
use serde::{Deserialize, Serialize};
+6 -3
View File
@@ -2,11 +2,11 @@ mod helper;
mod model_impl;
use chrono::TimeDelta;
use galaxy_core::features::FeatureFlag;
use galaxyui::{AppContext, ViewContext};
pub use helper::AIBlockModelHelper;
pub use model_impl::*;
use session_sharing_protocol::common::ParticipantId;
use galaxy_core::features::FeatureFlag;
use galaxyui::{AppContext, ViewContext};
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::{
@@ -219,7 +219,10 @@ pub trait AIBlockModel {
#[cfg(any(test, feature = "integration_tests"))]
pub mod testing {
use super::{AIBlockModel, AIBlockOutputStatus, OutputStatusUpdateCallback};
use super::{
AIBlockModel, AIBlockOutputStatus, AIConversationId, AppContext, LLMId,
OutputStatusUpdateCallback, ViewContext,
};
use crate::ai::agent::{AIAgentInput, AIAgentOutput, ServerOutputId, Shared};
use crate::ai::blocklist::model::{
AIRequestType, PassiveRequestType, PassiveSuggestionTriggerType,
@@ -2,10 +2,9 @@ use std::marker::PhantomData;
use anyhow::{anyhow, Result};
use chrono::{Local, TimeDelta};
use galaxyui::{AppContext, SingletonEntity, View, ViewContext};
use galaxyui::{AppContext, Entity, SingletonEntity, View, ViewContext};
use history_model::{BlocklistAIHistoryEvent, BlocklistAIHistoryModel};
use session_sharing_protocol::common::ParticipantId;
use galaxyui::{AppContext, Entity, SingletonEntity, ViewContext};
use super::{AIBlockModel, AIBlockOutputStatus, OutputStatusUpdateCallback};
use crate::ai::agent::conversation::AIConversationId;
@@ -1,7 +1,6 @@
use std::cell::RefCell;
use std::rc::Rc;
use pathfinder_geometry::vector::{vec2f, Vector2F};
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::new_scrollable::SingleAxisConfig;
use galaxyui::elements::{ChildView, Clipped, ClippedScrollStateHandle, ConstrainedBox, Fill};
@@ -10,7 +9,7 @@ use galaxyui::{
App, Entity, Event, Presenter, TypedActionView, View, ViewContext, ViewHandle, WindowId,
WindowInvalidation,
};
use std::{cell::RefCell, rc::Rc};
use pathfinder_geometry::vector::{vec2f, Vector2F};
use super::*;
@@ -1,6 +1,5 @@
use std::sync::Arc;
use parking_lot::RwLock;
use galaxy_core::features::FeatureFlag;
use galaxy_core::semantic_selection::SemanticSelection;
use galaxyui::elements::{
@@ -12,6 +11,7 @@ use galaxyui::{
AppContext, Element, Entity, EntityId, SingletonEntity, TypedActionView, View, ViewContext,
ViewHandle,
};
use parking_lot::RwLock;
use crate::ai::blocklist::block::view_impl::common::render_user_avatar;
use crate::ai::blocklist::block::view_impl::{
+8 -6
View File
@@ -2,31 +2,32 @@ use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration;
use instant::Instant;
use markdown_parser::FormattedTextFragment;
use parking_lot::FairMutex;
use pathfinder_color::ColorU;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::Fill;
use galaxy_core::ui::Icon as CoreIcon;
use warp_multi_agent_api as api;
use galaxyui::elements::shimmering_text::ShimmeringTextStateHandle;
use galaxyui::elements::{Border, Container, Empty, Flex, MouseStateHandle, ParentElement, Text};
use galaxyui::keymap::Keystroke;
use galaxyui::presenter::ChildView;
use galaxyui::r#async::{SpawnedFutureHandle, Timer};
use galaxyui::text_layout::ClipConfig;
use galaxyui::{
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
ViewContext, ViewHandle,
};
use instant::Instant;
use markdown_parser::FormattedTextFragment;
use parking_lot::FairMutex;
use pathfinder_color::ColorU;
use warp_multi_agent_api as api;
use super::cli_controller::{CLISubagentController, CLISubagentEvent, UserTakeOverReason};
use super::model::{AIBlockModel, AIBlockModelImpl, AIBlockOutputStatus};
use super::view_impl::common::{
render_switch_control_to_user_button, render_warping_indicator, render_warping_indicator_base,
AutoExecuteButtonProps, ButtonProps, ForceRefreshButtonProps, MaybeShimmeringText,
WarpingIndicatorProps, WarpingProps, LOAD_OUTPUT_MESSAGE, WAITING_FOR_USER_INPUT_MESSAGE,
WarpingIndicatorProps, WarpingProps, WAITING_FOR_USER_INPUT_MESSAGE,
};
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::{
@@ -39,6 +40,7 @@ use crate::ai::blocklist::agent_view::{
agent_view_bg_fill, is_in_cloud_context, AgentMessageBar, AgentViewController,
EphemeralMessageModel,
};
use crate::ai::blocklist::block::view_impl::common::random_load_output_message;
use crate::ai::blocklist::model::AIBlockModelHelper;
use crate::ai::blocklist::summarization_cancel_dialog::{
self, SummarizationCancelDialog, SummarizationCancelDialogEvent,
+5 -4
View File
@@ -32,16 +32,13 @@ mod todos;
use std::collections::{HashMap, HashSet};
use common::get_highlight_ranges_for_find_matches;
use itertools::Itertools;
use pathfinder_color::ColorU;
use settings::Setting as _;
use galaxy_core::features::FeatureFlag;
use galaxy_core::semantic_selection::SemanticSelection;
use galaxy_core::ui::color::contrast::{
foreground_color_with_minimum_contrast, MinimumAllowedContrast,
};
use galaxy_core::ui::color::Rgb;
use galaxy_core::ui::theme::{Fill, WarpTheme};
use galaxy_core::ui::theme::{Fill, GalaxyTheme, WarpTheme};
use galaxyui::elements::{
Align, Border, Clipped, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Empty,
Expanded, Flex, FormattedTextElement, Highlight, HighlightedRange, Hoverable,
@@ -53,6 +50,9 @@ use galaxyui::platform::Cursor;
use galaxyui::text_layout::TextStyle;
use galaxyui::ui_components::components::UiComponent;
use galaxyui::{AppContext, Element, SingletonEntity, View, ViewContext};
use itertools::Itertools;
use pathfinder_color::ColorU;
use settings::Setting as _;
use super::secret_redaction::SecretRedactionState;
use super::{
@@ -1127,6 +1127,7 @@ impl View for AIBlock {
disable_rule_suggestions_button: &self.disable_rule_suggestions_button,
has_accepted_edits,
current_todo_list: self.current_todo_list(app),
is_usage_footer_expanded: self.is_usage_footer_expanded,
finish_reason: self.finish_reason.as_ref(),
shared_session_status: &shared_session_status,
terminal_view_id: self.terminal_view_id,
@@ -12,10 +12,6 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use itertools::Itertools;
use markdown_parser::{FormattedText, FormattedTextInline, TableAlignment};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use galaxy_core::channel::ChannelState;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::appearance::Appearance;
@@ -45,6 +41,11 @@ use galaxyui::text_layout::{ClipConfig, TextAlignment, TextStyle};
use galaxyui::ui_components::button::Button;
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
use galaxyui::{Action, AppContext, Element, EventContext, SingletonEntity, View, ViewHandle};
use itertools::Itertools;
use markdown_parser::{FormattedText, FormattedTextInline, TableAlignment};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use rand::Rng;
use super::output::LinkActionConstructors;
use super::{add_highlights_to_rich_text, add_highlights_to_text};
@@ -3,13 +3,13 @@ use std::path::PathBuf;
use std::sync::Arc;
use ai::skills::{ParsedSkill, SkillProvider, SkillScope};
use itertools::Itertools;
use ui_components::lightbox::{LightboxImage, LightboxImageSource};
use warp_util::local_or_remote_path::LocalOrRemotePath;
#[cfg(feature = "local_fs")]
use galaxyui::assets::asset_cache::AssetSource;
use galaxyui::elements::{Empty, MouseStateHandle};
use galaxyui::{App, Element};
use itertools::Itertools;
use ui_components::lightbox::{LightboxImage, LightboxImageSource};
use warp_util::local_or_remote_path::LocalOrRemotePath;
#[cfg(feature = "local_fs")]
use super::{blocklist_image_asset_source, ResolvedBlocklistImageSources};
@@ -1,13 +1,13 @@
//! Rendering functions for orchestration-related output items (messaging & agent management).
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_color::ColorU;
use galaxyui::elements::{
ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Empty, Flex, FormattedTextElement,
Hoverable, MouseStateHandle, ParentElement, Radius, Shrinkable, Text,
};
use galaxyui::platform::Cursor;
use galaxyui::{AppContext, Element, SingletonEntity};
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_color::ColorU;
use super::common::render_scrollable_collapsible_content;
use super::output::{action_icon, Props};
@@ -299,6 +299,7 @@ fn participant_for_restored_child_run_id_resolves_to_agent_name() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
})
.expect("child conversation data should serialize"),
last_modified_at: now,
@@ -352,6 +353,7 @@ fn participant_for_restored_child_run_id_resolves_to_agent_name() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
})
.expect("parent conversation data should serialize"),
last_modified_at: now - chrono::Duration::seconds(1),
+12 -12
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
//! Renders the AI output portion of the AI block.
//!
//! This includes text, code snippets, suggested commands, and interactive inline action UX.
@@ -14,12 +16,6 @@ use ai::agent::action::{
};
use ai::agent::file_locations::group_file_contexts_for_display;
use ai::skills::{ParsedSkill, SkillReference};
use indexmap::IndexMap;
use itertools::Itertools;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use ui_components::{button, Component as _, Options as _};
use galaxy_core::channel::ChannelState;
use galaxy_core::ui::theme::color::internal_colors;
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
@@ -37,6 +33,12 @@ use galaxyui::ui_components::radio_buttons::{RadioButtonItem, RadioButtonLayout}
use galaxyui::{
Action, AppContext, Element, EntityId, ModelHandle, SingletonEntity, View, ViewHandle,
};
use indexmap::IndexMap;
use itertools::Itertools;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use ui_components::{button, Component as _, Options as _};
use super::common::{
format_elapsed_seconds, render_debug_footer, render_failed_output, render_informational_footer,
@@ -93,6 +95,7 @@ use crate::ai::blocklist::inline_action::requested_command::RequestedCommand;
use crate::ai::blocklist::inline_action::run_agents_card_view::RunAgentsCardView;
use crate::ai::blocklist::inline_action::search_codebase::SearchCodebaseView;
use crate::ai::blocklist::inline_action::suggested_unit_tests::SuggestedUnitTestsView;
use crate::ai::blocklist::inline_action::summarization::SummarizationView;
use crate::ai::blocklist::inline_action::web_fetch::WebFetchView;
use crate::ai::blocklist::inline_action::web_search::WebSearchView;
use crate::ai::blocklist::keyboard_navigable_buttons::KeyboardNavigableButtons;
@@ -170,6 +173,7 @@ pub(crate) struct Props<'a> {
pub(super) disable_rule_suggestions_button: &'a ViewHandle<ActionButton>,
pub(super) current_todo_list: Option<&'a AIAgentTodoList>,
pub(super) has_accepted_edits: bool,
pub(super) is_usage_footer_expanded: bool,
pub(super) finish_reason: Option<&'a FinishReason>,
pub(super) shared_session_status: &'a SharedSessionStatus,
pub(super) terminal_view_id: EntityId,
@@ -886,13 +890,9 @@ pub(super) fn render(props: Props, app: &AppContext) -> Box<dyn Element> {
AIAgentOutputMessageType::Summarization {
text,
finished_duration,
summarization_type,
summarization_type: SummarizationType::ConversationSummary,
..
} if matches!(
summarization_type,
SummarizationType::ConversationSummary
) =>
{
} => {
if let Some(summarization_view) =
props.summarization_views.get(&output_message.id)
{
@@ -2,9 +2,9 @@
//!
//! Queries are not rendered in blocks corresponding to requested command or requested action responses.
use pathfinder_color::ColorU;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::theme::color::internal_colors;
use pathfinder_color::ColorU;
use warpui::elements::{
Container, CornerRadius, DispatchEventResult, EventHandler, Flex, MainAxisAlignment,
MainAxisSize, ParentElement, Radius, Shrinkable, Wrap,
+1 -1
View File
@@ -3,9 +3,9 @@ use std::path::PathBuf;
use ai::agent::action::{RunAgentsAgentRunConfig, RunAgentsExecutionMode};
use ai::agent::action_result::StartAgentVersion;
use ai::skills::SkillReference;
use settings::Setting;
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
use galaxyui::{App, SingletonEntity};
use settings::Setting;
use super::{
default_collapsible_state_for_orchestration_action,
+1 -2
View File
@@ -7,12 +7,11 @@ use std::sync::Arc;
use ai::project_context::model::ProjectContextModel;
use galaxy_core::features::FeatureFlag;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use parking_lot::FairMutex;
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
use galaxyui::{
AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity, WeakModelHandle,
};
use parking_lot::FairMutex;
use super::agent_view::{AgentViewEntryOrigin, EnterAgentViewError};
use super::block::DirectoryContext;
+85 -9
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
//! This module contains core business logic for Agent Mode, primarily sending input to an AI
//! model and receiving output.
//!
@@ -8,7 +10,7 @@ mod pending_response_streams;
pub mod response_stream;
pub(super) mod shared_session;
mod slash_command;
use std::collections::{HashMap, HashSet};
use std::collections::{HashMap, HashSet, VecDeque};
#[cfg(not(target_family = "wasm"))]
use std::path::PathBuf;
use std::sync::Arc;
@@ -17,13 +19,13 @@ use std::time::Duration;
use ai::skills::SkillPathOrigin;
use anyhow::anyhow;
use chrono::{DateTime, Local};
use galaxy_core::assertions::safe_assert;
use input_context::{input_context_for_request, parse_context_attachments};
use itertools::Itertools;
use parking_lot::FairMutex;
use pending_response_streams::PendingResponseStreams;
use session_sharing_protocol::common::ParticipantId;
pub use slash_command::*;
use galaxy_core::assertions::safe_assert;
use warp_multi_agent_api::{message, Task, ToolType};
use warpui::r#async::{SpawnedFutureHandle, Timer};
use warpui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
@@ -58,6 +60,7 @@ use crate::ai::document::ai_document_model::{
AIDocumentId, AIDocumentModel, AIDocumentUserEditStatus,
};
use crate::ai::llms::{LLMId, LLMPreferences};
use crate::ai::provider::types::ContentPart;
use crate::ai::AIRequestUsageModel;
use crate::cloud_object::model::persistence::CloudModel;
use crate::features::FeatureFlag;
@@ -1688,6 +1691,65 @@ impl BlocklistAIController {
self.pending_passive_follow_ups.remove(&conversation_id);
}
fn check_and_record_loop_detection(
&mut self,
conversation_id: AIConversationId,
results: &[AIAgentActionResult],
) -> Option<String> {
use std::hash::{Hash, Hasher};
let state = self.loop_detection.entry(conversation_id).or_default();
let mut has_success = false;
for result in results {
if result.result.is_failed() {
let discriminant = std::mem::discriminant(&result.result);
// Use a stable description that includes the tool type and the *input*
// (command, file paths, etc.) but NOT the variable output, so the same
// failing command with different output is still recognized as a loop.
let description = result.result.loop_description();
let mut hasher = std::collections::hash_map::DefaultHasher::new();
discriminant.hash(&mut hasher);
description.hash(&mut hasher);
let input_hash = hasher.finish();
state.record_failure(LoopDetectionEntry {
tool_discriminant: discriminant,
input_hash,
description: description.clone(),
});
} else if result.result.is_successful() {
has_success = true;
}
}
// If we had at least one success in this batch, clear loop state —
// the agent is making progress.
if has_success {
state.clear();
return None;
}
// Check for loops
if let Some(looping_entry) = state.detect_loop() {
let warning = format!(
"[SYSTEM] Loop detected: the same action has failed {} or more times consecutively. \
Do NOT repeat this action or any similar approach.\n\n\
Failing action: {}\n\n\
Take a completely different approach to accomplish the goal. \
If you cannot find an alternative, explain to the user what is failing and why.",
LOOP_DETECTION_THRESHOLD,
looping_entry.description
);
// Clear the state so we don't keep injecting on every subsequent turn
state.clear();
Some(warning)
} else {
None
}
}
fn conversation_ready_for_pending_events(
&self,
conversation_id: AIConversationId,
@@ -2766,7 +2828,7 @@ impl BlocklistAIController {
.conversation(&conversation_id)
.is_some_and(|c| c.status().is_in_progress())
{
let terminal_view_id = self.terminal_view_id;
let terminal_view_id = self.terminal_surface_id;
history_model.update(ctx, |history_model, ctx| {
if let Some(conversation) = history_model.conversation_mut(&conversation_id)
{
@@ -3288,7 +3350,7 @@ impl BlocklistAIController {
);
history_model.update(ctx, |history_model, ctx| {
history_model.update_conversation_status(
self.terminal_view_id,
self.terminal_surface_id,
conversation_id,
crate::ai::agent::conversation::ConversationStatus::Success,
ctx,
@@ -3605,28 +3667,41 @@ impl BlocklistAIController {
conversation_id: AIConversationId,
ctx: &mut ModelContext<Self>,
) {
use settings::Setting;
use crate::ai::bedrock::client::{BedrockClient, BedrockClientConfig};
use crate::ai::bedrock::convert::{ConversationMessage, MessageContent, MessageRole};
use crate::ai::bedrock::response_translator::{
context_window_for_model, estimate_cost_cents,
};
use crate::settings::ai::AISettings;
use settings::Setting;
let settings = AISettings::as_ref(ctx);
if !*settings.bedrock_enabled.value() {
return;
}
let config = BedrockClientConfig {
let api_key_manager = ::ai::api_keys::ApiKeyManager::as_ref(ctx);
let mut config = BedrockClientConfig {
auth_method: *settings.bedrock_auth_method.value(),
profile: settings.bedrock_profile.value().clone(),
region: settings.bedrock_region.value().clone(),
access_key_id: settings.bedrock_access_key_id.value().clone(),
secret_access_key: settings.bedrock_secret_access_key.value().clone(),
session_token: None,
cross_region_inference: *settings.bedrock_cross_region_inference.value(),
};
if let ::ai::api_keys::AwsCredentialsState::Loaded { credentials, .. } =
api_key_manager.aws_credentials_state()
{
config.auth_method = crate::settings::BedrockAuthMethod::StaticKeys;
config.access_key_id = credentials.access_key().to_string();
config.secret_access_key = credentials.secret_key().to_string();
config.session_token = credentials.session_token().map(|s| s.to_string());
}
.with_external_fallbacks();
let config = config.with_external_fallbacks();
let cross_region = config.cross_region_inference;
// Use Sonnet for summarization — cheaper and fast enough for this task
@@ -3764,7 +3839,7 @@ impl BlocklistAIController {
// Use the conversation's active model for context window sizing,
// not the summarizer model.
let active_model_id = crate::ai::llms::LLMPreferences::as_ref(ctx)
.get_active_base_model(ctx, Some(me.terminal_view_id))
.get_active_base_model(ctx, Some(me.terminal_surface_id))
.id
.to_string();
@@ -3838,7 +3913,7 @@ impl BlocklistAIController {
});
// Update cost tracking
history_model.update(ctx, |history_model, _| {
history_model.update(ctx, |history_model, ctx| {
use warp_multi_agent_api::response_event::stream_finished;
let token_usage = vec![stream_finished::TokenUsage {
model_id: "bedrock".to_string(),
@@ -3854,6 +3929,7 @@ impl BlocklistAIController {
token_usage,
None,
false,
ctx,
);
});
}
@@ -4,10 +4,10 @@ use std::sync::Arc;
use ai::index::full_source_code_embedding::manager::CodebaseIndexManager;
use chrono::Local;
use galaxy_core::features::FeatureFlag;
use galaxy_graphql::generic_string_object::GenericStringObjectFormat as GraphQLFormat;
use galaxyui::{AppContext, SingletonEntity};
use lazy_static::lazy_static;
use regex::Regex;
use galaxy_graphql::generic_string_object::GenericStringObjectFormat as GraphQLFormat;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::{
@@ -1,3 +1,5 @@
#![allow(dead_code)]
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
@@ -6,15 +8,19 @@ use anyhow::anyhow;
use chrono::{DateTime, Local, TimeDelta};
use futures::channel::oneshot;
use galaxyui::{Entity, ModelContext, SingletonEntity};
use settings::Setting;
use uuid::Uuid;
use warp_multi_agent_api::response_event;
use crate::ai::agent::api::{self, generate_multi_agent_output, ConvertToAPITypeError};
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::{AIIdentifiers, CancellationReason};
use crate::ai::bedrock::client::BedrockClientConfig;
use crate::ai::openai::client::OpenAIClientConfig;
use crate::ai::provider::ProviderConfig;
use crate::network::NetworkStatus;
use crate::server::server_api::{AIApiError, ServerApiProvider};
use crate::{report_error, send_telemetry_from_ctx};
use crate::{report_error, send_telemetry_from_ctx, AISettings};
/// Maximum number of times a single MAA request is re-sent before the failure is
/// surfaced.
@@ -165,6 +171,66 @@ impl ResponseStream {
}
}
fn resolve_provider_config(model_id: &str, ctx: &ModelContext<Self>) -> ProviderConfig {
let settings = AISettings::as_ref(ctx);
// Check if OpenAI/LiteLLM provider is enabled
if *settings.openai_enabled.value() {
let base_url = settings.openai_base_url.value().clone();
let api_key = {
let key = settings.openai_api_key.value().clone();
if key.is_empty() {
None
} else {
Some(key)
}
};
// Use the model override from settings if set, otherwise use the selected model ID.
// This allows LiteLLM models to pass through their actual model_id to the proxy.
let model = {
let m = settings.openai_model.value().clone();
if m.is_empty() {
Some(model_id.to_string())
} else {
Some(m)
}
};
return ProviderConfig::OpenAI(OpenAIClientConfig {
base_url,
api_key,
model,
});
}
// Fall back to Bedrock
if *settings.bedrock_enabled.value() {
let auth_method = *settings.bedrock_auth_method.value();
let api_key_manager = ::ai::api_keys::ApiKeyManager::as_ref(ctx);
let mut config = BedrockClientConfig {
auth_method,
profile: settings.bedrock_profile.value().clone(),
region: settings.bedrock_region.value().clone(),
access_key_id: settings.bedrock_access_key_id.value().clone(),
secret_access_key: settings.bedrock_secret_access_key.value().clone(),
session_token: None,
cross_region_inference: *settings.bedrock_cross_region_inference.value(),
};
if let ::ai::api_keys::AwsCredentialsState::Loaded { credentials, .. } =
api_key_manager.aws_credentials_state()
{
config.auth_method = crate::settings::BedrockAuthMethod::StaticKeys;
config.access_key_id = credentials.access_key().to_string();
config.secret_access_key = credentials.secret_key().to_string();
config.session_token = credentials.session_token().map(|s| s.to_string());
}
return ProviderConfig::Bedrock(config.with_external_fallbacks());
}
ProviderConfig::None
}
pub fn new(
params: api::RequestParams,
ai_identifiers: AIIdentifiers,
@@ -176,10 +242,17 @@ impl ResponseStream {
let request_id = Uuid::new_v4();
let provider_config = Self::resolve_provider_config(params.model.as_str(), ctx);
let server_api = ServerApiProvider::as_ref(ctx).get_ai_client().clone();
let params_clone = params.clone();
let _ = ctx.spawn(
async move {
generate_multi_agent_output(provider_config, params_clone, cancellation_rx).await
generate_multi_agent_output(
provider_config,
server_api,
params_clone,
cancellation_rx,
)
.await
},
move |me, stream, ctx| {
me.handle_response_stream_result(request_id, stream, ctx);
@@ -260,15 +333,16 @@ impl ResponseStream {
self.current_request_id = Some(request_id);
let params = self.params.clone();
let provider_config = Self::resolve_provider_config(params.model.as_str(), ctx);
let _ =
ctx.spawn(
async move {
generate_multi_agent_output(provider_config, params, cancellation_rx).await
},
move |me, stream, ctx| {
me.handle_response_stream_result(request_id, stream, ctx);
},
);
let server_api = ServerApiProvider::as_ref(ctx).get_ai_client().clone();
let _ = ctx.spawn(
async move {
generate_multi_agent_output(provider_config, server_api, params, cancellation_rx)
.await
},
move |me, stream, ctx| {
me.handle_response_stream_result(request_id, stream, ctx);
},
);
}
/// Cancels the stream. The conversation_id is preserved in the emitted event for async handling.
@@ -451,7 +451,7 @@ impl BlocklistAIController {
exchange.input.iter().any(|input| input.is_user_query());
if let Some(output) = exchange.output_status.output() {
actions_to_queue.extend(output.get().actions().cloned().collect_vec().into_iter());
actions_to_queue.extend(output.get().actions().cloned().collect_vec());
}
}
@@ -41,6 +41,9 @@ pub enum SlashCommandRequest {
skill: ai::skills::ParsedSkill,
user_query: Option<String>,
},
Summarize {
prompt: Option<String>,
},
}
impl SlashCommandRequest {
@@ -106,7 +109,7 @@ impl SlashCommandRequest {
ctx,
);
let entrypoint = self.entrypoint();
let is_summarize = matches!(self, Self::Summarize { .. });
let _is_summarize = matches!(self, Self::Summarize { .. });
let inputs = self.input(
context,
prompt_files,
@@ -300,7 +303,8 @@ impl SlashCommandRequest {
SlashCommandRequest::CreateNewProject { .. }
| SlashCommandRequest::CreateEnvironment { .. }
| SlashCommandRequest::FetchReviewComments { .. }
| SlashCommandRequest::InvokeSkill { .. } => EntrypointType::UserInitiated,
| SlashCommandRequest::InvokeSkill { .. }
| SlashCommandRequest::Summarize { .. } => EntrypointType::UserInitiated,
}
}
}
@@ -170,15 +170,10 @@ async fn git_origin_url(git_root: &Path) -> Option<String> {
/// matching the env-creation flow).
fn parse_github_repo(remote_url: &str) -> Option<GithubRepo> {
let trimmed = remote_url.trim();
let path_part = if let Some(rest) = trimmed.strip_prefix("git@github.com:") {
rest
} else if let Some(rest) = trimmed.strip_prefix("https://github.com/") {
rest
} else if let Some(rest) = trimmed.strip_prefix("ssh://git@github.com/") {
rest
} else {
return None;
};
let path_part = None
.or_else(|| trimmed.strip_prefix("git@github.com:"))
.or_else(|| trimmed.strip_prefix("https://github.com/"))
.or_else(|| trimmed.strip_prefix("ssh://git@github.com/"))?;
let path_part = path_part.strip_suffix(".git").unwrap_or(path_part);
let mut segments = path_part.splitn(2, '/');
+11 -1
View File
@@ -8,11 +8,11 @@ use anyhow::anyhow;
use chrono::{DateTime, Local, NaiveDateTime};
#[cfg(feature = "local_fs")]
use diesel::SqliteConnection;
use galaxy_core::features::FeatureFlag;
use itertools::Itertools as _;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use warp_cli::agent::Harness;
use galaxy_core::features::FeatureFlag;
use warp_multi_agent_api::client_action::{Action, StartNewConversation};
use warp_multi_agent_api::response_event::stream_finished::{
ConversationUsageMetadata, TokenUsage,
@@ -1525,6 +1525,10 @@ impl BlocklistAIHistoryModel {
autoexecute_override: Some(source_conversation.autoexecute_override().into()),
last_event_sequence: None,
pinned: false,
progressive_summary: source_conversation
.progressive_summary()
.map(|s| s.to_string()),
messages_summarized_up_to: source_conversation.messages_summarized_up_to(),
};
let forked_conversation_id = AIConversationId::new();
if let Err(e) = sqlite_sender.send(ModelEvent::UpdateMultiAgentConversation {
@@ -1684,6 +1688,8 @@ impl BlocklistAIHistoryModel {
autoexecute_override: Some(conversation.autoexecute_override().into()),
last_event_sequence: None,
pinned: false,
progressive_summary: conversation.progressive_summary().map(|s| s.to_string()),
messages_summarized_up_to: conversation.messages_summarized_up_to(),
};
let forked_conversation_id = AIConversationId::new();
@@ -2698,6 +2704,10 @@ fn merged_remote_child_placeholder_conversation_data(
reverted_action_ids: None,
root_task_is_optimistic: None,
autoexecute_override: None,
progressive_summary: cloud_conversation
.progressive_summary()
.map(|s| s.to_string()),
messages_summarized_up_to: cloud_conversation.messages_summarized_up_to(),
}
}
+15 -13
View File
@@ -38,6 +38,7 @@ use crate::persistence::ModelEvent;
use crate::server::ids::ServerId;
use crate::server::telemetry::context_provider::AppTelemetryContextProvider;
use crate::terminal::model::session::SessionId;
use crate::test_util::ai_agent_tasks::{create_api_task, create_message};
use crate::test_util::settings::{
initialize_history_persistence_for_tests, initialize_settings_for_tests,
};
@@ -626,6 +627,7 @@ fn test_initialize_historical_conversations_resolves_parent_agent_id_children_vi
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
},
now,
None,
@@ -648,6 +650,7 @@ fn test_initialize_historical_conversations_resolves_parent_agent_id_children_vi
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
},
now - chrono::Duration::seconds(1),
Some("Parent query"),
@@ -698,6 +701,7 @@ fn test_initialize_historical_conversations_uses_root_task_description_title() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
})
.expect("conversation data should serialize"),
last_modified_at: now,
@@ -762,6 +766,7 @@ fn test_initialize_historical_conversations_eagerly_hydrates_orchestration_child
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
},
now,
// Child needs at least one root task so `AIConversation::new_restored` succeeds.
@@ -785,6 +790,7 @@ fn test_initialize_historical_conversations_eagerly_hydrates_orchestration_child
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
},
now - chrono::Duration::seconds(1),
Some("Parent query"),
@@ -1081,6 +1087,7 @@ fn create_server_metadata(
token_usage: vec![],
tool_usage_metadata: Default::default(),
context_window_segments: Vec::new(),
..Default::default()
};
ServerAIConversationMetadata {
@@ -1229,7 +1236,6 @@ fn test_merge_cloud_metadata_updates_already_restored_conversations() {
#[test]
fn test_merge_cloud_metadata_refreshes_stale_restored_conversation_metadata() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
let terminal_view_id = EntityId::new();
@@ -1277,7 +1283,6 @@ fn test_merge_cloud_metadata_refreshes_stale_restored_conversation_metadata() {
#[test]
fn test_merge_cloud_metadata_reuses_restored_conversation_id_for_token() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
let terminal_view_id = EntityId::new();
@@ -1685,7 +1690,6 @@ fn test_child_conversation_ids_of_unknown_parent() {
#[test]
fn test_restore_conversations_maintains_children_by_parent() {
App::test((), |mut app| async move {
let terminal_view_id = EntityId::new();
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1707,7 +1711,6 @@ fn test_restore_conversations_maintains_children_by_parent() {
#[test]
fn test_restore_conversations_indexes_child_by_parent_agent_id() {
App::test((), |mut app| async move {
let terminal_view_id = EntityId::new();
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1738,7 +1741,6 @@ fn test_restore_conversations_indexes_child_by_parent_agent_id() {
#[test]
fn test_restore_conversations_dedup_children_by_parent() {
App::test((), |mut app| async move {
let terminal_view_id = EntityId::new();
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -2284,7 +2286,6 @@ fn test_optimistic_root_restore_round_trip_yields_in_progress_optimistic_root()
/// (the synthesized optimistic root no longer produces a stub).
#[test]
fn test_truncate_from_exchange_to_empty_persist_event_has_empty_updated_tasks() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
@@ -2390,7 +2391,6 @@ fn test_truncate_from_exchange_to_empty_persist_event_has_empty_updated_tasks()
/// with the server id and no orphan optimistic tasks.
#[test]
fn test_two_restart_cycles_keep_exactly_one_server_root_task_row() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
@@ -2698,7 +2698,6 @@ fn test_find_by_token_after_merge_cloud_metadata() {
#[test]
fn test_find_by_token_after_restore_conversations() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
let terminal_view_id = EntityId::new();
@@ -2925,6 +2924,7 @@ fn test_find_by_token_after_insert_forked_conversation_from_tasks() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
};
let tasks = vec![warp_multi_agent_api::Task {
id: "root-task".to_string(),
@@ -2957,7 +2957,6 @@ fn test_find_by_token_after_insert_forked_conversation_from_tasks() {
#[test]
fn test_find_by_token_after_mark_conversations_historical_for_terminal_surface() {
App::test((), |mut app| async move {
let now = Local::now();
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -3117,6 +3116,7 @@ fn test_fork_then_bind_handoff_token_resolves_to_forked_conversation() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
}),
)
.expect("restored source conversation should build");
@@ -3165,7 +3165,6 @@ fn test_fork_then_bind_handoff_token_resolves_to_forked_conversation() {
#[test]
fn test_fork_then_bind_handoff_token_persists_to_restored_conversation() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
@@ -3201,6 +3200,7 @@ fn test_fork_then_bind_handoff_token_persists_to_restored_conversation() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
}),
)
.expect("restored source conversation should build");
@@ -3266,7 +3266,6 @@ fn test_fork_then_bind_handoff_token_persists_to_restored_conversation() {
#[test]
fn test_fork_then_bind_handoff_token_updates_cached_metadata_and_emits_refresh_events() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
@@ -3310,6 +3309,7 @@ fn test_fork_then_bind_handoff_token_updates_cached_metadata_and_emits_refresh_e
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
}),
)
.expect("restored source conversation should build");
@@ -3436,6 +3436,7 @@ fn test_fork_conversation_preserves_task_ids_when_requested() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
}),
)
.expect("restored source conversation should build");
@@ -3498,7 +3499,6 @@ fn setup_app_for_history_model_tests(app: &mut App) {
/// in-progress-ready state.
#[test]
fn test_new_conversation_does_not_inherit_waiting_for_events() {
App::test((), |mut app| async move {
setup_app_for_history_model_tests(&mut app);
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new_for_test());
@@ -3545,7 +3545,6 @@ fn test_new_conversation_does_not_inherit_waiting_for_events() {
#[test]
fn test_fork_conversation_title_override_replaces_prefix() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
@@ -3582,6 +3581,7 @@ fn test_fork_conversation_title_override_replaces_prefix() {
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
}),
)
.expect("restored source conversation should build");
@@ -3671,6 +3671,7 @@ fn hydrate_remote_child_placeholder_with_cloud_transcript_preserves_placeholder_
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
}),
)
.expect("placeholder conversation should build");
@@ -3717,6 +3718,7 @@ fn hydrate_remote_child_placeholder_with_cloud_transcript_preserves_placeholder_
autoexecute_override: None,
last_event_sequence: None,
pinned: false,
..Default::default()
}),
)
.expect("cloud conversation should build");
@@ -4,9 +4,8 @@ use std::time::Duration;
use ai::agent::action::{AskUserQuestionItem, AskUserQuestionOption, AskUserQuestionType};
use ai::agent::action_result::{AskUserQuestionAnswerItem, AskUserQuestionResult};
use itertools::Itertools;
use galaxy_core::ui::theme::color::internal_colors;
use galaxy_core::ui::theme::WarpTheme;
use galaxy_core::ui::theme::{GalaxyTheme, WarpTheme};
use galaxyui::elements::new_scrollable::SingleAxisConfig;
use galaxyui::elements::{
Border, ChildView, Clipped, ClippedScrollStateHandle, ConstrainedBox, Container, CornerRadius,
@@ -24,6 +23,7 @@ use galaxyui::{
LayoutContext, ModelHandle, PaintContext, SingletonEntity, SizeConstraint, TypedActionView,
View, ViewContext, ViewHandle,
};
use itertools::Itertools;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::agent::icons::yellow_stop_icon;
@@ -10,11 +10,6 @@ use ai::diff_validation::{
SearchAndReplace, V4AHunk,
};
use anyhow::Result;
use lazy_static::lazy_static;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_geometry::vector::vec2f;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng as _};
use galaxy_core::features::FeatureFlag;
use galaxy_core::platform::SessionPlatform;
use galaxy_core::settings::ToggleableSetting;
@@ -46,14 +41,11 @@ use galaxyui::{
AppContext, Element, Entity, FocusContext, ModelHandle, SingletonEntity, TypedActionView, View,
ViewContext, ViewHandle,
};
use rand::{distributions::Alphanumeric, thread_rng, Rng as _};
use std::{
collections::HashMap,
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
time::Duration,
};
use lazy_static::lazy_static;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_geometry::vector::vec2f;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng as _};
use super::malformed_line_heuristics::has_malformed_terminal_correction_signal;
use crate::ai::agent::icons::{self, yellow_stop_icon};
@@ -327,10 +327,8 @@ impl HostPicker {
match event {
EditorEvent::Enter => self.commit_custom(ctx),
EditorEvent::Escape => self.cancel_custom(ctx),
EditorEvent::Blurred => {
if self.is_custom_mode {
self.commit_custom(ctx);
}
EditorEvent::Blurred if self.is_custom_mode => {
self.commit_custom(ctx);
}
_ => {}
}
@@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::rc::Rc;
use pathfinder_color::ColorU;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::color::internal_colors;
use pathfinder_color::ColorU;
use warpui::elements::{
Border, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, DispatchEventResult,
EventHandler, Expanded, Flex, FormattedTextElement, Hoverable, MainAxisAlignment, MainAxisSize,
@@ -10,11 +10,11 @@ use std::collections::HashMap;
use ai::agent::action::RunAgentsExecutionMode;
use ai::agent::orchestration_config::{OrchestrationConfig, OrchestrationExecutionMode};
use galaxy_core::ui::theme::Fill;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::{vec2f, Vector2F};
use settings::Setting;
use warp_cli::agent::Harness;
use galaxy_core::ui::theme::Fill;
use warpui::elements::{
Border, ChildView, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Empty,
Expanded, Flex, Hoverable, MainAxisAlignment, MainAxisSize, MouseStateHandle, ParentElement,
@@ -11,9 +11,6 @@
use std::borrow::Cow;
use lazy_static::lazy_static;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_color::ColorU;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::color::internal_colors::neutral_2;
use galaxyui::elements::{
@@ -23,6 +20,9 @@ use galaxyui::elements::{
use galaxyui::fonts::FamilyId;
use galaxyui::keymap::Keystroke;
use galaxyui::{AppContext, Element, SingletonEntity};
use lazy_static::lazy_static;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use pathfinder_color::ColorU;
use super::inline_action_header::HeaderConfig;
use crate::ai::blocklist::block::view_impl::WithContentItemSpacing;
@@ -4,10 +4,6 @@ use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
use lazy_static::lazy_static;
use parking_lot::FairMutex;
use pathfinder_geometry::vector::vec2f;
use settings::Setting as _;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::Icon;
use galaxy_editor::render::element::VerticalExpansionBehavior;
@@ -22,6 +18,10 @@ use galaxyui::{
AppContext, Element, Entity, EntityId, EventContext, ModelHandle, SingletonEntity,
TypedActionView, UpdateView, View, ViewContext, ViewHandle,
};
use lazy_static::lazy_static;
use parking_lot::FairMutex;
use pathfinder_geometry::vector::vec2f;
use settings::Setting as _;
use super::inline_action_icons::{self, icon_size};
use crate::ai::agent::conversation::ConversationStatus;
@@ -1,8 +1,8 @@
//! Module to attribute AI-generated requested commands
//! to known documents (e.g. Warp Drive objects).
use markdown_parser::{parse_markdown, FormattedTextLine};
use galaxyui::{AppContext, SingletonEntity};
use markdown_parser::{parse_markdown, FormattedTextLine};
use crate::ai::agent::AIAgentCitation;
use crate::cloud_object::model::persistence::CloudModel;
@@ -10,8 +10,8 @@ use ai::agent::action::{RunAgentsAgentRunConfig, RunAgentsExecutionMode, RunAgen
use ai::agent::action_result::{RunAgentsAgentOutcomeKind, RunAgentsResult};
use ai::agent::orchestration_config::{OrchestrationConfig, OrchestrationConfigStatus};
use ai::skills::SkillReference;
use pathfinder_geometry::vector::vec2f;
use galaxy_core::send_telemetry_from_ctx;
use pathfinder_geometry::vector::vec2f;
use warpui::elements::{
Border, ChildAnchor, ChildView, Container, CornerRadius, CrossAxisAlignment, Empty, Flex,
OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Radius, Stack, Text, Wrap,
@@ -373,9 +373,11 @@ mod format_terminal_state_tests {
}
mod override_from_approved_config_tests {
use ai::agent::action::RunAgentsExecutionMode;
use ai::agent::orchestration_config::{OrchestrationConfig, OrchestrationExecutionMode};
use super::super::RunAgentsEditState;
use super::*;
fn local_config(model: &str, harness: &str) -> OrchestrationConfig {
OrchestrationConfig {
@@ -1,8 +1,5 @@
use std::sync::Arc;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng as _};
use galaxy_core::settings::ToggleableSetting;
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::{
@@ -15,7 +12,9 @@ use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles
use galaxyui::{
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
};
use rand::{distributions::Alphanumeric, thread_rng, Rng as _};
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng as _};
use crate::ai::agent::{AIAgentActionId, AIIdentifiers};
use crate::ai::predict::prompt_suggestions::{
@@ -1,3 +1,5 @@
use std::time::Duration;
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::shimmering_text::{
ShimmerConfig, ShimmeringTextElement, ShimmeringTextStateHandle,
@@ -9,7 +11,6 @@ use galaxyui::elements::{
use galaxyui::r#async::{SpawnedFutureHandle, Timer};
use galaxyui::{AppContext, Entity, SingletonEntity, View, ViewContext};
use instant::Instant;
use std::time::Duration;
use super::inline_action_header::{
INLINE_ACTION_HEADER_VERTICAL_PADDING, INLINE_ACTION_HORIZONTAL_PADDING,
+1 -1
View File
@@ -8,6 +8,7 @@
use std::sync::Arc;
use futures::stream::AbortHandle;
use galaxy_completer::completer::CompletionContext;
use galaxy_core::features::FeatureFlag;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
use input_classifier::util::{is_agent_follow_up_input, is_one_off_natural_language_word};
@@ -17,7 +18,6 @@ use parking_lot::FairMutex;
use serde::{Deserialize, Serialize};
use session_sharing_protocol::common::{InputMode, InputType as ProtocolInputType};
use settings::Setting as _;
use galaxy_completer::completer::CompletionContext;
/// The source of the final input type decision applied to the user input.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -1,3 +1,5 @@
#![allow(deprecated, dead_code)]
use std::collections::{HashMap, HashSet, VecDeque};
use std::sync::Arc;
use std::time::Duration;
@@ -5,14 +7,14 @@ use std::time::Duration;
use anyhow::anyhow;
use async_trait::async_trait;
use futures::channel::mpsc;
use uuid::Uuid;
use galaxy_cli::agent::Harness;
use galaxy_core::features::FeatureFlag;
use warp_multi_agent_api as api;
use galaxyui::r#async::{SpawnedFutureHandle, Timer};
use galaxyui::{
Entity, EntityId, GetSingletonModelHandle, ModelContext, SingletonEntity, UpdateModel,
};
use uuid::Uuid;
use warp_multi_agent_api as api;
use super::history_model::{BlocklistAIHistoryEvent, BlocklistAIHistoryModel};
use super::orchestration_events::{
@@ -1,7 +1,8 @@
use std::sync::Arc;
use mockall::predicate::eq;
use chrono::Utc;
use galaxy_core::features::FeatureFlag;
use mockall::predicate::eq;
use warpui::App;
use super::*;
@@ -162,6 +163,7 @@ fn ai_conversation_new_restored_preserves_last_event_sequence() {
autoexecute_override: None,
last_event_sequence: Some(42),
pinned: false,
..Default::default()
};
let conversation =
AIConversation::new_restored(AIConversationId::new(), vec![task], Some(data))
@@ -221,7 +223,6 @@ fn make_ambient_task_with_task_id(
fn make_server_metadata_with_harness(
harness: AIAgentHarness,
) -> crate::ai::agent::conversation::ServerAIConversationMetadata {
use crate::ai::agent::api::ServerConversationToken;
use crate::cloud_object::{Revision, ServerMetadata, ServerPermissions};
use crate::persistence::model::ConversationUsageMetadata;
@@ -240,6 +241,7 @@ fn make_server_metadata_with_harness(
token_usage: vec![],
tool_usage_metadata: Default::default(),
context_window_segments: Vec::new(),
..Default::default()
},
metadata: ServerMetadata {
uid: ServerId::default(),
@@ -262,9 +264,6 @@ fn make_server_metadata_with_harness(
#[test]
fn dormant_local_claude_child_skips_generic_sse_but_allows_wake_listener() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -317,9 +316,6 @@ fn dormant_local_claude_child_skips_generic_sse_but_allows_wake_listener() {
#[test]
fn persist_event_cursor_keeps_the_max_sequence_and_updates_history_model() {
App::test((), |mut app| async move {
initialize_settings_for_tests(&mut app);
let (sender, receiver) = std::sync::mpsc::sync_channel::<ModelEvent>(4);
@@ -378,8 +374,6 @@ fn persist_event_cursor_keeps_the_max_sequence_and_updates_history_model() {
#[test]
fn wake_ready_does_not_advance_cursor_before_wake_preparation() {
use crate::ai::agent::conversation::AIConversation;
use crate::ai::agent_events::AgentMessageEventMetadata;
use crate::server::server_api::ai::{AIClient, MockAIClient};
@@ -438,10 +432,8 @@ fn wake_ready_does_not_advance_cursor_before_wake_preparation() {
#[test]
fn dormant_local_claude_child_uses_task_harness_when_server_metadata_missing() {
use warp_cli::agent::Harness;
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -562,9 +554,6 @@ async fn dormant_claude_wake_consumer_stops_on_first_target_event() {
#[test]
fn restored_conversations_initialize_v2_streaming_state() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -643,9 +632,6 @@ async fn sse_forwarding_consumer_skips_message_hydration_when_disabled() {
}
#[test]
fn finish_restore_fetch_uses_server_cursor_when_sqlite_is_absent() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -697,9 +683,6 @@ fn finish_restore_fetch_uses_server_cursor_when_sqlite_is_absent() {
#[test]
fn handle_event_batch_persists_max_seq_to_history_model() {
App::test((), |mut app| async move {
// `update_event_sequence` calls `write_updated_conversation_state`,
// which reads `GeneralSettings`, `AppExecutionMode`, and the global
@@ -922,8 +905,6 @@ fn finish_restore_fetch_no_ops_when_conversation_deleted_mid_flight() {
// uses the missing entry as a sentinel and must not re-populate
// streamer state for the deleted conversation.
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -986,8 +967,6 @@ fn finish_restore_fetch_err_does_not_resurrect_deleted_conversation() {
// defeat the deletion sentinel inside the retry timer and cause an
// indefinite retry loop).
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1046,8 +1025,6 @@ fn on_conversation_removed_prunes_stale_child_run_id_from_parent() {
// model after the removal, which always returned `None` because the
// history model emits `RemoveConversation` after dropping the record.
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1099,9 +1076,6 @@ fn on_conversation_removed_prunes_stale_child_run_id_from_parent() {
#[test]
fn on_conversation_removed_prunes_killed_child_run_id_from_parent_but_keeps_tombstone() {
App::test((), |mut app| async move {
app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1447,7 +1421,6 @@ fn viewer_mode_consumer_refcount_handles_multiple_panes_and_double_unregister()
#[test]
fn is_remote_run_view_excludes_shared_session_viewer() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1479,7 +1452,6 @@ fn is_remote_run_view_excludes_shared_session_viewer() {
#[test]
fn is_remote_run_view_excludes_remote_child() {
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1590,8 +1562,6 @@ fn finish_restore_fetch_reconnects_sse_when_children_added_to_open_connection()
// before children are known, finish_restore_fetch must reconnect SSE
// with the updated run_id set rather than leaving children unwatched.
App::test((), |mut app| async move {
let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[]));
@@ -1,5 +1,8 @@
#![allow(dead_code)]
use std::collections::{HashMap, HashSet};
use uuid::Uuid;
use warp_multi_agent_api as api;
use warpui::{Entity, ModelContext, SingletonEntity};
@@ -7,9 +7,9 @@ use std::time::Duration;
use chrono::Utc;
#[cfg(not(target_family = "wasm"))]
use command::r#async::Command;
use galaxy_core::features::FeatureFlag;
use parking_lot::FairMutex;
use serde_json::json;
use galaxy_core::features::FeatureFlag;
use warpui::r#async::{FutureExt as AsyncFutureExt, SpawnedFutureHandle, Timer};
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
@@ -5,8 +5,8 @@ use std::sync::Arc;
use ai::agent::action::{AIAgentActionType, FileEdit};
use ai::diff_validation::ParsedDiff;
use chrono::{DateTime, Utc};
use parking_lot::FairMutex;
use galaxy_core::features::FeatureFlag;
use parking_lot::FairMutex;
use warpui::r#async::SpawnedFutureHandle;
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
@@ -559,9 +559,10 @@ fn coalesce_messages_from_client_actions(
use std::collections::HashMap;
use field_mask::FieldMaskOperation;
use warp_multi_agent_api as api;
use warp_multi_agent_api::client_action::Action;
let mut messages_by_id: HashMap<String, api::Message> = HashMap::new();
let mut messages_by_id: HashMap<String, warp_multi_agent_api::Message> = HashMap::new();
let mut message_order: Vec<String> = Vec::new();
for action in client_actions {
+4 -6
View File
@@ -2,16 +2,14 @@ use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use anyhow::Result;
use galaxy_completer::parsers::simple::decompose_command;
use galaxy_core::user_preferences::GetUserPreferences;
use galaxy_core::{features::FeatureFlag, settings::Setting};
use galaxy_util::path::EscapeChar;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, SingletonEntity};
use serde::{Deserialize, Serialize};
use galaxy_completer::parsers::simple::{command_without_leading_env_vars, decompose_command};
use galaxy_core::execution_mode::AppExecutionMode;
use galaxy_core::features::FeatureFlag;
use galaxy_core::settings::Setting;
use galaxy_core::user_preferences::GetUserPreferences;
use galaxy_util::path::EscapeChar;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, SingletonEntity};
use serde::{Deserialize, Serialize};
use super::BlocklistAIHistoryModel;
use crate::ai::agent::conversation::AIConversationId;
+1 -1
View File
@@ -1,9 +1,9 @@
use std::path::PathBuf;
use uuid::Uuid;
use galaxy_core::execution_mode::ExecutionMode;
use galaxy_util::path::EscapeChar;
use galaxyui::{App, EntityId, ModelHandle};
use uuid::Uuid;
use super::{BlocklistAIHistoryModel, BlocklistAIPermissions};
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
@@ -1,6 +1,5 @@
use std::sync::Arc;
use pathfinder_geometry::vector::vec2f;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::color::internal_colors;
@@ -17,6 +16,7 @@ use galaxyui::{
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity as _, TypedActionView,
View, ViewContext, ViewHandle,
};
use pathfinder_geometry::vector::vec2f;
use crate::ai::agent::icons::todo_list_icon;
use crate::ai::agent::todos::popup::{AgentTodosPopupEvent, AgentTodosPopupView};
+1 -1
View File
@@ -1,11 +1,11 @@
use ai::api_keys::ApiKeyManager;
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::{
ConstrainedBox, Container, CrossAxisAlignment, Flex, FormattedTextElement,
HighlightedHyperlink, HyperlinkLens, MainAxisAlignment, MainAxisSize, ParentElement,
};
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
use crate::ai::blocklist::error_color;
use crate::ai::AIRequestUsageModel;
+1 -1
View File
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use uuid::Uuid;
use galaxyui::{AppContext, Entity, EntityId, ModelContext, SingletonEntity};
use uuid::Uuid;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::blocklist::{BlocklistAIHistoryEvent, BlocklistAIHistoryModel, PendingAttachment};
@@ -2,7 +2,6 @@ use std::collections::HashMap;
use std::default::Default;
use std::sync::Arc;
use pathfinder_geometry::vector::vec2f;
use galaxy_core::send_telemetry_from_ctx;
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::{
@@ -15,7 +14,7 @@ use galaxyui::ui_components::components::{Coords, UiComponentStyles};
use galaxyui::{
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext, ViewHandle,
};
use std::{collections::HashMap, default::Default, sync::Arc};
use pathfinder_geometry::vector::vec2f;
use crate::ai::agent::SuggestedAgentModeWorkflow;
use crate::modal::{Modal, ModalEvent};
+1 -1
View File
@@ -1,5 +1,5 @@
use pathfinder_geometry::vector::vec2f;
use galaxy_core::ui::appearance::Appearance;
use pathfinder_geometry::vector::vec2f;
use warp_editor::editor::NavigationKey;
use warpui::elements::{
Align, Border, ChildAnchor, ChildView, ClippedScrollStateHandle, ClippedScrollable,
+3 -5
View File
@@ -1,4 +1,3 @@
use pathfinder_color::ColorU;
use galaxy_core::send_telemetry_from_ctx;
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::Fill;
@@ -6,6 +5,7 @@ use galaxyui::elements::{Align, ChildView, Container, ParentElement, SavePositio
use galaxyui::{
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext, ViewHandle,
};
use pathfinder_color::ColorU;
use super::suggested_agent_mode_workflow_modal::SuggestedAgentModeWorkflowAndId;
use super::suggested_rule_modal::SuggestedRuleAndId;
@@ -312,12 +312,10 @@ impl SuggestionChipView {
| CloudModelEvent::ObjectDeleted {
type_and_id: CloudObjectTypeAndId::GenericStringObject { id, .. },
..
} => {
} if self.sync_id == *id => {
// If the rule or workflow has been deleted, then we should reset it such that
// the suggestion can be added again.
if self.sync_id == *id {
self.reset_suggestion(ctx);
}
self.reset_suggestion(ctx);
}
_ => {}
}
@@ -1,12 +1,14 @@
use pathfinder_geometry::vector::vec2f;
use galaxy_core::ui::theme::Fill;
use galaxyui::elements::{Align, Container, CrossAxisAlignment, Dismiss, Flex, ParentElement, Stack};
use galaxyui::elements::{
Align, Container, CrossAxisAlignment, Dismiss, Flex, ParentElement, Stack,
};
use galaxyui::fonts::Weight;
use galaxyui::keymap::FixedBinding;
use galaxyui::platform::Cursor;
use galaxyui::ui_components::button::ButtonVariant;
use galaxyui::ui_components::components::{BorderStyle, Coords, UiComponent, UiComponentStyles};
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
use pathfinder_geometry::vector::vec2f;
use crate::appearance::Appearance;
use crate::ui_components::buttons;
+2
View File
@@ -1,3 +1,5 @@
use galaxy_core::features::FeatureFlag;
use galaxy_core::telemetry::{EnablementState, TelemetryEvent, TelemetryEventDesc};
use serde::Serialize;
use serde_json::{json, Value};
use strum_macros::{EnumDiscriminants, EnumIter};
@@ -1,10 +1,11 @@
use galaxyui::elements::{
Container, CornerRadius, CrossAxisAlignment, Flex, ParentElement, Radius, Text,
};
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
use crate::ai::bedrock::convert::{ContentPart, ConversationMessage, MessageContent, MessageRole};
use crate::appearance::Appearance;
use crate::ui_components::blended_colors;
use galaxyui::{
elements::{Container, CornerRadius, CrossAxisAlignment, Flex, ParentElement, Radius, Text},
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext,
};
pub struct ContextWindowView {
messages: Vec<ConversationMessage>,
@@ -1,8 +1,8 @@
#![allow(dead_code)]
use std::cmp::Ordering;
use std::collections::HashMap;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use galaxy_core::features::FeatureFlag;
use galaxy_core::ui::theme::color::internal_colors;
use galaxy_core::ui::Icon;
@@ -15,6 +15,8 @@ use galaxyui::fonts::{Properties, Weight};
use galaxyui::platform::Cursor;
use galaxyui::text_layout::ClipConfig;
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::blocklist::agent_view::orchestration_pill_bar::{
@@ -25,7 +27,7 @@ use crate::ai::blocklist::usage::render_context_window_usage_icon;
use crate::ai::blocklist::usage::rollup::{
compute_orchestration_rollup, AgentAvatar, OrchestrationCreditRollup, PerAgentCreditEntry,
};
use crate::ai::blocklist::view_util::format_credits;
use crate::ai::blocklist::view_util::{format_credits, format_token_count};
use crate::ai::blocklist::{BlocklistAIHistoryEvent, BlocklistAIHistoryModel};
use crate::appearance::Appearance;
use crate::persistence::model::{
@@ -40,6 +42,7 @@ pub enum DisplayMode {
Footer,
}
#[derive(Default)]
pub struct ConversationUsageInfo {
pub credits_spent: f32,
pub platform_credits_spent: f32,
@@ -341,10 +344,10 @@ impl ConversationUsageView {
.map(|r| r.total_credits)
.unwrap_or(self.usage_info.credits_spent + self.usage_info.platform_credits_spent);
if self.display_mode == DisplayMode::Footer
&& self.usage_info.credits_spent_for_last_block.is_some()
{
let last_block_credits = self.usage_info.credits_spent_for_last_block.unwrap();
if let (DisplayMode::Footer, Some(last_block_credits)) = (
self.display_mode,
self.usage_info.credits_spent_for_last_block,
) {
labels.push(render_label_text(
"Credits spent (last response)",
appearance,
@@ -44,6 +44,7 @@ fn placeholder_usage_info() -> ConversationUsageInfo {
lines_added: 0,
lines_removed: 0,
commands_executed: 0,
..Default::default()
}
}
+5 -3
View File
@@ -1,8 +1,8 @@
#![allow(dead_code)]
//! This module contains common utilities for rendering Blocklist AI UI.
use std::sync::LazyLock;
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use galaxy_core::ui::appearance::Appearance;
use galaxyui::elements::{
ChildAnchor, ConstrainedBox, Container, CrossAxisAlignment, Flex, Hoverable, MainAxisAlignment,
@@ -14,8 +14,10 @@ use galaxyui::ui_components::button::ButtonVariant;
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
use galaxyui::ui_components::text::Span;
use galaxyui::{AppContext, Element, EntityId, EventContext, SingletonEntity};
use pathfinder_color::ColorU;
use pathfinder_geometry::vector::vec2f;
use crate::themes::theme::{AnsiColorIdentifier, Fill, WarpTheme};
use crate::themes::theme::{AnsiColorIdentifier, Fill, GalaxyTheme, WarpTheme};
use crate::ui_components::icons::Icon;
const PROVIDER_BUTTON_ICON_SIZE: f32 = 14.;