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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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::{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, '/');
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,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,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,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,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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.;
|
||||
|
||||
Reference in New Issue
Block a user