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:
@@ -333,7 +333,9 @@ tracing-subscriber.workspace = true
|
||||
# AWS SDK (loading credentials for BYO LLM)
|
||||
aws-config = { version = "1.8.16", features = ["credentials-login"] }
|
||||
aws-credential-types = "1"
|
||||
aws-sdk-bedrockruntime = { version = "1", default-features = false, features = ["default-https-client", "rt-tokio"] }
|
||||
aws-sdk-sts = { version = "1", default-features = false, features = ["default-https-client", "rt-tokio"] }
|
||||
aws-smithy-types = "1"
|
||||
aws-types = "1"
|
||||
|
||||
notify-debouncer-full.workspace = true
|
||||
|
||||
@@ -14,14 +14,14 @@ pub use convert_from::{
|
||||
MaybeAIAgentOutputMessage, MessageToAIAgentOutputMessageError,
|
||||
};
|
||||
use futures_lite::Stream;
|
||||
use mcp::TemplatableMCPServerInfo;
|
||||
pub use r#impl::generate_multi_agent_output;
|
||||
use serde::Serialize;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::execution_mode::AppExecutionMode;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::user_preferences::GetUserPreferences;
|
||||
use galaxyui::{AppContext, EntityId, SingletonEntity as _};
|
||||
use mcp::TemplatableMCPServerInfo;
|
||||
pub use r#impl::generate_multi_agent_output;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{AIAgentInput, MCPContext, MCPServer, RequestMetadata, Suggestions};
|
||||
use crate::ai::agent::conversation::AIConversationId;
|
||||
@@ -211,6 +211,11 @@ impl RequestParams {
|
||||
supported_tools_override: None,
|
||||
parent_agent_id: None,
|
||||
agent_name: None,
|
||||
root_task_id: None,
|
||||
bedrock_message_history: vec![],
|
||||
bedrock_progressive_summary: None,
|
||||
bedrock_tool_result_archive: vec![],
|
||||
bedrock_messages_sent: std::sync::Arc::new(std::sync::Mutex::new(vec![])),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +308,7 @@ impl RequestParams {
|
||||
let geap_binding: Option<::ai::api_keys::GeapMintBinding> = None;
|
||||
let api_keys = api_key_manager.api_keys_for_request(
|
||||
is_byo_enabled,
|
||||
user_workspaces.is_aws_bedrock_credentials_enabled(app),
|
||||
user_workspaces.is_bedrock_enabled(app),
|
||||
geap_binding,
|
||||
);
|
||||
let is_custom_inference_enabled = user_workspaces.is_custom_inference_enabled(app);
|
||||
|
||||
@@ -14,8 +14,8 @@ use ai::agent::action_result::{
|
||||
};
|
||||
use ai::skills::{ParsedSkill, SkillPathOrigin};
|
||||
use chrono::{DateTime, Local, TimeZone};
|
||||
use persistence::model::AgentConversationData;
|
||||
use galaxy_core::command::ExitCode;
|
||||
use persistence::model::AgentConversationData;
|
||||
use warp_multi_agent_api as api;
|
||||
use warp_multi_agent_api::ask_user_question_result::answer_item::Answer as AskUserQuestionAnswer;
|
||||
|
||||
@@ -89,6 +89,8 @@ pub fn convert_conversation_data_to_ai_conversation(
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
progressive_summary: None,
|
||||
messages_summarized_up_to: 0,
|
||||
},
|
||||
RestorationMode::Continue => AgentConversationData {
|
||||
server_conversation_token: Some(
|
||||
@@ -110,6 +112,8 @@ pub fn convert_conversation_data_to_ai_conversation(
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
progressive_summary: None,
|
||||
messages_summarized_up_to: 0,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ fn test_server_metadata(
|
||||
token_usage: vec![],
|
||||
tool_usage_metadata: Default::default(),
|
||||
context_window_segments: Vec::new(),
|
||||
..Default::default()
|
||||
},
|
||||
metadata: ServerMetadata {
|
||||
uid: ServerId::default(),
|
||||
|
||||
@@ -8,11 +8,15 @@ use warp_multi_agent_api as api;
|
||||
use super::convert_to::convert_input;
|
||||
use super::{ConvertToAPITypeError, RequestParams, ResponseStream};
|
||||
use crate::ai::agent::redaction;
|
||||
use crate::server::server_api::{AIApiError, ServerApi};
|
||||
use crate::ai::openai::translator as openai_translator;
|
||||
use crate::ai::provider::ProviderConfig;
|
||||
use crate::server::server_api::ai::AIClient;
|
||||
use crate::server::server_api::AIApiError;
|
||||
use crate::terminal::model::session::SessionType;
|
||||
|
||||
pub async fn generate_multi_agent_output(
|
||||
provider_config: ProviderConfig,
|
||||
server_api: Arc<dyn AIClient>,
|
||||
mut params: RequestParams,
|
||||
cancellation_rx: futures::channel::oneshot::Receiver<()>,
|
||||
) -> Result<ResponseStream, ConvertToAPITypeError> {
|
||||
@@ -65,9 +69,9 @@ pub async fn generate_multi_agent_output(
|
||||
input: Some(convert_input(params.input)?),
|
||||
settings: Some(api::request::Settings {
|
||||
model_config: Some(api::request::settings::ModelConfig {
|
||||
base: params.model.into(),
|
||||
cli_agent: params.cli_agent_model.into(),
|
||||
computer_use_agent: params.computer_use_model.into(),
|
||||
base: params.model.clone().into(),
|
||||
cli_agent: params.cli_agent_model.clone().into(),
|
||||
computer_use_agent: params.computer_use_model.clone().into(),
|
||||
base_model_context_window_limit: params.context_window_limit.unwrap_or(0),
|
||||
..Default::default()
|
||||
}),
|
||||
@@ -136,24 +140,11 @@ pub async fn generate_multi_agent_output(
|
||||
mcp_context: params.mcp_context.map(Into::into),
|
||||
};
|
||||
|
||||
let response_stream =
|
||||
warp_multi_agent_client::generate_multi_agent_output(server_api.as_ref(), &request).await;
|
||||
match response_stream {
|
||||
Ok(stream) => {
|
||||
let output_stream = stream
|
||||
.then(|result| async {
|
||||
match result {
|
||||
Ok(event) => Ok(event),
|
||||
Err(error) => Err(convert_multi_agent_client_error(error).await),
|
||||
}
|
||||
})
|
||||
.take_until(cancellation_rx);
|
||||
Ok(Box::pin(output_stream))
|
||||
}
|
||||
match provider_config {
|
||||
ProviderConfig::OpenAI(config) => {
|
||||
let translator_request = openai_translator::TranslatorRequest {
|
||||
config,
|
||||
model_id,
|
||||
model_id: params.model.as_str().to_string(),
|
||||
root_task_id: params.root_task_id.clone(),
|
||||
message_history: params.bedrock_message_history.clone(),
|
||||
tool_result_archive: params.bedrock_tool_result_archive.clone(),
|
||||
@@ -178,19 +169,60 @@ pub async fn generate_multi_agent_output(
|
||||
}
|
||||
}
|
||||
}
|
||||
ProviderConfig::Bedrock(config) => {
|
||||
let translator_request = crate::ai::bedrock::translator::TranslatorRequest {
|
||||
config,
|
||||
model_id: params.model.as_str().to_string(),
|
||||
root_task_id: params.root_task_id.clone(),
|
||||
bedrock_message_history: params.bedrock_message_history.clone(),
|
||||
bedrock_tool_result_archive: params.bedrock_tool_result_archive.clone(),
|
||||
bedrock_progressive_summary: params.bedrock_progressive_summary.clone(),
|
||||
bedrock_messages_sent: params.bedrock_messages_sent.clone(),
|
||||
};
|
||||
|
||||
match crate::ai::bedrock::translator::execute(translator_request, &mut request).await {
|
||||
Ok(stream) => {
|
||||
let output_stream = stream.take_until(cancellation_rx);
|
||||
Ok(Box::pin(output_stream))
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("[bedrock] Translator error: {e}");
|
||||
let err = Arc::new(crate::server::server_api::AIApiError::Stream {
|
||||
stream_type: "bedrock",
|
||||
source: anyhow::anyhow!("{e}"),
|
||||
});
|
||||
let (tx, rx) = async_channel::unbounded();
|
||||
let _ = tx.send(Err(err)).await;
|
||||
Ok(Box::pin(rx))
|
||||
}
|
||||
}
|
||||
}
|
||||
ProviderConfig::None => {
|
||||
log::error!("No AI provider configured. Cannot process request.");
|
||||
let err = Arc::new(crate::server::server_api::AIApiError::Stream {
|
||||
stream_type: "provider_dispatch",
|
||||
source: anyhow::anyhow!(
|
||||
"No AI backend available. Please configure a provider in Settings > AI."
|
||||
),
|
||||
});
|
||||
let (tx, rx) = async_channel::unbounded();
|
||||
let _ = tx
|
||||
.send(Err(convert_multi_agent_client_error(e).await))
|
||||
.await;
|
||||
Ok(Box::pin(rx))
|
||||
let response_stream = warp_multi_agent_client::generate_multi_agent_output(
|
||||
server_api.base_client().as_ref(),
|
||||
&request,
|
||||
)
|
||||
.await;
|
||||
match response_stream {
|
||||
Ok(stream) => {
|
||||
let output_stream = stream
|
||||
.then(|result| async {
|
||||
match result {
|
||||
Ok(event) => Ok(event),
|
||||
Err(error) => Err(convert_multi_agent_client_error(error).await),
|
||||
}
|
||||
})
|
||||
.take_until(cancellation_rx);
|
||||
Ok(Box::pin(output_stream))
|
||||
}
|
||||
Err(e) => {
|
||||
let (tx, rx) = async_channel::unbounded();
|
||||
let _ = tx
|
||||
.send(Err(convert_multi_agent_client_error(e).await))
|
||||
.await;
|
||||
Ok(Box::pin(rx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,6 @@ use ai::agent::orchestration_config::{OrchestrationConfig, OrchestrationConfigSt
|
||||
use ai::document::AIDocumentId;
|
||||
use ai::skills::SkillPathOrigin;
|
||||
use chrono::{DateTime, Local, TimeZone};
|
||||
use itertools::Itertools as _;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use vec1::{Size0Error, Vec1};
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxy_core::command::ExitCode;
|
||||
use galaxy_core::execution_mode::AppExecutionMode;
|
||||
@@ -16,12 +12,16 @@ use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::send_telemetry_from_ctx;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxy_core::ui::theme::WarpTheme;
|
||||
use galaxy_core::ui::theme::GalaxyTheme;
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::{AppContext, EntityId, ModelContext, SingletonEntity};
|
||||
use itertools::Itertools as _;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use vec1::{Size0Error, Vec1};
|
||||
use warp_multi_agent_api::response_event::stream_finished;
|
||||
use warp_multi_agent_api::response_event::stream_finished::TokenUsage;
|
||||
use warp_multi_agent_api::{self as api};
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::{AppContext, EntityId, ModelContext, SingletonEntity};
|
||||
|
||||
use super::api::ServerConversationToken;
|
||||
use super::task::helper::*;
|
||||
@@ -327,6 +327,12 @@ pub struct AIConversation {
|
||||
/// Whether the user has pinned this child agent in the orchestration
|
||||
/// pill bar. Persisted via `AgentConversationData.pinned`.
|
||||
pinned: bool,
|
||||
bedrock_message_history: Vec<crate::ai::bedrock::convert::ConversationMessage>,
|
||||
tool_result_archive: Vec<crate::ai::bedrock::convert::ConversationMessage>,
|
||||
progressive_summary: Option<String>,
|
||||
messages_summarized_up_to: usize,
|
||||
current_context_tokens: u32,
|
||||
has_pending_progressive_summary: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn artifact_from_fork_proto(
|
||||
@@ -382,6 +388,12 @@ impl AIConversation {
|
||||
last_event_sequence: None,
|
||||
orchestration_configs: HashMap::new(),
|
||||
pinned: false,
|
||||
bedrock_message_history: Vec::new(),
|
||||
tool_result_archive: Vec::new(),
|
||||
progressive_summary: None,
|
||||
messages_summarized_up_to: 0,
|
||||
current_context_tokens: 0,
|
||||
has_pending_progressive_summary: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,6 +425,12 @@ impl AIConversation {
|
||||
tasks: Vec<api::Task>,
|
||||
conversation_data: Option<AgentConversationData>,
|
||||
) -> Result<Self, RestoreConversationError> {
|
||||
let bedrock_message_history: Vec<crate::ai::bedrock::convert::ConversationMessage> = tasks
|
||||
.iter()
|
||||
.flat_map(|task| task.messages.iter())
|
||||
.filter_map(crate::ai::bedrock::request_translator::convert_proto_message)
|
||||
.collect();
|
||||
|
||||
let (task_store, todo_lists, status) = if tasks.is_empty() {
|
||||
// Bypass `derive_status_from_root_task`: it would return `Success`
|
||||
// for a root with no exchanges, silently misclassifying a restored
|
||||
@@ -518,6 +536,8 @@ impl AIConversation {
|
||||
autoexecute_override,
|
||||
last_event_sequence,
|
||||
pinned,
|
||||
progressive_summary,
|
||||
messages_summarized_up_to,
|
||||
) = if let Some(data) = conversation_data {
|
||||
let server_conversation_token = data
|
||||
.server_conversation_token
|
||||
@@ -565,6 +585,8 @@ impl AIConversation {
|
||||
autoexecute_override,
|
||||
data.last_event_sequence,
|
||||
data.pinned,
|
||||
data.progressive_summary.clone(),
|
||||
data.messages_summarized_up_to,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
@@ -582,9 +604,33 @@ impl AIConversation {
|
||||
AIConversationAutoexecuteMode::default(),
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
let restored_token_usage = {
|
||||
let mut map = HashMap::new();
|
||||
let cache_read = conversation_usage_metadata.total_cache_read_tokens;
|
||||
let cache_write = conversation_usage_metadata.total_cache_write_tokens;
|
||||
let cache_miss = conversation_usage_metadata.total_cache_miss_tokens;
|
||||
let cost = conversation_usage_metadata.total_cost_cents;
|
||||
if cache_read > 0 || cache_write > 0 || cache_miss > 0 || cost > 0.0 {
|
||||
map.insert(
|
||||
"restored".to_string(),
|
||||
TokenUsage {
|
||||
model_id: "restored".to_string(),
|
||||
total_input: cache_miss,
|
||||
output: 0,
|
||||
input_cache_read: cache_read,
|
||||
input_cache_write: cache_write,
|
||||
cost_in_cents: cost,
|
||||
},
|
||||
);
|
||||
}
|
||||
map
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
is_viewing_shared_session: false,
|
||||
@@ -622,6 +668,12 @@ impl AIConversation {
|
||||
last_event_sequence,
|
||||
orchestration_configs: HashMap::new(),
|
||||
pinned,
|
||||
bedrock_message_history,
|
||||
tool_result_archive: Vec::new(),
|
||||
progressive_summary,
|
||||
messages_summarized_up_to,
|
||||
current_context_tokens: 0,
|
||||
has_pending_progressive_summary: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -629,6 +681,22 @@ impl AIConversation {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn current_context_tokens(&self) -> u32 {
|
||||
self.current_context_tokens
|
||||
}
|
||||
|
||||
pub fn set_current_context_tokens(&mut self, val: u32) {
|
||||
self.current_context_tokens = val;
|
||||
}
|
||||
|
||||
pub fn has_pending_progressive_summary(&self) -> bool {
|
||||
self.has_pending_progressive_summary
|
||||
}
|
||||
|
||||
pub fn set_has_pending_progressive_summary(&mut self, val: bool) {
|
||||
self.has_pending_progressive_summary = val;
|
||||
}
|
||||
|
||||
pub fn bedrock_message_history(&self) -> &[crate::ai::bedrock::convert::ConversationMessage] {
|
||||
&self.bedrock_message_history
|
||||
}
|
||||
@@ -765,6 +833,10 @@ impl AIConversation {
|
||||
self.conversation_usage_metadata.context_window_usage
|
||||
}
|
||||
|
||||
pub fn set_context_window_usage(&mut self, val: f32) {
|
||||
self.conversation_usage_metadata.context_window_usage = val;
|
||||
}
|
||||
|
||||
/// The per-segment breakdown of the context window (e.g. system prompt,
|
||||
/// tool definitions, conversation history). Scaled so the segments sum to
|
||||
/// `context_window_usage`. Empty when the server did not emit segments.
|
||||
@@ -963,7 +1035,7 @@ impl AIConversation {
|
||||
|
||||
// Sanity check: reject durations that are clearly wrong (> 24 hours
|
||||
// likely means start_time defaulted to epoch during session restore).
|
||||
if ms < 0 || ms > 86_400_000 {
|
||||
if !(0..=86_400_000).contains(&ms) {
|
||||
return None;
|
||||
}
|
||||
Some(ms)
|
||||
@@ -2447,7 +2519,7 @@ impl AIConversation {
|
||||
let is_hidden = self.is_exchange_hidden(exchange_id);
|
||||
ctx.emit(BlocklistAIHistoryEvent::UpdatedStreamingExchange {
|
||||
exchange_id,
|
||||
terminal_view_id,
|
||||
terminal_surface_id: terminal_view_id,
|
||||
conversation_id: self.id,
|
||||
is_hidden,
|
||||
});
|
||||
@@ -3278,7 +3350,7 @@ impl AIConversation {
|
||||
response_stream_id: Some(response_stream_id.clone()),
|
||||
exchange_id,
|
||||
task_id: task_id.clone(),
|
||||
terminal_view_id,
|
||||
terminal_surface_id,
|
||||
conversation_id: self.id,
|
||||
is_hidden,
|
||||
});
|
||||
@@ -3465,7 +3537,7 @@ impl AIConversation {
|
||||
&mut self,
|
||||
block_id: &BlockId,
|
||||
) -> TaskId {
|
||||
let new_task = Task::new_optimistic_cli_agent_subtask(block_id.clone());
|
||||
let new_task = Task::new_optimistic_cli_agent_subtask(block_id.clone(), None);
|
||||
let new_task_id = new_task.id().clone();
|
||||
self.optimistic_cli_subagent_subtask_id = Some(new_task_id.clone());
|
||||
self.task_store.insert(new_task);
|
||||
@@ -3670,6 +3742,8 @@ impl AIConversation {
|
||||
autoexecute_override: Some(self.autoexecute_override.into()),
|
||||
last_event_sequence: self.last_event_sequence,
|
||||
pinned: self.pinned,
|
||||
progressive_summary: self.progressive_summary.clone(),
|
||||
messages_summarized_up_to: self.messages_summarized_up_to,
|
||||
},
|
||||
};
|
||||
ctx.spawn(
|
||||
@@ -4784,7 +4858,7 @@ impl ConversationStatus {
|
||||
|
||||
pub fn status_icon_and_color(
|
||||
&self,
|
||||
theme: &WarpTheme,
|
||||
theme: &GalaxyTheme,
|
||||
color_style: StatusColorStyle,
|
||||
) -> (Icon, ColorU) {
|
||||
match self {
|
||||
|
||||
@@ -27,6 +27,8 @@ use ai::skills::ParsedSkill;
|
||||
use chrono::{DateTime, Local, TimeDelta};
|
||||
use comment::ReviewComment;
|
||||
use derivative::Derivative;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use markdown_parser::{parse_markdown, FormattedTable, FormattedText, FormattedTextInline};
|
||||
use parking_lot::RwLock;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -34,8 +36,6 @@ use session_sharing_protocol::common::ParticipantId;
|
||||
use task::TaskId;
|
||||
pub use telemetry::AIIdentifiers;
|
||||
use uuid::Uuid;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use warp_editor::render::model::LineCount;
|
||||
use warp_multi_agent_api::{diff_hunk as diff_hunk_api, AgentEvent, AgentType};
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ struct ServerTask {
|
||||
}
|
||||
|
||||
mod optimistic {
|
||||
use crate::terminal::model::block::BlockId;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) struct CLIAgentSubtask {
|
||||
@@ -211,7 +212,7 @@ impl Task {
|
||||
subagent_params: Some(SubagentParams {
|
||||
tool_call_id: String::new(),
|
||||
call: api::message::tool_call::Subagent {
|
||||
task_id: task_id,
|
||||
task_id,
|
||||
payload: String::new(),
|
||||
metadata: Some(Metadata::Cli(
|
||||
api::message::tool_call::subagent::CliSubagent {
|
||||
@@ -815,13 +816,7 @@ impl Task {
|
||||
"[bedrock] append_to_message_content: message_id={} not found, treating as implicit add",
|
||||
message.id
|
||||
);
|
||||
self.add_messages(
|
||||
vec![message],
|
||||
exchange_id,
|
||||
current_todo_list,
|
||||
current_comments,
|
||||
false,
|
||||
)?;
|
||||
self.add_messages(vec![message], exchange_id, message_context, false)?;
|
||||
return self
|
||||
.try_get_source()?
|
||||
.messages
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::ai::agent::{
|
||||
SubagentCall,
|
||||
};
|
||||
use crate::ai::llms::LLMId;
|
||||
use crate::terminal::model::block::BlockId;
|
||||
|
||||
fn create_test_exchange() -> AIAgentExchange {
|
||||
AIAgentExchange {
|
||||
@@ -40,7 +41,6 @@ fn create_test_task_with_exchanges(exchange_count: usize) -> Task {
|
||||
}
|
||||
|
||||
fn create_test_subtask_with_exchanges(exchange_count: usize) -> Task {
|
||||
use crate::terminal::model::block::BlockId;
|
||||
let mut task = Task::new_optimistic_cli_agent_subtask(BlockId::new(), None);
|
||||
for _ in 0..exchange_count {
|
||||
task.append_exchange(create_test_exchange());
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use pathfinder_color::ColorU;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
use galaxyui::elements::{
|
||||
@@ -12,6 +11,7 @@ use galaxyui::{
|
||||
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
|
||||
ViewContext,
|
||||
};
|
||||
use pathfinder_color::ColorU;
|
||||
|
||||
use crate::ai::agent::icons::{in_progress_icon, pending_icon, succeeded_icon};
|
||||
use crate::ai::agent::todos::AIAgentTodoList;
|
||||
|
||||
@@ -11,15 +11,15 @@ pub use entry::{
|
||||
AgentConversationProvenance,
|
||||
};
|
||||
use futures::stream::AbortHandle;
|
||||
use instant::Instant;
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use warp_cli::agent::Harness;
|
||||
use galaxy_core::execution_mode::AppExecutionMode;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::report_error;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxy_core::ui::theme::WarpTheme;
|
||||
use galaxy_core::ui::theme::GalaxyTheme;
|
||||
use instant::Instant;
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use warp_cli::agent::Harness;
|
||||
use warpui::color::ColorU;
|
||||
use warpui::r#async::Timer;
|
||||
use warpui::windowing::{StateEvent, WindowManager};
|
||||
@@ -1921,8 +1921,8 @@ impl AgentConversationsModel {
|
||||
});
|
||||
|
||||
// Sort each by updated_at (newest first), truncate
|
||||
personal.sort_by(|a, b| b.1.updated_at.cmp(&a.1.updated_at));
|
||||
team.sort_by(|a, b| b.1.updated_at.cmp(&a.1.updated_at));
|
||||
personal.sort_by_key(|b| std::cmp::Reverse(b.1.updated_at));
|
||||
team.sort_by_key(|b| std::cmp::Reverse(b.1.updated_at));
|
||||
personal.truncate(MAX_PERSONAL_TASKS);
|
||||
team.truncate(MAX_TEAM_TASKS);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use session_sharing_protocol::common::SessionId;
|
||||
use warp_cli::agent::Harness;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use warpui::{AppContext, SingletonEntity};
|
||||
|
||||
use super::{
|
||||
|
||||
@@ -3,13 +3,12 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxyui::{App, EntityId};
|
||||
use galaxyui::{App, EntityId, ModelHandle, SingletonEntity};
|
||||
use instant::Instant;
|
||||
use parking_lot::Mutex;
|
||||
use persistence::model::{AgentConversationData, ConversationUsageMetadata};
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxyui::{App, EntityId, ModelHandle, SingletonEntity};
|
||||
|
||||
use super::entry::{
|
||||
AgentConversationEntryId, AgentConversationNavigationSubject, AgentConversationProvenance,
|
||||
@@ -238,6 +237,7 @@ fn test_title_update_refreshes_shadowing_task_title() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -344,6 +344,7 @@ fn test_display_status_uses_matching_conversation_for_in_progress_task() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -400,6 +401,7 @@ fn test_display_status_uses_active_execution_over_previous_conversation_status()
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -463,6 +465,7 @@ fn test_display_status_updates_when_blocked_conversation_resumes() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -542,6 +545,7 @@ fn test_display_status_terminal_task_state_overrides_matching_conversation() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -597,6 +601,7 @@ fn test_status_filter_uses_display_status_for_task_backed_conversations() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -792,6 +797,7 @@ fn create_server_conversation_metadata(
|
||||
token_usage: vec![],
|
||||
tool_usage_metadata: Default::default(),
|
||||
context_window_segments: Vec::new(),
|
||||
..Default::default()
|
||||
},
|
||||
metadata: mock_server_metadata(),
|
||||
creator: None,
|
||||
@@ -928,6 +934,7 @@ fn test_get_entries_merges_task_and_local_conversation_by_run_id() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -983,6 +990,7 @@ fn test_get_entries_merges_task_and_local_conversation_by_server_token() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1191,6 +1199,7 @@ fn test_resolve_open_action_returns_none_for_active_unattachable_session() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1477,6 +1486,7 @@ fn test_server_token_assignment_updates_copy_link_resolution() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1639,6 +1649,7 @@ fn test_resolve_copy_link_uses_attached_synced_conversation_for_task_without_tok
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1966,6 +1977,7 @@ fn test_get_entries_prefers_task_when_task_id_matches_conversation_run_id() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2027,6 +2039,7 @@ fn test_get_entries_prefers_task_when_server_token_matches() {
|
||||
autoexecute_override: None,
|
||||
last_event_sequence: None,
|
||||
pinned: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use futures::future::Either;
|
||||
use futures::StreamExt;
|
||||
use galaxy_core::errors::AnyhowErrorExt as _;
|
||||
use galaxyui::r#async::Timer;
|
||||
use instant::Instant;
|
||||
use galaxy_core::errors::AnyhowErrorExt as _;
|
||||
|
||||
use crate::server::retry_strategies::is_transient_http_error;
|
||||
use crate::server::server_api::ai::AgentRunEvent;
|
||||
|
||||
@@ -5,11 +5,11 @@ use anyhow::{anyhow, Context, Result};
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use futures::future::Either;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use galaxyui::r#async::Timer;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use instant::Instant;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use reqwest::Error as ReqwestError;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use galaxyui::r#async::Timer;
|
||||
|
||||
use crate::ai::agent::ReceivedMessageInput;
|
||||
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use settings::Setting as _;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxyui::{App, EntityId, ModelHandle, SingletonEntity};
|
||||
use settings::Setting as _;
|
||||
|
||||
use super::AgentNotificationsModel;
|
||||
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
//! This modal is displayed when users click "New agent" to choose between
|
||||
//! cloud and local agent modes.
|
||||
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use galaxy_core::ui::color::blend::Blend;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxyui::elements::{
|
||||
@@ -17,6 +15,8 @@ use galaxyui::keymap::{FixedBinding, Keystroke};
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
|
||||
use crate::appearance::Appearance;
|
||||
use crate::ui_components::icons::Icon;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use galaxy_core::report_error;
|
||||
use galaxy_core::ui::theme::{AnsiColorIdentifier, AnsiColors};
|
||||
use serde::Serialize;
|
||||
use string_offset::CharCounter;
|
||||
use warp_completer::signatures::CommandRegistry;
|
||||
use warp_completer::util::parse_current_commands_and_tokens;
|
||||
use warp_completer::ParsedTokensSnapshot;
|
||||
use galaxy_core::report_error;
|
||||
use galaxy_core::ui::theme::{AnsiColorIdentifier, AnsiColors};
|
||||
use warpui::clipboard::ClipboardContent;
|
||||
use warpui::elements::new_scrollable::{ClippedAxisConfiguration, DualAxisConfig, NewScrollable};
|
||||
use warpui::elements::{
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pathfinder_color::ColorU;
|
||||
use galaxy_core::ui::appearance::Appearance as CoreAppearance;
|
||||
use galaxy_core::ui::icons::Icon;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxy_core::ui::theme::{Fill, WarpTheme};
|
||||
use galaxy_core::ui::theme::{Fill, GalaxyTheme, WarpTheme};
|
||||
use galaxyui::clipboard::ClipboardContent;
|
||||
use galaxyui::elements::{
|
||||
ChildView, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, DispatchEventResult,
|
||||
@@ -14,6 +13,7 @@ use galaxyui::elements::{
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{View, ViewContext, ViewHandle};
|
||||
use pathfinder_color::ColorU;
|
||||
|
||||
use crate::ai::agent::conversation::ConversationStatus;
|
||||
use crate::ai::agent_management::notifications::item::NotificationSourceAgent;
|
||||
|
||||
@@ -4,13 +4,6 @@ use std::sync::Arc;
|
||||
|
||||
use fuzzy_match::match_indices_case_insensitive;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxyui::scene::DropShadow;
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use lazy_static::lazy_static;
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use settings::Setting;
|
||||
use siphasher::sip::SipHasher;
|
||||
use galaxy_core::ui::icons::Icon;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
@@ -28,11 +21,18 @@ use galaxyui::elements::{
|
||||
use galaxyui::fonts::{Properties, Weight};
|
||||
use galaxyui::keymap::FixedBinding;
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::scene::DropShadow;
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{
|
||||
AppContext, Entity, FocusContext, ModelHandle, SingletonEntity, TypedActionView, View,
|
||||
ViewContext, ViewHandle, WeakViewHandle,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use settings::Setting;
|
||||
use siphasher::sip::SipHasher;
|
||||
|
||||
use crate::ai::agent::conversation::AIConversationId;
|
||||
use crate::ai::agent_conversations_model::{
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use galaxyui::{platform::TerminationMode, AppContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
use galaxyui::platform::TerminationMode;
|
||||
use galaxyui::{AppContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::auth::auth_manager::{AuthManager, AuthManagerEvent};
|
||||
use crate::auth::user::PrincipalType;
|
||||
|
||||
@@ -6,6 +6,8 @@ use std::time::Duration;
|
||||
use anyhow::{anyhow, Context as _};
|
||||
use comfy_table::Cell;
|
||||
use futures::{future, StreamExt};
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use serde::Serialize;
|
||||
use warp_cli::agent::{Harness, OutputFormat, Prompt, RunCloudArgs};
|
||||
use warp_cli::json_filter::JsonOutput;
|
||||
@@ -15,8 +17,6 @@ use warp_cli::task::{
|
||||
RunSourceArg, RunStateArg, TaskGetArgs,
|
||||
};
|
||||
use warp_cli::{GlobalOptions, SortOrderArg};
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use warpui::platform::TerminationMode;
|
||||
use warpui::r#async::{Spawnable, Timer};
|
||||
use warpui::{AppContext, ModelContext, SingletonEntity};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ fn create_conversation_metadata(
|
||||
token_usage: vec![],
|
||||
tool_usage_metadata: Default::default(),
|
||||
context_window_segments: Vec::new(),
|
||||
..Default::default()
|
||||
},
|
||||
metadata: create_mock_server_metadata(),
|
||||
creator: None,
|
||||
|
||||
@@ -15,6 +15,8 @@ use anyhow::{anyhow, Context as _};
|
||||
use futures::channel::oneshot;
|
||||
use futures::future::{self, join_all, Either};
|
||||
use futures::FutureExt as _;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::{report_error, report_if_error, safe_debug, safe_error, safe_info};
|
||||
use handlebars::get_arguments;
|
||||
use itertools::Itertools as _;
|
||||
use oneshot::{Canceled, Receiver};
|
||||
@@ -26,8 +28,6 @@ use warp_cli::agent::{Harness, OutputFormat};
|
||||
use warp_cli::mcp::MCPSpec;
|
||||
use warp_cli::share::ShareRequest;
|
||||
use warp_cli::skill::SkillSpec;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::{report_error, report_if_error, safe_debug, safe_error, safe_info};
|
||||
use warp_graphql::ai::AgentTaskState;
|
||||
use warp_managed_secrets::ManagedSecretValue;
|
||||
use warp_util::local_or_remote_path::LocalOrRemotePath;
|
||||
|
||||
@@ -9,13 +9,13 @@ use ai::index::full_source_code_embedding::manager::{
|
||||
};
|
||||
use futures::channel::oneshot;
|
||||
use futures::future::join_all;
|
||||
use repo_metadata::repositories::{DetectedRepositories, RepoDetectionSource};
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxy_completer::completer::CommandExitStatus;
|
||||
use galaxy_core::command::ExitCode;
|
||||
use galaxy_core::{safe_info, safe_warn};
|
||||
use galaxyui::r#async::FutureExt;
|
||||
use galaxyui::{ModelContext, ModelSpawner, SingletonEntity};
|
||||
use repo_metadata::repositories::{DetectedRepositories, RepoDetectionSource};
|
||||
|
||||
use super::terminal::TerminalDriver;
|
||||
use super::AgentDriverError;
|
||||
|
||||
@@ -7,13 +7,13 @@ use std::sync::Arc;
|
||||
use anyhow::{Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxy_managed_secrets::ManagedSecretValue;
|
||||
use galaxyui::{ModelHandle, ModelSpawner};
|
||||
use parking_lot::Mutex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Map, Value};
|
||||
use tempfile::NamedTempFile;
|
||||
use uuid::Uuid;
|
||||
use galaxy_managed_secrets::ManagedSecretValue;
|
||||
|
||||
use super::super::terminal::{CommandHandle, TerminalDriver};
|
||||
use super::super::{AgentDriver, AgentDriverError};
|
||||
|
||||
@@ -6,13 +6,13 @@ use std::sync::{Arc, OnceLock};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use parking_lot::Mutex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Map, Value};
|
||||
use tempfile::NamedTempFile;
|
||||
use uuid::Uuid;
|
||||
use warp_cli::agent::Harness;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use warp_managed_secrets::ManagedSecretValue;
|
||||
use warpui::{ModelHandle, ModelSpawner, SingletonEntity};
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ use std::sync::Arc;
|
||||
use anyhow::{Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxy_managed_secrets::ManagedSecretValue;
|
||||
use galaxyui::{ModelHandle, ModelSpawner, SingletonEntity};
|
||||
use tempfile::NamedTempFile;
|
||||
use galaxy_cli::{
|
||||
OZ_CLI_ENV, OZ_HARNESS_ENV, OZ_PARENT_RUN_ID_ENV, OZ_RUN_ID_ENV, SERVER_ROOT_URL_OVERRIDE_ENV,
|
||||
SESSION_SHARING_SERVER_URL_OVERRIDE_ENV, WS_SERVER_URL_OVERRIDE_ENV,
|
||||
};
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_managed_secrets::ManagedSecretValue;
|
||||
use galaxyui::{ModelHandle, ModelSpawner, SingletonEntity};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use super::terminal::{CommandHandle, TerminalDriver};
|
||||
use super::{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use warp_cli::agent::Harness;
|
||||
|
||||
use super::{auth_check_command_for, validate_cli_installed};
|
||||
use super::{auth_check_command_for, validate_cli_installed, ThirdPartyHarness};
|
||||
use crate::ai::agent_sdk::driver::AgentDriverError;
|
||||
|
||||
fn assert_harness_setup_failed(err: &AgentDriverError) -> (&str, &str) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use galaxy_core::telemetry::{EnablementState, TelemetryEvent, TelemetryEventDesc};
|
||||
use serde_json::{json, Value};
|
||||
use strum_macros::{EnumDiscriminants, EnumIter};
|
||||
use galaxy_core::telemetry::{EnablementState, TelemetryEvent, TelemetryEventDesc};
|
||||
|
||||
/// Telemetry events emitted by the third-party harness runtime layer.
|
||||
#[derive(Debug, EnumDiscriminants)]
|
||||
|
||||
@@ -564,17 +564,19 @@ pub mod text {
|
||||
|
||||
pub mod json {
|
||||
use std::borrow::Cow;
|
||||
use std::io::{self, Write};
|
||||
use std::ops::Range;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::ai::agent::comment::ReviewComment;
|
||||
use crate::ai::agent::{
|
||||
AIAgentActionType, AIAgentInput, AIAgentOutput, AIAgentOutputMessage,
|
||||
AIAgentOutputMessageType, AIAgentTodo, ArtifactCreatedData, CallMCPToolResult, FileContext,
|
||||
FileGlobResult, FileGlobV2Result, GrepResult, ReadFilesResult, ReadMCPResourceResult,
|
||||
RequestCommandOutputResult, RequestFileEditsResult, SearchCodebaseResult, SubagentCall,
|
||||
TodoOperation, UploadArtifactResult, WriteToLongRunningShellCommandResult,
|
||||
AIAgentActionResultType, AIAgentActionType, AIAgentInput, AIAgentOutput,
|
||||
AIAgentOutputMessage, AIAgentOutputMessageType, AIAgentTodo, ArtifactCreatedData,
|
||||
CallMCPToolResult, FileContext, FileGlobResult, FileGlobV2Result, GrepResult,
|
||||
ReadFilesResult, ReadMCPResourceResult, RequestCommandOutputResult, RequestFileEditsResult,
|
||||
SearchCodebaseResult, SubagentCall, TodoOperation, UploadArtifactResult,
|
||||
WriteToLongRunningShellCommandResult,
|
||||
};
|
||||
use crate::code::buffer_location::LocalOrRemotePath;
|
||||
|
||||
|
||||
@@ -34,12 +34,12 @@ use anyhow::{Context as _, Result};
|
||||
use command::r#async::Command;
|
||||
use command::Stdio;
|
||||
use futures::future::join_all;
|
||||
use tokio::fs::{self as tokio_fs, OpenOptions};
|
||||
use tokio::io::AsyncWriteExt as _;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
use galaxy_core::report_error;
|
||||
use galaxyui::r#async::executor::Background;
|
||||
use galaxyui::r#async::FutureExt as _;
|
||||
use tokio::fs::{self as tokio_fs, OpenOptions};
|
||||
use tokio::io::AsyncWriteExt as _;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
use crate::ai::agent_sdk::retry::with_bounded_retry;
|
||||
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
||||
@@ -825,7 +825,7 @@ pub(crate) async fn upload_snapshot_for_handoff(
|
||||
);
|
||||
}
|
||||
let mut target_map: HashMap<String, UploadTarget> = HashMap::new();
|
||||
for (file, target) in file_infos.iter().zip(response.uploads.into_iter()) {
|
||||
for (file, target) in file_infos.iter().zip(response.uploads) {
|
||||
target_map.insert(file.filename.clone(), target);
|
||||
}
|
||||
|
||||
@@ -1006,7 +1006,7 @@ async fn upload_gathered_snapshot(
|
||||
chunk.len(),
|
||||
);
|
||||
}
|
||||
for (file, target) in chunk.iter().zip(targets.into_iter()) {
|
||||
for (file, target) in chunk.iter().zip(targets) {
|
||||
target_map.insert(file.filename.clone(), target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
|
||||
use futures::channel::oneshot;
|
||||
use session_sharing_protocol::common::{Role, SessionId};
|
||||
use session_sharing_protocol::sharer::SessionRetentionReason;
|
||||
use galaxy_cli::share::{ShareAccessLevel, ShareRequest, ShareSubject};
|
||||
use galaxy_completer::completer::CommandOutput;
|
||||
use galaxy_core::command::ExitCode;
|
||||
@@ -18,6 +16,8 @@ use galaxy_terminal::model::grid::Dimensions;
|
||||
use galaxy_util::path::ShellFamily;
|
||||
use galaxyui::r#async::FutureExt;
|
||||
use galaxyui::{AppContext, Entity, ModelContext, ModelHandle, SingletonEntity as _, ViewHandle};
|
||||
use session_sharing_protocol::common::{Role, SessionId};
|
||||
use session_sharing_protocol::sharer::SessionRetentionReason;
|
||||
|
||||
use super::AgentDriverError;
|
||||
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
||||
|
||||
@@ -8,8 +8,6 @@ use std::time::Duration;
|
||||
use cloud_object_models::CodeForge;
|
||||
use futures::channel::oneshot;
|
||||
use futures::executor::block_on;
|
||||
use repo_metadata::{DirectoryWatcher, RepoMetadataEvent, RepoMetadataModel, RepositoryIdentifier};
|
||||
use tempfile::TempDir;
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxy_cli::mcp::MCPSpec;
|
||||
use galaxy_cli::skill::SkillSpec;
|
||||
@@ -25,6 +23,8 @@ use galaxy_graphql::response_context::ResponseContext;
|
||||
use galaxy_managed_secrets::ManagedSecretValue;
|
||||
use galaxy_util::standardized_path::StandardizedPath;
|
||||
use galaxyui::{App, SingletonEntity as _};
|
||||
use repo_metadata::{DirectoryWatcher, RepoMetadataEvent, RepoMetadataModel, RepositoryIdentifier};
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::{
|
||||
build_secret_env_vars, AgentDriver, AgentDriverError, IdleTimeoutSender,
|
||||
|
||||
@@ -2,9 +2,6 @@ use std::collections::HashSet;
|
||||
|
||||
use comfy_table::Cell;
|
||||
use cynic::QueryBuilder;
|
||||
use inquire::error::InquireError;
|
||||
use inquire::{Confirm, Select};
|
||||
use serde::Serialize;
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use galaxy_cli::environment::{EnvironmentCommand, ImageCommand};
|
||||
use galaxy_cli::scope::ObjectScope;
|
||||
@@ -16,6 +13,9 @@ use galaxy_graphql::queries::list_warp_dev_images::{
|
||||
use galaxy_graphql::queries::user_repo_auth_status::UserRepoAuthStatusEnum;
|
||||
use galaxyui::r#async::FutureExt;
|
||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||
use inquire::error::InquireError;
|
||||
use inquire::{Confirm, Select};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::ai::agent_sdk::driver::WARP_DRIVE_SYNC_TIMEOUT;
|
||||
use crate::ai::agent_sdk::oauth_flow::poll_oauth_until_terminal;
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
use std::process;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use galaxy_cli::federate::{FederateCommand, IssueGcpTokenArgs, IssueTokenArgs};
|
||||
use galaxy_cli::{agent::OutputFormat, GlobalOptions};
|
||||
use galaxy_core::{features::FeatureFlag, report_error};
|
||||
use galaxy_managed_secrets::ManagedSecretManager;
|
||||
use galaxyui::{platform::TerminationMode, AppContext, SingletonEntity as _};
|
||||
use serde_json::json;
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use galaxy_cli::federate::{FederateCommand, IssueGcpTokenArgs, IssueTokenArgs};
|
||||
use galaxy_cli::GlobalOptions;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::report_error;
|
||||
use galaxy_managed_secrets::ManagedSecretManager;
|
||||
use galaxyui::platform::TerminationMode;
|
||||
use galaxyui::{AppContext, SingletonEntity as _};
|
||||
use serde_json::json;
|
||||
|
||||
use super::common::set_ambient_task_context_from_run_id;
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use comfy_table::presets::UTF8_FULL;
|
||||
use comfy_table::{Cell, Table};
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use galaxy_graphql::queries::get_simple_integrations::{
|
||||
ListedSimpleIntegrationConfig, SimpleIntegration, SimpleIntegrationConnectionStatus,
|
||||
SimpleIntegrationsOutput,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||
use crate::util::time_format::format_approx_duration_from_now_utc;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use comfy_table::Cell;
|
||||
use galaxy_cli::{mcp::MCPCommand, GlobalOptions};
|
||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
use galaxy_cli::mcp::MCPCommand;
|
||||
use galaxy_cli::GlobalOptions;
|
||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||
use crate::ai::mcp::TemplatableMCPServerManager;
|
||||
|
||||
@@ -12,6 +12,7 @@ use anyhow::Context;
|
||||
pub(crate) use driver::harness::{task_env_vars, validate_cli_installed, ClaudeHarness};
|
||||
pub use driver::AgentDriver;
|
||||
use driver::AgentDriverError;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use telemetry::CliTelemetryEvent;
|
||||
use tracing::Instrument as _;
|
||||
use warp_cli::agent::{
|
||||
@@ -32,7 +33,6 @@ use warp_cli::secret::SecretCommand;
|
||||
use warp_cli::share::ShareRequest;
|
||||
use warp_cli::task::{MessageCommand, TaskCommand};
|
||||
use warp_cli::{CliCommand, GlobalOptions, OZ_HARNESS_ENV};
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use warp_graphql::object_permissions::OwnerType;
|
||||
use warp_isolation_platform::IsolationPlatformError;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use serde_json::json;
|
||||
use galaxy_cli::agent::Harness;
|
||||
use galaxy_cli::artifact::{
|
||||
ArtifactCommand, DownloadArtifactArgs, GetArtifactArgs, UploadArtifactArgs,
|
||||
@@ -6,6 +5,7 @@ use galaxy_cli::artifact::{
|
||||
use galaxy_cli::task::{MessageCommand, MessageSendArgs, MessageWatchArgs, TaskCommand};
|
||||
use galaxy_cli::CliCommand;
|
||||
use galaxy_core::telemetry::TelemetryEvent;
|
||||
use serde_json::json;
|
||||
|
||||
use super::{command_requires_auth, command_to_telemetry_event, reconcile_task_harness};
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ use anyhow::Context;
|
||||
use comfy_table::modifiers::UTF8_ROUND_CORNERS;
|
||||
use comfy_table::presets::UTF8_FULL;
|
||||
use comfy_table::{Cell, ContentArrangement, Table};
|
||||
use jaq_all::data::Runner;
|
||||
use jaq_all::fmts::write::Writer;
|
||||
use jaq_all::fmts::Format;
|
||||
// Use jaq_json directly to ensure serde support is included.
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use galaxy_cli::json_filter::{JqFilter, JsonOutput};
|
||||
use jaq_all::data::Runner;
|
||||
use jaq_all::fmts::write::Writer;
|
||||
use jaq_all::fmts::Format;
|
||||
use jaq_json::{write as jaq_write, Val};
|
||||
use serde::Serialize;
|
||||
use tabwriter::TabWriter;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use comfy_table::Cell;
|
||||
use galaxy_cli::{agent::AgentProfileCommand, GlobalOptions};
|
||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
use galaxy_cli::agent::AgentProfileCommand;
|
||||
use galaxy_cli::GlobalOptions;
|
||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||
use crate::ai::execution_profiles::profiles::AIExecutionProfilesModel;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
//! Provider command for linking third-party services.
|
||||
use comfy_table::Cell;
|
||||
use serde::Serialize;
|
||||
use galaxy_cli::provider::{ProviderCommand, ProviderType};
|
||||
use galaxy_cli::GlobalOptions;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxyui::platform::TerminationMode;
|
||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use comfy_table::Cell;
|
||||
use futures::future;
|
||||
use serde::Serialize;
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use galaxy_cli::schedule::{
|
||||
CreateScheduleArgs, DeleteScheduleArgs, GetScheduleArgs, PauseScheduleArgs, ScheduleCommand,
|
||||
@@ -11,6 +10,7 @@ use galaxy_cli::GlobalOptions;
|
||||
use galaxy_graphql::queries::get_scheduled_agent_history::ScheduledAgentHistory;
|
||||
use galaxyui::platform::TerminationMode;
|
||||
use galaxyui::{AppContext, SingletonEntity};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::common::{EnvironmentChoice, ResolveConfigurationError};
|
||||
use super::output::{self, TableFormat};
|
||||
|
||||
@@ -4,8 +4,6 @@ use std::io::{self, IsTerminal as _, Read};
|
||||
use anyhow::{Context, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
use comfy_table::Cell;
|
||||
use inquire::{Confirm, InquireError, Password};
|
||||
use serde::Serialize;
|
||||
use galaxy_cli::agent::OutputFormat;
|
||||
use galaxy_cli::scope::ObjectScope;
|
||||
use galaxy_cli::secret::{
|
||||
@@ -20,6 +18,8 @@ use galaxy_managed_secrets::client::SecretOwner;
|
||||
use galaxy_managed_secrets::{ManagedSecretManager, ManagedSecretValue};
|
||||
use galaxyui::platform::TerminationMode;
|
||||
use galaxyui::{AppContext, SingletonEntity as _};
|
||||
use inquire::{Confirm, InquireError, Password};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::output::{self, TableFormat};
|
||||
use crate::auth::UserUid;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use galaxy_core::telemetry::{EnablementState, TelemetryEvent, TelemetryEventDesc};
|
||||
use serde_json::{json, Value};
|
||||
use strum_macros::{EnumDiscriminants, EnumIter};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::time::Duration;
|
||||
|
||||
use ai::index::full_source_code_embedding::manager::CodebaseIndexManager;
|
||||
use markdown_parser::FormattedTextFragment;
|
||||
use rand::seq::SliceRandom;
|
||||
use warpui::keymap::Keystroke;
|
||||
use warpui::r#async::{SpawnedFutureHandle, Timer};
|
||||
use warpui::{AppContext, Entity, ModelContext, SingletonEntity};
|
||||
@@ -624,7 +625,6 @@ impl AITipModel<crate::terminal::view::ambient_agent::CloudModeTip> {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Select a random tip
|
||||
let mut rng = rand::thread_rng();
|
||||
self.current_tip = self.tips.choose(&mut rng).cloned();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use galaxy_core::ui::icons;
|
||||
use galaxy_core::ui::icons::ICON_DIMENSIONS;
|
||||
use galaxy_core::ui::theme::Fill as ThemeFill;
|
||||
@@ -20,6 +19,7 @@ use galaxyui::{
|
||||
id, AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
|
||||
ViewContext, ViewHandle,
|
||||
};
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
|
||||
use crate::ai::agent::conversation::AIConversationId;
|
||||
use crate::ai::blocklist::agent_view::AgentViewEntryOrigin;
|
||||
|
||||
@@ -6,9 +6,9 @@ pub use cloud_object_models::{
|
||||
};
|
||||
use futures::channel::oneshot;
|
||||
use futures::FutureExt;
|
||||
use serde_json::{Map, Value};
|
||||
use galaxy_graphql::queries::get_scheduled_agent_history::ScheduledAgentHistory;
|
||||
use galaxyui::{AppContext, Entity, ModelContext, ModelHandle, SingletonEntity};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::cloud_object::model::generic_string_model::StringModel;
|
||||
use crate::cloud_object::model::json_model::JsonModel;
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use chrono::Utc;
|
||||
use futures::StreamExt;
|
||||
use session_sharing_protocol::common::SessionId;
|
||||
|
||||
use super::{
|
||||
@@ -10,7 +11,9 @@ use super::{
|
||||
};
|
||||
use crate::ai::agent::UserQueryMode;
|
||||
use crate::ai::ambient_agents::{AmbientAgentTask, AmbientAgentTaskState};
|
||||
use crate::server::retry_strategies::MAX_ATTEMPTS;
|
||||
use crate::server::server_api::ai::{MockAIClient, SpawnAgentResponse, TaskStatusMessage};
|
||||
use crate::server::server_api::presigned_upload::HttpStatusError;
|
||||
use crate::terminal::shared_session;
|
||||
|
||||
fn task_with(
|
||||
@@ -127,7 +130,6 @@ async fn followup_submits_before_polling_and_ignores_previous_session_id() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_api_error_does_not_poll() {
|
||||
|
||||
let mut mock = MockAIClient::new();
|
||||
mock.expect_submit_run_followup()
|
||||
.times(1)
|
||||
@@ -154,7 +156,6 @@ async fn followup_api_error_does_not_poll() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_terminal_failure_surfaces_status_message() {
|
||||
|
||||
// Post-fix, a follow-up only surfaces a terminal-state failure after observing at least
|
||||
// one working state, so the new run's `Error` is interpreted as the follow-up's outcome
|
||||
// rather than residue of the prior run. The mock yields `InProgress` (no joinable
|
||||
@@ -227,7 +228,6 @@ async fn followup_terminal_failure_surfaces_status_message() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_without_previous_session_id_accepts_joinable_session() {
|
||||
|
||||
let session_id = SessionId::new();
|
||||
let expected_session_id = session_id;
|
||||
let mut mock = MockAIClient::new();
|
||||
@@ -285,7 +285,6 @@ async fn followup_without_previous_session_id_accepts_joinable_session() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_without_previous_session_id_errors_if_run_finishes_before_session() {
|
||||
|
||||
// Same shape as `followup_terminal_failure_surfaces_status_message`: the follow-up
|
||||
// must first observe a working state before a terminal `Succeeded` is interpreted as
|
||||
// the follow-up's outcome.
|
||||
@@ -356,7 +355,6 @@ async fn followup_without_previous_session_id_errors_if_run_finishes_before_sess
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_skips_prior_terminal_state_until_working_then_attaches() {
|
||||
|
||||
// Reproduces the race fix's happy path: the server hasn't yet transitioned the task off
|
||||
// its prior `Blocked` state on the first poll, but does so before the next. The poll
|
||||
// loop must silently skip the prior-terminal observation, then surface the new run's
|
||||
@@ -445,7 +443,6 @@ async fn followup_skips_prior_terminal_state_until_working_then_attaches() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_skips_prior_terminal_then_surfaces_real_failure() {
|
||||
|
||||
// Variant of the happy-path test where the new run legitimately fails after a working
|
||||
// state. The prior-terminal `Blocked` observation must still be suppressed, and the
|
||||
// new run's `Error` + `status_message` must surface as the follow-up's outcome.
|
||||
@@ -533,7 +530,6 @@ async fn followup_skips_prior_terminal_then_surfaces_real_failure() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_cancelled_state_breaks_skip_loop() {
|
||||
|
||||
// `Cancelled` is a carve-out: even before a working state has been observed it falls
|
||||
// through to terminal handling so a user-initiated cancellation can never leak an
|
||||
// infinite poll loop.
|
||||
@@ -581,7 +577,6 @@ async fn followup_cancelled_state_breaks_skip_loop() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn followup_bounded_skip_for_server_stall() {
|
||||
|
||||
// If the server is wedged on the prior terminal state, the bounded-skip counter must
|
||||
// eventually give up so the stream doesn't poll forever.
|
||||
let call_count = Arc::new(AtomicUsize::new(0));
|
||||
@@ -642,7 +637,6 @@ fn run_id() -> crate::ai::ambient_agents::AmbientAgentTaskId {
|
||||
}
|
||||
|
||||
fn transient_http_error() -> anyhow::Error {
|
||||
use crate::server::server_api::presigned_upload::HttpStatusError;
|
||||
anyhow::Error::new(HttpStatusError {
|
||||
status: 429,
|
||||
body: "Too Many Requests".to_string(),
|
||||
@@ -660,9 +654,6 @@ fn permanent_http_error() -> anyhow::Error {
|
||||
|
||||
#[tokio::test]
|
||||
async fn poll_retries_transient_429_errors() {
|
||||
|
||||
use crate::server::retry_strategies::MAX_ATTEMPTS;
|
||||
|
||||
let mut mock = MockAIClient::new();
|
||||
let call_count = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
@@ -739,7 +730,6 @@ async fn poll_retries_transient_429_errors() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn poll_fails_on_permanent_http_error() {
|
||||
|
||||
let mut mock = MockAIClient::new();
|
||||
|
||||
mock.expect_spawn_agent().returning(|_| {
|
||||
@@ -801,8 +791,6 @@ async fn poll_fails_on_permanent_http_error() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn poll_gives_up_after_max_transient_retries() {
|
||||
|
||||
|
||||
let mut mock = MockAIClient::new();
|
||||
let call_count = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
@@ -871,7 +859,6 @@ async fn poll_gives_up_after_max_transient_retries() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn poll_stops_on_terminal_failure_like_state() {
|
||||
|
||||
let mut mock = MockAIClient::new();
|
||||
|
||||
mock.expect_spawn_agent().returning(|_| {
|
||||
@@ -1001,7 +988,6 @@ fn session_join_info_ignores_empty_link_and_invalid_session_id() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn poll_for_session_join_info_waits_until_link_is_available() {
|
||||
|
||||
let mut mock = MockAIClient::new();
|
||||
|
||||
let call_count = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
@@ -5,14 +5,14 @@ use chrono::{DateTime, Duration as ChronoDuration, Utc};
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub use cloud_object_models::HarnessModelConfig;
|
||||
pub use cloud_object_models::{AgentConfigSnapshot, HarnessAuthSecretsConfig, HarnessConfig};
|
||||
use galaxy_core::report_error;
|
||||
use galaxy_core::ui::theme::{GalaxyTheme, WarpTheme};
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::{SingletonEntity, View, ViewContext};
|
||||
use iso8601_duration::Duration as Iso8601Duration;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use session_sharing_protocol::common::SessionId;
|
||||
use url::Url;
|
||||
use galaxy_core::report_error;
|
||||
use galaxy_core::ui::theme::WarpTheme;
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::{SingletonEntity, View, ViewContext};
|
||||
|
||||
use super::AmbientAgentTaskId;
|
||||
use crate::ai::artifacts::{deserialize_artifacts, Artifact};
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -7,11 +7,11 @@ use aws_credential_types::provider::error::CredentialsError;
|
||||
use aws_credential_types::provider::ProvideCredentials;
|
||||
use futures::channel::oneshot::channel;
|
||||
use futures::future::BoxFuture;
|
||||
use tokio::sync::Mutex;
|
||||
use vec1::vec1;
|
||||
use galaxy_managed_secrets::client::IdentityTokenOptions;
|
||||
use galaxy_managed_secrets::ManagedSecretManager;
|
||||
use galaxyui::{ModelContext, ModelHandle, SingletonEntity};
|
||||
use tokio::sync::Mutex;
|
||||
use vec1::vec1;
|
||||
|
||||
use crate::settings::{AISettings, AISettingsChangedEvent};
|
||||
use crate::terminal::event::{AfterBlockCompletedEvent, BlockType, UserBlockCompleted};
|
||||
@@ -137,7 +137,7 @@ pub async fn load_aws_credentials_from_sdk(
|
||||
let region_provider = aws_config::meta::region::RegionProviderChain::default_provider();
|
||||
let loader =
|
||||
aws_config::defaults(aws_config::BehaviorVersion::latest()).region(region_provider);
|
||||
let loader = if profile.trim().is_empty() {
|
||||
let loader = if profile.trim().is_empty() || profile.trim() == "default" {
|
||||
loader // Let AWS SDK use its default behavior
|
||||
} else {
|
||||
loader.profile_name(profile)
|
||||
|
||||
@@ -2,17 +2,17 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::Result;
|
||||
use aws_config::BehaviorVersion;
|
||||
use aws_credential_types::provider::ProvideCredentials;
|
||||
use aws_sdk_bedrockruntime::config::Region;
|
||||
use aws_sdk_bedrockruntime::Client as BedrockRuntimeClient;
|
||||
|
||||
use crate::settings::ai::BedrockAuthMethod;
|
||||
|
||||
use super::convert::{build_converse_request, CachingConfig, ConversationMessage, ToolDefinition};
|
||||
use super::diagnostic::BedrockDiagnosticLogger;
|
||||
use super::external_config::ExternalBedrockConfig;
|
||||
use super::models::apply_cross_region_prefix;
|
||||
use super::response_translator::bedrock_stream_to_response_events;
|
||||
use crate::ai::agent::api::ResponseStream;
|
||||
use crate::settings::ai::BedrockAuthMethod;
|
||||
|
||||
fn strip_context_marker(model_id: &str) -> String {
|
||||
if let Some(base) = model_id.strip_suffix("[1m]") {
|
||||
@@ -36,6 +36,7 @@ pub struct BedrockClientConfig {
|
||||
pub region: String,
|
||||
pub access_key_id: String,
|
||||
pub secret_access_key: String,
|
||||
pub session_token: Option<String>,
|
||||
pub cross_region_inference: bool,
|
||||
}
|
||||
|
||||
@@ -86,10 +87,23 @@ pub enum BedrockError {
|
||||
|
||||
impl BedrockClient {
|
||||
pub async fn from_config(config: BedrockClientConfig) -> Result<Self, BedrockError> {
|
||||
log::info!(
|
||||
"[bedrock] from_config input: auth_method={:?}, profile={:?}, region={:?}, access_key_id_set={}, secret_access_key_set={}, session_token_set={}",
|
||||
config.auth_method,
|
||||
config.profile,
|
||||
config.region,
|
||||
!config.access_key_id.is_empty(),
|
||||
!config.secret_access_key.is_empty(),
|
||||
config.session_token.is_some(),
|
||||
);
|
||||
|
||||
let aws_config = match config.auth_method {
|
||||
BedrockAuthMethod::Profile | BedrockAuthMethod::Sso => {
|
||||
let mut loader =
|
||||
aws_config::defaults(BehaviorVersion::latest()).profile_name(&config.profile);
|
||||
let mut loader = aws_config::defaults(BehaviorVersion::latest());
|
||||
|
||||
if !config.profile.is_empty() && config.profile != "default" {
|
||||
loader = loader.profile_name(&config.profile);
|
||||
}
|
||||
|
||||
if !config.region.is_empty() {
|
||||
loader = loader.region(Region::new(config.region.clone()));
|
||||
@@ -105,7 +119,7 @@ impl BedrockClient {
|
||||
let creds = aws_credential_types::Credentials::new(
|
||||
&config.access_key_id,
|
||||
&config.secret_access_key,
|
||||
None,
|
||||
config.session_token,
|
||||
None,
|
||||
"warp-bedrock-static",
|
||||
);
|
||||
@@ -123,6 +137,24 @@ impl BedrockClient {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(provider) = aws_config.credentials_provider() {
|
||||
match provider.provide_credentials().await {
|
||||
Ok(creds) => {
|
||||
log::info!(
|
||||
"[bedrock] Resolved AWS credentials successfully: access_key_id={:?}, has_session_token={}, expiry={:?}",
|
||||
creds.access_key_id(),
|
||||
creds.session_token().is_some(),
|
||||
creds.expiry(),
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("[bedrock] Failed to resolve AWS credentials from provider: {e:?}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("[bedrock] No credentials provider found in resolved AWS config");
|
||||
}
|
||||
|
||||
let region = aws_config
|
||||
.region()
|
||||
.map(|r| r.to_string())
|
||||
@@ -136,6 +168,7 @@ impl BedrockClient {
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn converse_stream(
|
||||
&self,
|
||||
model_id: &str,
|
||||
@@ -174,6 +207,13 @@ impl BedrockClient {
|
||||
tools.len()
|
||||
);
|
||||
|
||||
log::info!(
|
||||
"[bedrock] Sending request payload to Bedrock:\nSystem Prompt: {:?}\nMessages: {:#?}\nTools: {:#?}",
|
||||
system_prompt,
|
||||
messages,
|
||||
tools
|
||||
);
|
||||
|
||||
let converted = build_converse_request(
|
||||
messages.clone(),
|
||||
system_prompt.clone(),
|
||||
@@ -302,12 +342,10 @@ impl BedrockClient {
|
||||
})?;
|
||||
|
||||
let mut response_text = String::new();
|
||||
if let Some(output_msg) = output.output() {
|
||||
if let aws_sdk_bedrockruntime::types::ConverseOutput::Message(msg) = output_msg {
|
||||
for block in msg.content() {
|
||||
if let aws_sdk_bedrockruntime::types::ContentBlock::Text(text) = block {
|
||||
response_text.push_str(text);
|
||||
}
|
||||
if let Some(aws_sdk_bedrockruntime::types::ConverseOutput::Message(msg)) = output.output() {
|
||||
for block in msg.content() {
|
||||
if let aws_sdk_bedrockruntime::types::ContentBlock::Text(text) = block {
|
||||
response_text.push_str(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ use aws_smithy_types::Document;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use super::external_config::ExternalBedrockConfig;
|
||||
|
||||
// Re-export shared provider types so existing imports from bedrock::convert continue to work.
|
||||
pub use crate::ai::provider::types::{
|
||||
ContentPart, ConversationMessage, MessageContent, MessageRole, ToolDefinition,
|
||||
@@ -47,6 +46,7 @@ pub struct ConvertedRequest {
|
||||
pub tool_config: Option<ToolConfiguration>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn build_converse_request(
|
||||
messages: Vec<ConversationMessage>,
|
||||
system_prompt: Option<String>,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use aws_sdk_bedrockruntime::types::{ContentBlock, ConversationRole};
|
||||
use aws_sdk_bedrockruntime::types::{ContentBlock, ConversationRole, SystemContentBlock, Tool};
|
||||
use serde_json::json;
|
||||
|
||||
use super::convert::*;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use chrono::{Local, Utc};
|
||||
use serde_json::Value as JsonValue;
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{BufWriter, Read, Seek, SeekFrom, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Mutex;
|
||||
|
||||
use chrono::{Local, Utc};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use super::convert::{ConversationMessage, MessageContent, MessageRole, ToolDefinition};
|
||||
|
||||
const ENV_VAR: &str = "GALAXY_BEDROCK_DIAGNOSTICS";
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use futures::StreamExt;
|
||||
use serde_json::json;
|
||||
use std::path::PathBuf;
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
use super::client::{BedrockClient, BedrockClientConfig};
|
||||
use super::convert::{ConversationMessage, MessageContent, MessageRole, ToolDefinition};
|
||||
use crate::settings::ai::BedrockAuthMethod;
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
fn make_user_query_message(id: &str, task_id: &str, query: &str) -> api::Message {
|
||||
api::Message {
|
||||
@@ -24,6 +24,7 @@ fn make_user_query_message(id: &str, task_id: &str, query: &str) -> api::Message
|
||||
mode: None,
|
||||
intended_agent: 0,
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +55,7 @@ fn make_tool_call_run_shell(
|
||||
},
|
||||
)),
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +83,7 @@ fn make_tool_call_read_files(
|
||||
},
|
||||
)),
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,12 +116,14 @@ fn make_tool_result_shell(
|
||||
output: output.into(),
|
||||
exit_code,
|
||||
command_id: String::new(),
|
||||
..Default::default()
|
||||
},
|
||||
)),
|
||||
},
|
||||
)),
|
||||
},
|
||||
)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +160,7 @@ fn make_tool_result_read_files(
|
||||
)),
|
||||
},
|
||||
)),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +223,7 @@ fn make_settings(model: &str) -> api::request::Settings {
|
||||
supports_bundled_skills: false,
|
||||
supports_research_agent: false,
|
||||
supports_orchestration_v2: false,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +267,7 @@ fn get_test_config() -> Option<BedrockClientConfig> {
|
||||
region,
|
||||
access_key_id: String::new(),
|
||||
secret_access_key: String::new(),
|
||||
session_token: None,
|
||||
cross_region_inference: false,
|
||||
})
|
||||
}
|
||||
@@ -691,7 +699,7 @@ impl AgentSimulation {
|
||||
match name {
|
||||
"run_shell_command" => {
|
||||
let command = input["command"].as_str().unwrap_or("echo 'no command'");
|
||||
let output = std::process::Command::new("sh")
|
||||
let output = command::blocking::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(command)
|
||||
.current_dir(&self.project_path)
|
||||
@@ -759,7 +767,7 @@ impl AgentSimulation {
|
||||
.unwrap_or(self.project_path.to_str().unwrap_or("."));
|
||||
let mut result = String::new();
|
||||
for query in queries {
|
||||
let output = std::process::Command::new("grep")
|
||||
let output = command::blocking::Command::new("grep")
|
||||
.args(["-rn", query, path])
|
||||
.output();
|
||||
if let Ok(out) = output {
|
||||
@@ -999,7 +1007,7 @@ async fn test_agent_multi_turn_tool_use_produces_output() {
|
||||
let tool_use_id = format!("tool_{}", total_turns);
|
||||
let (result, is_error) = match tool.name.as_str() {
|
||||
"run_shell_command" => {
|
||||
let ls_output = std::process::Command::new("ls")
|
||||
let ls_output = command::blocking::Command::new("ls")
|
||||
.arg("-la")
|
||||
.current_dir(&project_path)
|
||||
.output()
|
||||
@@ -1075,7 +1083,7 @@ async fn test_agent_multi_turn_tool_use_produces_output() {
|
||||
// 2. No partial reasoning fragments leak to the UI
|
||||
// 3. The stream protocol is correct (Init, CreateTask, content, Finished)
|
||||
assert!(
|
||||
sim.all_text_output.len() > 0 || total_turns > 1,
|
||||
!sim.all_text_output.is_empty() || total_turns > 1,
|
||||
"Agent should either produce text or make multiple tool calls to explore"
|
||||
);
|
||||
|
||||
@@ -1160,39 +1168,34 @@ async fn test_reasoning_model_produces_substantial_output() {
|
||||
while let Some(event_result) = stream.next().await {
|
||||
event_count += 1;
|
||||
let event = event_result.expect("event should be Ok");
|
||||
if let Some(event_type) = &event.r#type {
|
||||
match event_type {
|
||||
api::response_event::Type::ClientActions(actions) => {
|
||||
for action in &actions.actions {
|
||||
if let Some(action_type) = &action.action {
|
||||
match action_type {
|
||||
api::client_action::Action::CreateTask(_) => {
|
||||
had_create_task = true;
|
||||
if let Some(api::response_event::Type::ClientActions(actions)) = &event.r#type {
|
||||
for action in &actions.actions {
|
||||
if let Some(action_type) = &action.action {
|
||||
match action_type {
|
||||
api::client_action::Action::CreateTask(_) => {
|
||||
had_create_task = true;
|
||||
}
|
||||
api::client_action::Action::AddMessagesToTask(add) => {
|
||||
for msg in &add.messages {
|
||||
if let Some(api::message::Message::AgentOutput(output)) =
|
||||
&msg.message
|
||||
{
|
||||
total_text.push_str(&output.text);
|
||||
}
|
||||
api::client_action::Action::AddMessagesToTask(add) => {
|
||||
for msg in &add.messages {
|
||||
if let Some(api::message::Message::AgentOutput(output)) =
|
||||
&msg.message
|
||||
{
|
||||
total_text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
api::client_action::Action::AppendToMessageContent(append) => {
|
||||
if let Some(msg) = &append.message {
|
||||
if let Some(api::message::Message::AgentOutput(output)) =
|
||||
&msg.message
|
||||
{
|
||||
total_text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
api::client_action::Action::AppendToMessageContent(append) => {
|
||||
if let Some(msg) = &append.message {
|
||||
if let Some(api::message::Message::AgentOutput(output)) =
|
||||
&msg.message
|
||||
{
|
||||
total_text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1610,7 +1613,7 @@ async fn test_slash_create_new_project() {
|
||||
|
||||
if !events.is_empty() {
|
||||
assert!(
|
||||
text.len() > 0
|
||||
!text.is_empty()
|
||||
|| events
|
||||
.iter()
|
||||
.any(|e| matches!(e.event_type, StreamEventType::ToolCallMessage { .. })),
|
||||
@@ -1645,7 +1648,7 @@ async fn test_slash_auto_code_diff() {
|
||||
assert_valid_stream(&events, "slash_auto_code_diff");
|
||||
|
||||
if !events.is_empty() {
|
||||
let has_action = text.len() > 0
|
||||
let has_action = !text.is_empty()
|
||||
|| events
|
||||
.iter()
|
||||
.any(|e| matches!(e.event_type, StreamEventType::ToolCallMessage { .. }));
|
||||
@@ -1775,7 +1778,7 @@ async fn test_slash_query_with_canned_response() {
|
||||
assert_valid_stream(&events, "slash_query_with_canned_response");
|
||||
|
||||
if !events.is_empty() {
|
||||
let has_output = text.len() > 0
|
||||
let has_output = !text.is_empty()
|
||||
|| events
|
||||
.iter()
|
||||
.any(|e| matches!(e.event_type, StreamEventType::ToolCallMessage { .. }));
|
||||
|
||||
@@ -144,7 +144,6 @@ fn parse_claude_code_model_map(
|
||||
model_id: arn,
|
||||
display_name,
|
||||
vision_supported: true,
|
||||
context_size: 200_000,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
||||
@@ -22,6 +22,7 @@ fn get_test_config() -> Option<BedrockClientConfig> {
|
||||
region,
|
||||
access_key_id: String::new(),
|
||||
secret_access_key: String::new(),
|
||||
session_token: None,
|
||||
cross_region_inference: false,
|
||||
})
|
||||
}
|
||||
@@ -81,6 +82,7 @@ async fn collect_stream_output(
|
||||
while let Some(event) = stream.next().await {
|
||||
let event = event.expect("stream event should be Ok");
|
||||
if let Some(event_type) = event.r#type {
|
||||
use warp_multi_agent_api::message::Message;
|
||||
use warp_multi_agent_api::response_event::Type;
|
||||
match event_type {
|
||||
Type::ClientActions(actions) => {
|
||||
@@ -90,24 +92,16 @@ async fn collect_stream_output(
|
||||
match action_type {
|
||||
Action::AddMessagesToTask(add) => {
|
||||
for msg in add.messages {
|
||||
if let Some(msg_content) = msg.message {
|
||||
use warp_multi_agent_api::message::Message;
|
||||
match msg_content {
|
||||
Message::AgentOutput(output) => {
|
||||
text.push_str(&output.text);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(Message::AgentOutput(output)) = msg.message {
|
||||
text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
Action::AppendToMessageContent(append) => {
|
||||
if let Some(msg) = append.message {
|
||||
if let Some(msg_content) = msg.message {
|
||||
if let Message::AgentOutput(output) = msg_content {
|
||||
text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
if let Some(Message::AgentOutput(output)) =
|
||||
append.message.and_then(|m| m.message)
|
||||
{
|
||||
text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -553,9 +547,10 @@ async fn test_arn_based_model() {
|
||||
return;
|
||||
};
|
||||
|
||||
let arn = std::env::var("BEDROCK_TEST_ARN").unwrap_or_else(|_| {
|
||||
"arn:aws:bedrock:us-east-1:156729649053:application-inference-profile/1tim45pgo320".into()
|
||||
});
|
||||
let Some(arn) = std::env::var("BEDROCK_TEST_ARN").ok() else {
|
||||
eprintln!("Skipping: BEDROCK_TEST_ARN not set");
|
||||
return;
|
||||
};
|
||||
|
||||
let client = BedrockClient::from_config(config)
|
||||
.await
|
||||
@@ -696,3 +691,100 @@ async fn test_all_tools_visible_to_model() {
|
||||
tools.len()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_bedrock_integration_live_stream() {
|
||||
let Some(config) = get_test_config() else {
|
||||
eprintln!("Skipping: BEDROCK_INTEGRATION_TEST not set");
|
||||
return;
|
||||
};
|
||||
|
||||
println!("[live-test] Initializing Bedrock client...");
|
||||
let client = BedrockClient::from_config(config)
|
||||
.await
|
||||
.expect("client creation");
|
||||
let model = get_test_model();
|
||||
println!("[live-test] Using model: {model}");
|
||||
|
||||
let messages = vec![ConversationMessage {
|
||||
role: MessageRole::User,
|
||||
content: MessageContent::Text(
|
||||
"Write a 2-line poem about antigravity. Output only the poem.".into(),
|
||||
),
|
||||
}];
|
||||
|
||||
println!("[live-test] Requesting stream response from Bedrock...");
|
||||
let stream = client
|
||||
.converse_stream(
|
||||
&model,
|
||||
"live-test-task-id",
|
||||
true,
|
||||
messages,
|
||||
None,
|
||||
None,
|
||||
vec![],
|
||||
1024,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
Arc::new(Mutex::new(Vec::new())),
|
||||
Vec::new(),
|
||||
)
|
||||
.await
|
||||
.expect("converse_stream should succeed");
|
||||
|
||||
let mut full_text = String::new();
|
||||
let mut stream = stream;
|
||||
|
||||
while let Some(event) = stream.next().await {
|
||||
let event = event.expect("stream event should be Ok");
|
||||
if let Some(event_type) = event.r#type {
|
||||
use warp_multi_agent_api::message::Message;
|
||||
use warp_multi_agent_api::response_event::Type;
|
||||
match event_type {
|
||||
Type::ClientActions(actions) => {
|
||||
for action in actions.actions {
|
||||
if let Some(action_type) = action.action {
|
||||
use warp_multi_agent_api::client_action::Action;
|
||||
match action_type {
|
||||
Action::AddMessagesToTask(add) => {
|
||||
for msg in add.messages {
|
||||
if let Some(Message::AgentOutput(output)) = msg.message {
|
||||
print!("{}", output.text);
|
||||
full_text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
Action::AppendToMessageContent(append) => {
|
||||
if let Some(Message::AgentOutput(output)) =
|
||||
append.message.and_then(|m| m.message)
|
||||
{
|
||||
print!("{}", output.text);
|
||||
full_text.push_str(&output.text);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::Finished(finished) => {
|
||||
println!(
|
||||
"\n[live-test] Stream finished. Reason: {:?}",
|
||||
finished.reason
|
||||
);
|
||||
if let Some(meta) = finished.conversation_usage_metadata {
|
||||
if let Some(usage) = meta.byok_token_usage.get("bedrock") {
|
||||
println!("[live-test] Token Usage - Total: {}", usage.total_tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("[live-test] Received full response:\n{}", full_text.trim());
|
||||
assert!(!full_text.is_empty(), "Model returned an empty response");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::settings::ai::BedrockModelConfig;
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::external_config::ExternalBedrockConfig;
|
||||
use crate::settings::ai::BedrockModelConfig;
|
||||
|
||||
pub struct DefaultModel {
|
||||
pub model_id: &'static str,
|
||||
@@ -128,7 +129,6 @@ pub fn get_effective_models(user_models: &[BedrockModelConfig]) -> Vec<BedrockMo
|
||||
model_id: m.model_id.to_string(),
|
||||
display_name: m.display_name.to_string(),
|
||||
vision_supported: m.vision_supported,
|
||||
context_size: m.context_size,
|
||||
})
|
||||
.collect();
|
||||
for default in defaults {
|
||||
@@ -145,7 +145,6 @@ pub fn get_effective_models(user_models: &[BedrockModelConfig]) -> Vec<BedrockMo
|
||||
model_id: m.model_id.to_string(),
|
||||
display_name: m.display_name.to_string(),
|
||||
vision_supported: m.vision_supported,
|
||||
context_size: m.context_size,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@ fn test_get_effective_models_custom_overrides() {
|
||||
model_id: "custom.model-v1:0".to_string(),
|
||||
display_name: "Custom Model".to_string(),
|
||||
vision_supported: false,
|
||||
context_size: 200_000,
|
||||
}];
|
||||
let models = get_effective_models(&custom);
|
||||
assert_eq!(models.len(), 1);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
use super::convert::{
|
||||
@@ -357,6 +361,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::ToolCallResult(
|
||||
api::message::ToolCallResult {
|
||||
tool_call_id: result.tool_call_id.clone(),
|
||||
@@ -382,6 +387,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::UserQuery(
|
||||
api::message::UserQuery {
|
||||
query: query.query.clone(),
|
||||
@@ -422,6 +428,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::UserQuery(
|
||||
api::message::UserQuery {
|
||||
query: query_text,
|
||||
@@ -445,6 +452,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
||||
query: query.query.clone(),
|
||||
..Default::default()
|
||||
@@ -462,6 +470,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::ToolCallResult(
|
||||
api::message::ToolCallResult {
|
||||
tool_call_id: result.tool_call_id.clone(),
|
||||
@@ -492,6 +501,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
||||
query: prompt,
|
||||
..Default::default()
|
||||
@@ -728,7 +738,6 @@ fn ensure_starts_with_user_message(messages: &mut Vec<ConversationMessage>) {
|
||||
/// 4. Removes trailing assistant tool_use messages that have no following user message.
|
||||
/// 5. Ensures strict user/assistant role alternation.
|
||||
fn ensure_tool_results_paired(messages: &mut Vec<ConversationMessage>) {
|
||||
|
||||
// Collect all tool_result IDs that exist anywhere in the conversation.
|
||||
let mut all_result_ids = HashSet::new();
|
||||
for msg in messages.iter() {
|
||||
@@ -1035,7 +1044,7 @@ pub fn extract_tools(request: &api::Request) -> Vec<ToolDefinition> {
|
||||
let input_schema = tool
|
||||
.input_schema
|
||||
.as_ref()
|
||||
.map(|s| prost_struct_to_json(s))
|
||||
.map(prost_struct_to_json)
|
||||
.unwrap_or_else(|| serde_json::json!({"type": "object", "properties": {}}));
|
||||
tools.push(ToolDefinition {
|
||||
name,
|
||||
@@ -1057,7 +1066,7 @@ pub fn extract_tools(request: &api::Request) -> Vec<ToolDefinition> {
|
||||
let input_schema = tool
|
||||
.input_schema
|
||||
.as_ref()
|
||||
.map(|s| prost_struct_to_json(s))
|
||||
.map(prost_struct_to_json)
|
||||
.unwrap_or_else(|| serde_json::json!({"type": "object", "properties": {}}));
|
||||
tools.push(ToolDefinition {
|
||||
name,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use aws_sdk_bedrockruntime::operation::converse_stream::ConverseStreamOutput;
|
||||
@@ -10,11 +12,10 @@ use uuid::Uuid;
|
||||
use warp_multi_agent_api::response_event::stream_finished;
|
||||
use warp_multi_agent_api::{self as api, ClientAction, ResponseEvent};
|
||||
|
||||
use crate::ai::agent::api::Event;
|
||||
use crate::server::server_api::AIApiError;
|
||||
|
||||
use super::convert::{ContentPart, ConversationMessage, MessageContent, MessageRole};
|
||||
use super::diagnostic::BedrockDiagnosticLogger;
|
||||
use crate::ai::agent::api::Event;
|
||||
use crate::server::server_api::AIApiError;
|
||||
|
||||
fn json_to_prost_struct(value: &serde_json::Value) -> prost_types::Struct {
|
||||
let fields = match value.as_object() {
|
||||
@@ -57,6 +58,7 @@ pub fn context_window_for_model(model_id: &str) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn bedrock_stream_to_response_events(
|
||||
mut output: ConverseStreamOutput,
|
||||
task_id: String,
|
||||
@@ -129,41 +131,36 @@ pub fn bedrock_stream_to_response_events(
|
||||
}
|
||||
StreamEvent::ContentBlockStart(block_start) => {
|
||||
log::debug!("[bedrock] Event #{event_count}: ContentBlockStart");
|
||||
if let Some(start) = block_start.start() {
|
||||
match start {
|
||||
ContentBlockStart::ToolUse(tool_start) => {
|
||||
_has_tool_calls = true;
|
||||
if !buffered_text.is_empty() {
|
||||
let msg_id = current_text_message_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| Uuid::new_v4().to_string());
|
||||
if !text_flushed {
|
||||
current_text_message_id = Some(msg_id.clone());
|
||||
text_flushed = true;
|
||||
log::debug!("[bedrock] Flushing buffered text ({} chars) before tool call", buffered_text.len());
|
||||
let add_msg = build_add_agent_output_message(
|
||||
&task_id,
|
||||
&msg_id,
|
||||
&buffered_text,
|
||||
);
|
||||
yield Ok(add_msg);
|
||||
} else {
|
||||
log::debug!("[bedrock] Flushing remaining buffered text ({} chars) as append before tool call", buffered_text.len());
|
||||
let append = build_append_text(
|
||||
&task_id,
|
||||
&msg_id,
|
||||
&buffered_text,
|
||||
);
|
||||
yield Ok(append);
|
||||
}
|
||||
buffered_text.clear();
|
||||
}
|
||||
current_tool_use_id = tool_start.tool_use_id().to_string();
|
||||
current_tool_name = tool_start.name().to_string();
|
||||
current_tool_input_json.clear();
|
||||
if let Some(ContentBlockStart::ToolUse(tool_start)) = block_start.start() {
|
||||
_has_tool_calls = true;
|
||||
if !buffered_text.is_empty() {
|
||||
let msg_id = current_text_message_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| Uuid::new_v4().to_string());
|
||||
if !text_flushed {
|
||||
current_text_message_id = Some(msg_id.clone());
|
||||
text_flushed = true;
|
||||
log::debug!("[bedrock] Flushing buffered text ({} chars) before tool call", buffered_text.len());
|
||||
let add_msg = build_add_agent_output_message(
|
||||
&task_id,
|
||||
&msg_id,
|
||||
&buffered_text,
|
||||
);
|
||||
yield Ok(add_msg);
|
||||
} else {
|
||||
log::debug!("[bedrock] Flushing remaining buffered text ({} chars) as append before tool call", buffered_text.len());
|
||||
let append = build_append_text(
|
||||
&task_id,
|
||||
&msg_id,
|
||||
&buffered_text,
|
||||
);
|
||||
yield Ok(append);
|
||||
}
|
||||
_ => {}
|
||||
buffered_text.clear();
|
||||
}
|
||||
current_tool_use_id = tool_start.tool_use_id().to_string();
|
||||
current_tool_name = tool_start.name().to_string();
|
||||
current_tool_input_json.clear();
|
||||
}
|
||||
}
|
||||
StreamEvent::ContentBlockDelta(delta) => {
|
||||
@@ -187,7 +184,7 @@ pub fn bedrock_stream_to_response_events(
|
||||
// AddMessagesToTask carries enough content for
|
||||
// the exchange to be fully registered before
|
||||
// subsequent AppendToMessageContent events arrive.
|
||||
if buffered_text.len() >= 1 {
|
||||
if !buffered_text.is_empty() {
|
||||
let msg_id = Uuid::new_v4().to_string();
|
||||
current_text_message_id = Some(msg_id.clone());
|
||||
text_flushed = true;
|
||||
@@ -201,10 +198,8 @@ pub fn bedrock_stream_to_response_events(
|
||||
}
|
||||
}
|
||||
}
|
||||
ContentBlockDelta::ReasoningContent(reasoning) => {
|
||||
if let ReasoningContentBlockDelta::Text(text) = reasoning {
|
||||
log::trace!("[bedrock] Reasoning delta ({} chars) - not displayed to user", text.len());
|
||||
}
|
||||
ContentBlockDelta::ReasoningContent(ReasoningContentBlockDelta::Text(text)) => {
|
||||
log::trace!("[bedrock] Reasoning delta ({} chars) - not displayed to user", text.len());
|
||||
}
|
||||
ContentBlockDelta::ToolUse(tool_delta) => {
|
||||
current_tool_input_json.push_str(tool_delta.input());
|
||||
@@ -593,6 +588,7 @@ fn build_user_query_message(task_id: &str, query_text: &str) -> ResponseEvent {
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
||||
query: query_text.to_string(),
|
||||
..Default::default()
|
||||
@@ -682,10 +678,14 @@ pub fn build_stream_finished(
|
||||
context_window_usage: context_usage,
|
||||
summarized: is_summarization,
|
||||
credits_spent: 0.0,
|
||||
platform_credits_spent: 0.0,
|
||||
total_input_tokens: input_tokens as u32,
|
||||
token_usage: vec![],
|
||||
tool_usage_metadata: None,
|
||||
warp_token_usage: std::collections::HashMap::new(),
|
||||
byok_token_usage,
|
||||
custom_endpoint_token_usage: std::collections::HashMap::new(),
|
||||
context_window_segments: vec![],
|
||||
});
|
||||
|
||||
ResponseEvent {
|
||||
@@ -757,6 +757,7 @@ fn build_add_agent_output_message(
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::AgentOutput(
|
||||
api::message::AgentOutput {
|
||||
text: initial_text.to_string(),
|
||||
@@ -790,6 +791,7 @@ fn build_append_text(task_id: &str, message_id: &str, text_delta: &str) -> Respo
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::AgentOutput(
|
||||
api::message::AgentOutput {
|
||||
text: text_delta.to_string(),
|
||||
@@ -1227,6 +1229,7 @@ pub fn build_tool_call_message(
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::ToolCall(api::message::ToolCall {
|
||||
tool_call_id: effective_tool_call_id,
|
||||
tool: Some(tool_variant),
|
||||
@@ -1243,6 +1246,7 @@ pub fn build_tool_call_message(
|
||||
timestamp: None,
|
||||
server_message_data: String::new(),
|
||||
citations: vec![],
|
||||
fetched_memories: vec![],
|
||||
message: Some(api::message::Message::AgentOutput(
|
||||
api::message::AgentOutput {
|
||||
text: format!(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use warp_multi_agent_api::{self as api, response_event::stream_finished};
|
||||
use warp_multi_agent_api::response_event::stream_finished;
|
||||
use warp_multi_agent_api::{self as api};
|
||||
|
||||
use super::response_translator::*;
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use galaxyui::elements::{
|
||||
Container, CornerRadius, CrossAxisAlignment, Flex, ParentElement, Radius, Text,
|
||||
};
|
||||
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
||||
|
||||
use crate::ai::bedrock::convert::CachingConfig;
|
||||
use crate::ai::bedrock::external_config::ExternalBedrockConfig;
|
||||
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 SettingsView {
|
||||
external_config: ExternalBedrockConfig,
|
||||
|
||||
@@ -9,16 +9,5 @@ pub fn multiply(a: i32, b: i32) -> i32 {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
assert_eq!(add(2, 3), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiply() {
|
||||
assert_eq!(multiply(3, 4), 12);
|
||||
}
|
||||
}
|
||||
#[path = "lib_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
assert_eq!(add(2, 3), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiply() {
|
||||
assert_eq!(multiply(3, 4), 12);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user