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:
Generated
+47
@@ -1613,6 +1613,7 @@ dependencies = [
|
|||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-sigv4",
|
"aws-sigv4",
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-eventstream",
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
"aws-smithy-runtime",
|
"aws-smithy-runtime",
|
||||||
"aws-smithy-runtime-api",
|
"aws-smithy-runtime-api",
|
||||||
@@ -1629,6 +1630,34 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-sdk-bedrockruntime"
|
||||||
|
version = "1.135.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e74b780f2f36912bae71b4f4f8ed9a0a88832b4681a1add3caf5ca25dbc8ab2d"
|
||||||
|
dependencies = [
|
||||||
|
"arc-swap",
|
||||||
|
"aws-credential-types",
|
||||||
|
"aws-runtime",
|
||||||
|
"aws-sigv4",
|
||||||
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-eventstream",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-json",
|
||||||
|
"aws-smithy-observability",
|
||||||
|
"aws-smithy-runtime",
|
||||||
|
"aws-smithy-runtime-api",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-types",
|
||||||
|
"bytes",
|
||||||
|
"fastrand 2.4.1",
|
||||||
|
"http 0.2.12",
|
||||||
|
"http 1.4.2",
|
||||||
|
"http-body-util",
|
||||||
|
"regex-lite",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-signin"
|
name = "aws-sdk-signin"
|
||||||
version = "1.14.0"
|
version = "1.14.0"
|
||||||
@@ -1737,6 +1766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "bae38512beae0ffee7010fc24e7a8a123c53efdfef42a61e80fda4882418dc71"
|
checksum = "bae38512beae0ffee7010fc24e7a8a123c53efdfef42a61e80fda4882418dc71"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
|
"aws-smithy-eventstream",
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
"aws-smithy-runtime-api",
|
"aws-smithy-runtime-api",
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
@@ -1763,12 +1793,24 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-smithy-eventstream"
|
||||||
|
version = "0.60.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78d8391e65fcea47c586a22e1a41f173b38615b112b2c6b7a44e80cec3e6b706"
|
||||||
|
dependencies = [
|
||||||
|
"aws-smithy-types",
|
||||||
|
"bytes",
|
||||||
|
"crc32fast",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-http"
|
name = "aws-smithy-http"
|
||||||
version = "0.63.6"
|
version = "0.63.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231"
|
checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aws-smithy-eventstream",
|
||||||
"aws-smithy-runtime-api",
|
"aws-smithy-runtime-api",
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -5635,7 +5677,9 @@ dependencies = [
|
|||||||
"async-trait",
|
"async-trait",
|
||||||
"aws-config",
|
"aws-config",
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
|
"aws-sdk-bedrockruntime",
|
||||||
"aws-sdk-sts",
|
"aws-sdk-sts",
|
||||||
|
"aws-smithy-types",
|
||||||
"aws-types",
|
"aws-types",
|
||||||
"axum",
|
"axum",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -5952,6 +5996,7 @@ dependencies = [
|
|||||||
"galaxy_core",
|
"galaxy_core",
|
||||||
"galaxy_js",
|
"galaxy_js",
|
||||||
"galaxy_util",
|
"galaxy_util",
|
||||||
|
"galaxyui",
|
||||||
"galaxyui_core",
|
"galaxyui_core",
|
||||||
"getset",
|
"getset",
|
||||||
"instant",
|
"instant",
|
||||||
@@ -9006,6 +9051,7 @@ dependencies = [
|
|||||||
"directories",
|
"directories",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"hf-hub",
|
"hf-hub",
|
||||||
|
"instant",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -9137,6 +9183,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"galaxy_core",
|
"galaxy_core",
|
||||||
"galaxy_util",
|
"galaxy_util",
|
||||||
|
"galaxyui",
|
||||||
"galaxyui_core",
|
"galaxyui_core",
|
||||||
"globset",
|
"globset",
|
||||||
"http_client",
|
"http_client",
|
||||||
|
|||||||
@@ -333,7 +333,9 @@ tracing-subscriber.workspace = true
|
|||||||
# AWS SDK (loading credentials for BYO LLM)
|
# AWS SDK (loading credentials for BYO LLM)
|
||||||
aws-config = { version = "1.8.16", features = ["credentials-login"] }
|
aws-config = { version = "1.8.16", features = ["credentials-login"] }
|
||||||
aws-credential-types = "1"
|
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-sdk-sts = { version = "1", default-features = false, features = ["default-https-client", "rt-tokio"] }
|
||||||
|
aws-smithy-types = "1"
|
||||||
aws-types = "1"
|
aws-types = "1"
|
||||||
|
|
||||||
notify-debouncer-full.workspace = true
|
notify-debouncer-full.workspace = true
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ pub use convert_from::{
|
|||||||
MaybeAIAgentOutputMessage, MessageToAIAgentOutputMessageError,
|
MaybeAIAgentOutputMessage, MessageToAIAgentOutputMessageError,
|
||||||
};
|
};
|
||||||
use futures_lite::Stream;
|
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::channel::ChannelState;
|
||||||
use galaxy_core::execution_mode::AppExecutionMode;
|
use galaxy_core::execution_mode::AppExecutionMode;
|
||||||
use galaxy_core::features::FeatureFlag;
|
use galaxy_core::features::FeatureFlag;
|
||||||
use galaxy_core::user_preferences::GetUserPreferences;
|
use galaxy_core::user_preferences::GetUserPreferences;
|
||||||
use galaxyui::{AppContext, EntityId, SingletonEntity as _};
|
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 super::{AIAgentInput, MCPContext, MCPServer, RequestMetadata, Suggestions};
|
||||||
use crate::ai::agent::conversation::AIConversationId;
|
use crate::ai::agent::conversation::AIConversationId;
|
||||||
@@ -211,6 +211,11 @@ impl RequestParams {
|
|||||||
supported_tools_override: None,
|
supported_tools_override: None,
|
||||||
parent_agent_id: None,
|
parent_agent_id: None,
|
||||||
agent_name: 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 geap_binding: Option<::ai::api_keys::GeapMintBinding> = None;
|
||||||
let api_keys = api_key_manager.api_keys_for_request(
|
let api_keys = api_key_manager.api_keys_for_request(
|
||||||
is_byo_enabled,
|
is_byo_enabled,
|
||||||
user_workspaces.is_aws_bedrock_credentials_enabled(app),
|
user_workspaces.is_bedrock_enabled(app),
|
||||||
geap_binding,
|
geap_binding,
|
||||||
);
|
);
|
||||||
let is_custom_inference_enabled = user_workspaces.is_custom_inference_enabled(app);
|
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 ai::skills::{ParsedSkill, SkillPathOrigin};
|
||||||
use chrono::{DateTime, Local, TimeZone};
|
use chrono::{DateTime, Local, TimeZone};
|
||||||
use persistence::model::AgentConversationData;
|
|
||||||
use galaxy_core::command::ExitCode;
|
use galaxy_core::command::ExitCode;
|
||||||
|
use persistence::model::AgentConversationData;
|
||||||
use warp_multi_agent_api as api;
|
use warp_multi_agent_api as api;
|
||||||
use warp_multi_agent_api::ask_user_question_result::answer_item::Answer as AskUserQuestionAnswer;
|
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,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
progressive_summary: None,
|
||||||
|
messages_summarized_up_to: 0,
|
||||||
},
|
},
|
||||||
RestorationMode::Continue => AgentConversationData {
|
RestorationMode::Continue => AgentConversationData {
|
||||||
server_conversation_token: Some(
|
server_conversation_token: Some(
|
||||||
@@ -110,6 +112,8 @@ pub fn convert_conversation_data_to_ai_conversation(
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
progressive_summary: None,
|
||||||
|
messages_summarized_up_to: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ fn test_server_metadata(
|
|||||||
token_usage: vec![],
|
token_usage: vec![],
|
||||||
tool_usage_metadata: Default::default(),
|
tool_usage_metadata: Default::default(),
|
||||||
context_window_segments: Vec::new(),
|
context_window_segments: Vec::new(),
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
metadata: ServerMetadata {
|
metadata: ServerMetadata {
|
||||||
uid: ServerId::default(),
|
uid: ServerId::default(),
|
||||||
|
|||||||
@@ -8,11 +8,15 @@ use warp_multi_agent_api as api;
|
|||||||
use super::convert_to::convert_input;
|
use super::convert_to::convert_input;
|
||||||
use super::{ConvertToAPITypeError, RequestParams, ResponseStream};
|
use super::{ConvertToAPITypeError, RequestParams, ResponseStream};
|
||||||
use crate::ai::agent::redaction;
|
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;
|
use crate::terminal::model::session::SessionType;
|
||||||
|
|
||||||
pub async fn generate_multi_agent_output(
|
pub async fn generate_multi_agent_output(
|
||||||
provider_config: ProviderConfig,
|
provider_config: ProviderConfig,
|
||||||
|
server_api: Arc<dyn AIClient>,
|
||||||
mut params: RequestParams,
|
mut params: RequestParams,
|
||||||
cancellation_rx: futures::channel::oneshot::Receiver<()>,
|
cancellation_rx: futures::channel::oneshot::Receiver<()>,
|
||||||
) -> Result<ResponseStream, ConvertToAPITypeError> {
|
) -> Result<ResponseStream, ConvertToAPITypeError> {
|
||||||
@@ -65,9 +69,9 @@ pub async fn generate_multi_agent_output(
|
|||||||
input: Some(convert_input(params.input)?),
|
input: Some(convert_input(params.input)?),
|
||||||
settings: Some(api::request::Settings {
|
settings: Some(api::request::Settings {
|
||||||
model_config: Some(api::request::settings::ModelConfig {
|
model_config: Some(api::request::settings::ModelConfig {
|
||||||
base: params.model.into(),
|
base: params.model.clone().into(),
|
||||||
cli_agent: params.cli_agent_model.into(),
|
cli_agent: params.cli_agent_model.clone().into(),
|
||||||
computer_use_agent: params.computer_use_model.into(),
|
computer_use_agent: params.computer_use_model.clone().into(),
|
||||||
base_model_context_window_limit: params.context_window_limit.unwrap_or(0),
|
base_model_context_window_limit: params.context_window_limit.unwrap_or(0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@@ -136,24 +140,11 @@ pub async fn generate_multi_agent_output(
|
|||||||
mcp_context: params.mcp_context.map(Into::into),
|
mcp_context: params.mcp_context.map(Into::into),
|
||||||
};
|
};
|
||||||
|
|
||||||
let response_stream =
|
match provider_config {
|
||||||
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))
|
|
||||||
}
|
|
||||||
ProviderConfig::OpenAI(config) => {
|
ProviderConfig::OpenAI(config) => {
|
||||||
let translator_request = openai_translator::TranslatorRequest {
|
let translator_request = openai_translator::TranslatorRequest {
|
||||||
config,
|
config,
|
||||||
model_id,
|
model_id: params.model.as_str().to_string(),
|
||||||
root_task_id: params.root_task_id.clone(),
|
root_task_id: params.root_task_id.clone(),
|
||||||
message_history: params.bedrock_message_history.clone(),
|
message_history: params.bedrock_message_history.clone(),
|
||||||
tool_result_archive: params.bedrock_tool_result_archive.clone(),
|
tool_result_archive: params.bedrock_tool_result_archive.clone(),
|
||||||
@@ -178,14 +169,53 @@ pub async fn generate_multi_agent_output(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ProviderConfig::None => {
|
ProviderConfig::Bedrock(config) => {
|
||||||
log::error!("No AI provider configured. Cannot process request.");
|
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 {
|
let err = Arc::new(crate::server::server_api::AIApiError::Stream {
|
||||||
stream_type: "provider_dispatch",
|
stream_type: "bedrock",
|
||||||
source: anyhow::anyhow!(
|
source: anyhow::anyhow!("{e}"),
|
||||||
"No AI backend available. Please configure a provider in Settings > AI."
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
let (tx, rx) = async_channel::unbounded();
|
||||||
|
let _ = tx.send(Err(err)).await;
|
||||||
|
Ok(Box::pin(rx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProviderConfig::None => {
|
||||||
|
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, rx) = async_channel::unbounded();
|
||||||
let _ = tx
|
let _ = tx
|
||||||
.send(Err(convert_multi_agent_client_error(e).await))
|
.send(Err(convert_multi_agent_client_error(e).await))
|
||||||
@@ -194,6 +224,8 @@ pub async fn generate_multi_agent_output(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn convert_multi_agent_client_error(
|
async fn convert_multi_agent_client_error(
|
||||||
error: warp_multi_agent_client::Error,
|
error: warp_multi_agent_client::Error,
|
||||||
|
|||||||
@@ -5,10 +5,6 @@ use ai::agent::orchestration_config::{OrchestrationConfig, OrchestrationConfigSt
|
|||||||
use ai::document::AIDocumentId;
|
use ai::document::AIDocumentId;
|
||||||
use ai::skills::SkillPathOrigin;
|
use ai::skills::SkillPathOrigin;
|
||||||
use chrono::{DateTime, Local, TimeZone};
|
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_cli::agent::Harness;
|
||||||
use galaxy_core::command::ExitCode;
|
use galaxy_core::command::ExitCode;
|
||||||
use galaxy_core::execution_mode::AppExecutionMode;
|
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::send_telemetry_from_ctx;
|
||||||
use galaxy_core::ui::appearance::Appearance;
|
use galaxy_core::ui::appearance::Appearance;
|
||||||
use galaxy_core::ui::theme::color::internal_colors;
|
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;
|
||||||
use warp_multi_agent_api::response_event::stream_finished::TokenUsage;
|
use warp_multi_agent_api::response_event::stream_finished::TokenUsage;
|
||||||
use warp_multi_agent_api::{self as api};
|
use warp_multi_agent_api::{self as api};
|
||||||
use galaxyui::color::ColorU;
|
|
||||||
use galaxyui::{AppContext, EntityId, ModelContext, SingletonEntity};
|
|
||||||
|
|
||||||
use super::api::ServerConversationToken;
|
use super::api::ServerConversationToken;
|
||||||
use super::task::helper::*;
|
use super::task::helper::*;
|
||||||
@@ -327,6 +327,12 @@ pub struct AIConversation {
|
|||||||
/// Whether the user has pinned this child agent in the orchestration
|
/// Whether the user has pinned this child agent in the orchestration
|
||||||
/// pill bar. Persisted via `AgentConversationData.pinned`.
|
/// pill bar. Persisted via `AgentConversationData.pinned`.
|
||||||
pinned: bool,
|
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(
|
pub(crate) fn artifact_from_fork_proto(
|
||||||
@@ -382,6 +388,12 @@ impl AIConversation {
|
|||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
orchestration_configs: HashMap::new(),
|
orchestration_configs: HashMap::new(),
|
||||||
pinned: false,
|
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>,
|
tasks: Vec<api::Task>,
|
||||||
conversation_data: Option<AgentConversationData>,
|
conversation_data: Option<AgentConversationData>,
|
||||||
) -> Result<Self, RestoreConversationError> {
|
) -> 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() {
|
let (task_store, todo_lists, status) = if tasks.is_empty() {
|
||||||
// Bypass `derive_status_from_root_task`: it would return `Success`
|
// Bypass `derive_status_from_root_task`: it would return `Success`
|
||||||
// for a root with no exchanges, silently misclassifying a restored
|
// for a root with no exchanges, silently misclassifying a restored
|
||||||
@@ -518,6 +536,8 @@ impl AIConversation {
|
|||||||
autoexecute_override,
|
autoexecute_override,
|
||||||
last_event_sequence,
|
last_event_sequence,
|
||||||
pinned,
|
pinned,
|
||||||
|
progressive_summary,
|
||||||
|
messages_summarized_up_to,
|
||||||
) = if let Some(data) = conversation_data {
|
) = if let Some(data) = conversation_data {
|
||||||
let server_conversation_token = data
|
let server_conversation_token = data
|
||||||
.server_conversation_token
|
.server_conversation_token
|
||||||
@@ -565,6 +585,8 @@ impl AIConversation {
|
|||||||
autoexecute_override,
|
autoexecute_override,
|
||||||
data.last_event_sequence,
|
data.last_event_sequence,
|
||||||
data.pinned,
|
data.pinned,
|
||||||
|
data.progressive_summary.clone(),
|
||||||
|
data.messages_summarized_up_to,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
@@ -582,9 +604,33 @@ impl AIConversation {
|
|||||||
AIConversationAutoexecuteMode::default(),
|
AIConversationAutoexecuteMode::default(),
|
||||||
None,
|
None,
|
||||||
false,
|
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 {
|
Ok(Self {
|
||||||
id,
|
id,
|
||||||
is_viewing_shared_session: false,
|
is_viewing_shared_session: false,
|
||||||
@@ -622,6 +668,12 @@ impl AIConversation {
|
|||||||
last_event_sequence,
|
last_event_sequence,
|
||||||
orchestration_configs: HashMap::new(),
|
orchestration_configs: HashMap::new(),
|
||||||
pinned,
|
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
|
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] {
|
pub fn bedrock_message_history(&self) -> &[crate::ai::bedrock::convert::ConversationMessage] {
|
||||||
&self.bedrock_message_history
|
&self.bedrock_message_history
|
||||||
}
|
}
|
||||||
@@ -765,6 +833,10 @@ impl AIConversation {
|
|||||||
self.conversation_usage_metadata.context_window_usage
|
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,
|
/// The per-segment breakdown of the context window (e.g. system prompt,
|
||||||
/// tool definitions, conversation history). Scaled so the segments sum to
|
/// tool definitions, conversation history). Scaled so the segments sum to
|
||||||
/// `context_window_usage`. Empty when the server did not emit segments.
|
/// `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
|
// Sanity check: reject durations that are clearly wrong (> 24 hours
|
||||||
// likely means start_time defaulted to epoch during session restore).
|
// 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;
|
return None;
|
||||||
}
|
}
|
||||||
Some(ms)
|
Some(ms)
|
||||||
@@ -2447,7 +2519,7 @@ impl AIConversation {
|
|||||||
let is_hidden = self.is_exchange_hidden(exchange_id);
|
let is_hidden = self.is_exchange_hidden(exchange_id);
|
||||||
ctx.emit(BlocklistAIHistoryEvent::UpdatedStreamingExchange {
|
ctx.emit(BlocklistAIHistoryEvent::UpdatedStreamingExchange {
|
||||||
exchange_id,
|
exchange_id,
|
||||||
terminal_view_id,
|
terminal_surface_id: terminal_view_id,
|
||||||
conversation_id: self.id,
|
conversation_id: self.id,
|
||||||
is_hidden,
|
is_hidden,
|
||||||
});
|
});
|
||||||
@@ -3278,7 +3350,7 @@ impl AIConversation {
|
|||||||
response_stream_id: Some(response_stream_id.clone()),
|
response_stream_id: Some(response_stream_id.clone()),
|
||||||
exchange_id,
|
exchange_id,
|
||||||
task_id: task_id.clone(),
|
task_id: task_id.clone(),
|
||||||
terminal_view_id,
|
terminal_surface_id,
|
||||||
conversation_id: self.id,
|
conversation_id: self.id,
|
||||||
is_hidden,
|
is_hidden,
|
||||||
});
|
});
|
||||||
@@ -3465,7 +3537,7 @@ impl AIConversation {
|
|||||||
&mut self,
|
&mut self,
|
||||||
block_id: &BlockId,
|
block_id: &BlockId,
|
||||||
) -> TaskId {
|
) -> 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();
|
let new_task_id = new_task.id().clone();
|
||||||
self.optimistic_cli_subagent_subtask_id = Some(new_task_id.clone());
|
self.optimistic_cli_subagent_subtask_id = Some(new_task_id.clone());
|
||||||
self.task_store.insert(new_task);
|
self.task_store.insert(new_task);
|
||||||
@@ -3670,6 +3742,8 @@ impl AIConversation {
|
|||||||
autoexecute_override: Some(self.autoexecute_override.into()),
|
autoexecute_override: Some(self.autoexecute_override.into()),
|
||||||
last_event_sequence: self.last_event_sequence,
|
last_event_sequence: self.last_event_sequence,
|
||||||
pinned: self.pinned,
|
pinned: self.pinned,
|
||||||
|
progressive_summary: self.progressive_summary.clone(),
|
||||||
|
messages_summarized_up_to: self.messages_summarized_up_to,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ctx.spawn(
|
ctx.spawn(
|
||||||
@@ -4784,7 +4858,7 @@ impl ConversationStatus {
|
|||||||
|
|
||||||
pub fn status_icon_and_color(
|
pub fn status_icon_and_color(
|
||||||
&self,
|
&self,
|
||||||
theme: &WarpTheme,
|
theme: &GalaxyTheme,
|
||||||
color_style: StatusColorStyle,
|
color_style: StatusColorStyle,
|
||||||
) -> (Icon, ColorU) {
|
) -> (Icon, ColorU) {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ use ai::skills::ParsedSkill;
|
|||||||
use chrono::{DateTime, Local, TimeDelta};
|
use chrono::{DateTime, Local, TimeDelta};
|
||||||
use comment::ReviewComment;
|
use comment::ReviewComment;
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
|
use galaxy_core::channel::ChannelState;
|
||||||
|
use galaxy_core::features::FeatureFlag;
|
||||||
use markdown_parser::{parse_markdown, FormattedTable, FormattedText, FormattedTextInline};
|
use markdown_parser::{parse_markdown, FormattedTable, FormattedText, FormattedTextInline};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -34,8 +36,6 @@ use session_sharing_protocol::common::ParticipantId;
|
|||||||
use task::TaskId;
|
use task::TaskId;
|
||||||
pub use telemetry::AIIdentifiers;
|
pub use telemetry::AIIdentifiers;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use galaxy_core::channel::ChannelState;
|
|
||||||
use galaxy_core::features::FeatureFlag;
|
|
||||||
use warp_editor::render::model::LineCount;
|
use warp_editor::render::model::LineCount;
|
||||||
use warp_multi_agent_api::{diff_hunk as diff_hunk_api, AgentEvent, AgentType};
|
use warp_multi_agent_api::{diff_hunk as diff_hunk_api, AgentEvent, AgentType};
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ struct ServerTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod optimistic {
|
mod optimistic {
|
||||||
|
use crate::terminal::model::block::BlockId;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct CLIAgentSubtask {
|
pub(super) struct CLIAgentSubtask {
|
||||||
@@ -211,7 +212,7 @@ impl Task {
|
|||||||
subagent_params: Some(SubagentParams {
|
subagent_params: Some(SubagentParams {
|
||||||
tool_call_id: String::new(),
|
tool_call_id: String::new(),
|
||||||
call: api::message::tool_call::Subagent {
|
call: api::message::tool_call::Subagent {
|
||||||
task_id: task_id,
|
task_id,
|
||||||
payload: String::new(),
|
payload: String::new(),
|
||||||
metadata: Some(Metadata::Cli(
|
metadata: Some(Metadata::Cli(
|
||||||
api::message::tool_call::subagent::CliSubagent {
|
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",
|
"[bedrock] append_to_message_content: message_id={} not found, treating as implicit add",
|
||||||
message.id
|
message.id
|
||||||
);
|
);
|
||||||
self.add_messages(
|
self.add_messages(vec![message], exchange_id, message_context, false)?;
|
||||||
vec![message],
|
|
||||||
exchange_id,
|
|
||||||
current_todo_list,
|
|
||||||
current_comments,
|
|
||||||
false,
|
|
||||||
)?;
|
|
||||||
return self
|
return self
|
||||||
.try_get_source()?
|
.try_get_source()?
|
||||||
.messages
|
.messages
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use crate::ai::agent::{
|
|||||||
SubagentCall,
|
SubagentCall,
|
||||||
};
|
};
|
||||||
use crate::ai::llms::LLMId;
|
use crate::ai::llms::LLMId;
|
||||||
|
use crate::terminal::model::block::BlockId;
|
||||||
|
|
||||||
fn create_test_exchange() -> AIAgentExchange {
|
fn create_test_exchange() -> AIAgentExchange {
|
||||||
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 {
|
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);
|
let mut task = Task::new_optimistic_cli_agent_subtask(BlockId::new(), None);
|
||||||
for _ in 0..exchange_count {
|
for _ in 0..exchange_count {
|
||||||
task.append_exchange(create_test_exchange());
|
task.append_exchange(create_test_exchange());
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use pathfinder_color::ColorU;
|
|
||||||
use galaxy_core::ui::appearance::Appearance;
|
use galaxy_core::ui::appearance::Appearance;
|
||||||
use galaxy_core::ui::theme::Fill;
|
use galaxy_core::ui::theme::Fill;
|
||||||
use galaxyui::elements::{
|
use galaxyui::elements::{
|
||||||
@@ -12,6 +11,7 @@ use galaxyui::{
|
|||||||
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
|
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
|
||||||
ViewContext,
|
ViewContext,
|
||||||
};
|
};
|
||||||
|
use pathfinder_color::ColorU;
|
||||||
|
|
||||||
use crate::ai::agent::icons::{in_progress_icon, pending_icon, succeeded_icon};
|
use crate::ai::agent::icons::{in_progress_icon, pending_icon, succeeded_icon};
|
||||||
use crate::ai::agent::todos::AIAgentTodoList;
|
use crate::ai::agent::todos::AIAgentTodoList;
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ pub use entry::{
|
|||||||
AgentConversationProvenance,
|
AgentConversationProvenance,
|
||||||
};
|
};
|
||||||
use futures::stream::AbortHandle;
|
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::execution_mode::AppExecutionMode;
|
||||||
use galaxy_core::features::FeatureFlag;
|
use galaxy_core::features::FeatureFlag;
|
||||||
use galaxy_core::report_error;
|
use galaxy_core::report_error;
|
||||||
use galaxy_core::ui::theme::color::internal_colors;
|
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::color::ColorU;
|
||||||
use warpui::r#async::Timer;
|
use warpui::r#async::Timer;
|
||||||
use warpui::windowing::{StateEvent, WindowManager};
|
use warpui::windowing::{StateEvent, WindowManager};
|
||||||
@@ -1921,8 +1921,8 @@ impl AgentConversationsModel {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Sort each by updated_at (newest first), truncate
|
// Sort each by updated_at (newest first), truncate
|
||||||
personal.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(|a, b| b.1.updated_at.cmp(&a.1.updated_at));
|
team.sort_by_key(|b| std::cmp::Reverse(b.1.updated_at));
|
||||||
personal.truncate(MAX_PERSONAL_TASKS);
|
personal.truncate(MAX_PERSONAL_TASKS);
|
||||||
team.truncate(MAX_TEAM_TASKS);
|
team.truncate(MAX_TEAM_TASKS);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
use galaxy_core::features::FeatureFlag;
|
||||||
use session_sharing_protocol::common::SessionId;
|
use session_sharing_protocol::common::SessionId;
|
||||||
use warp_cli::agent::Harness;
|
use warp_cli::agent::Harness;
|
||||||
use galaxy_core::features::FeatureFlag;
|
|
||||||
use warpui::{AppContext, SingletonEntity};
|
use warpui::{AppContext, SingletonEntity};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::{DateTime, Duration, Utc};
|
||||||
|
use galaxy_cli::agent::Harness;
|
||||||
use galaxy_core::features::FeatureFlag;
|
use galaxy_core::features::FeatureFlag;
|
||||||
use galaxyui::{App, EntityId};
|
use galaxyui::{App, EntityId, ModelHandle, SingletonEntity};
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use persistence::model::{AgentConversationData, ConversationUsageMetadata};
|
use persistence::model::{AgentConversationData, ConversationUsageMetadata};
|
||||||
use galaxy_cli::agent::Harness;
|
|
||||||
use galaxyui::{App, EntityId, ModelHandle, SingletonEntity};
|
|
||||||
|
|
||||||
use super::entry::{
|
use super::entry::{
|
||||||
AgentConversationEntryId, AgentConversationNavigationSubject, AgentConversationProvenance,
|
AgentConversationEntryId, AgentConversationNavigationSubject, AgentConversationProvenance,
|
||||||
@@ -238,6 +237,7 @@ fn test_title_update_refreshes_shadowing_task_title() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -344,6 +344,7 @@ fn test_display_status_uses_matching_conversation_for_in_progress_task() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -400,6 +401,7 @@ fn test_display_status_uses_active_execution_over_previous_conversation_status()
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -463,6 +465,7 @@ fn test_display_status_updates_when_blocked_conversation_resumes() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -542,6 +545,7 @@ fn test_display_status_terminal_task_state_overrides_matching_conversation() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -597,6 +601,7 @@ fn test_status_filter_uses_display_status_for_task_backed_conversations() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -792,6 +797,7 @@ fn create_server_conversation_metadata(
|
|||||||
token_usage: vec![],
|
token_usage: vec![],
|
||||||
tool_usage_metadata: Default::default(),
|
tool_usage_metadata: Default::default(),
|
||||||
context_window_segments: Vec::new(),
|
context_window_segments: Vec::new(),
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
metadata: mock_server_metadata(),
|
metadata: mock_server_metadata(),
|
||||||
creator: None,
|
creator: None,
|
||||||
@@ -928,6 +934,7 @@ fn test_get_entries_merges_task_and_local_conversation_by_run_id() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -983,6 +990,7 @@ fn test_get_entries_merges_task_and_local_conversation_by_server_token() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1191,6 +1199,7 @@ fn test_resolve_open_action_returns_none_for_active_unattachable_session() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1477,6 +1486,7 @@ fn test_server_token_assignment_updates_copy_link_resolution() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1639,6 +1649,7 @@ fn test_resolve_copy_link_uses_attached_synced_conversation_for_task_without_tok
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1966,6 +1977,7 @@ fn test_get_entries_prefers_task_when_task_id_matches_conversation_run_id() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2027,6 +2039,7 @@ fn test_get_entries_prefers_task_when_server_token_matches() {
|
|||||||
autoexecute_override: None,
|
autoexecute_override: None,
|
||||||
last_event_sequence: None,
|
last_event_sequence: None,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ use anyhow::{anyhow, Result};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::future::Either;
|
use futures::future::Either;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use galaxy_core::errors::AnyhowErrorExt as _;
|
||||||
use galaxyui::r#async::Timer;
|
use galaxyui::r#async::Timer;
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
use galaxy_core::errors::AnyhowErrorExt as _;
|
|
||||||
|
|
||||||
use crate::server::retry_strategies::is_transient_http_error;
|
use crate::server::retry_strategies::is_transient_http_error;
|
||||||
use crate::server::server_api::ai::AgentRunEvent;
|
use crate::server::server_api::ai::AgentRunEvent;
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ use anyhow::{anyhow, Context, Result};
|
|||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
use futures::future::Either;
|
use futures::future::Either;
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
use galaxyui::r#async::Timer;
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
use reqwest::Error as ReqwestError;
|
use reqwest::Error as ReqwestError;
|
||||||
#[cfg(not(target_family = "wasm"))]
|
|
||||||
use galaxyui::r#async::Timer;
|
|
||||||
|
|
||||||
use crate::ai::agent::ReceivedMessageInput;
|
use crate::ai::agent::ReceivedMessageInput;
|
||||||
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use settings::Setting as _;
|
|
||||||
use galaxy_core::features::FeatureFlag;
|
use galaxy_core::features::FeatureFlag;
|
||||||
use galaxyui::{App, EntityId, ModelHandle, SingletonEntity};
|
use galaxyui::{App, EntityId, ModelHandle, SingletonEntity};
|
||||||
|
use settings::Setting as _;
|
||||||
|
|
||||||
use super::AgentNotificationsModel;
|
use super::AgentNotificationsModel;
|
||||||
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
|
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
//! This modal is displayed when users click "New agent" to choose between
|
//! This modal is displayed when users click "New agent" to choose between
|
||||||
//! cloud and local agent modes.
|
//! 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::color::blend::Blend;
|
||||||
use galaxy_core::ui::theme::color::internal_colors;
|
use galaxy_core::ui::theme::color::internal_colors;
|
||||||
use galaxyui::elements::{
|
use galaxyui::elements::{
|
||||||
@@ -17,6 +15,8 @@ use galaxyui::keymap::{FixedBinding, Keystroke};
|
|||||||
use galaxyui::platform::Cursor;
|
use galaxyui::platform::Cursor;
|
||||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||||
use galaxyui::{AppContext, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
use galaxyui::{AppContext, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
||||||
|
use pathfinder_color::ColorU;
|
||||||
|
use pathfinder_geometry::vector::vec2f;
|
||||||
|
|
||||||
use crate::appearance::Appearance;
|
use crate::appearance::Appearance;
|
||||||
use crate::ui_components::icons::Icon;
|
use crate::ui_components::icons::Icon;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use galaxy_core::report_error;
|
||||||
|
use galaxy_core::ui::theme::{AnsiColorIdentifier, AnsiColors};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use string_offset::CharCounter;
|
use string_offset::CharCounter;
|
||||||
use warp_completer::signatures::CommandRegistry;
|
use warp_completer::signatures::CommandRegistry;
|
||||||
use warp_completer::util::parse_current_commands_and_tokens;
|
use warp_completer::util::parse_current_commands_and_tokens;
|
||||||
use warp_completer::ParsedTokensSnapshot;
|
use warp_completer::ParsedTokensSnapshot;
|
||||||
use galaxy_core::report_error;
|
|
||||||
use galaxy_core::ui::theme::{AnsiColorIdentifier, AnsiColors};
|
|
||||||
use warpui::clipboard::ClipboardContent;
|
use warpui::clipboard::ClipboardContent;
|
||||||
use warpui::elements::new_scrollable::{ClippedAxisConfiguration, DualAxisConfig, NewScrollable};
|
use warpui::elements::new_scrollable::{ClippedAxisConfiguration, DualAxisConfig, NewScrollable};
|
||||||
use warpui::elements::{
|
use warpui::elements::{
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pathfinder_color::ColorU;
|
|
||||||
use galaxy_core::ui::appearance::Appearance as CoreAppearance;
|
use galaxy_core::ui::appearance::Appearance as CoreAppearance;
|
||||||
use galaxy_core::ui::icons::Icon;
|
use galaxy_core::ui::icons::Icon;
|
||||||
use galaxy_core::ui::theme::color::internal_colors;
|
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::clipboard::ClipboardContent;
|
||||||
use galaxyui::elements::{
|
use galaxyui::elements::{
|
||||||
ChildView, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, DispatchEventResult,
|
ChildView, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, DispatchEventResult,
|
||||||
@@ -14,6 +13,7 @@ use galaxyui::elements::{
|
|||||||
use galaxyui::fonts::Weight;
|
use galaxyui::fonts::Weight;
|
||||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||||
use galaxyui::{View, ViewContext, ViewHandle};
|
use galaxyui::{View, ViewContext, ViewHandle};
|
||||||
|
use pathfinder_color::ColorU;
|
||||||
|
|
||||||
use crate::ai::agent::conversation::ConversationStatus;
|
use crate::ai::agent::conversation::ConversationStatus;
|
||||||
use crate::ai::agent_management::notifications::item::NotificationSourceAgent;
|
use crate::ai::agent_management::notifications::item::NotificationSourceAgent;
|
||||||
|
|||||||
@@ -4,13 +4,6 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use fuzzy_match::match_indices_case_insensitive;
|
use fuzzy_match::match_indices_case_insensitive;
|
||||||
use galaxy_core::features::FeatureFlag;
|
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::icons::Icon;
|
||||||
use galaxy_core::ui::theme::color::internal_colors;
|
use galaxy_core::ui::theme::color::internal_colors;
|
||||||
use galaxy_core::ui::theme::Fill;
|
use galaxy_core::ui::theme::Fill;
|
||||||
@@ -28,11 +21,18 @@ use galaxyui::elements::{
|
|||||||
use galaxyui::fonts::{Properties, Weight};
|
use galaxyui::fonts::{Properties, Weight};
|
||||||
use galaxyui::keymap::FixedBinding;
|
use galaxyui::keymap::FixedBinding;
|
||||||
use galaxyui::platform::Cursor;
|
use galaxyui::platform::Cursor;
|
||||||
|
use galaxyui::scene::DropShadow;
|
||||||
|
use galaxyui::ui_components::button::ButtonVariant;
|
||||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||||
use galaxyui::{
|
use galaxyui::{
|
||||||
AppContext, Entity, FocusContext, ModelHandle, SingletonEntity, TypedActionView, View,
|
AppContext, Entity, FocusContext, ModelHandle, SingletonEntity, TypedActionView, View,
|
||||||
ViewContext, ViewHandle, WeakViewHandle,
|
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::conversation::AIConversationId;
|
||||||
use crate::ai::agent_conversations_model::{
|
use crate::ai::agent_conversations_model::{
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use galaxy_cli::agent::OutputFormat;
|
use galaxy_cli::agent::OutputFormat;
|
||||||
use galaxyui::{platform::TerminationMode, AppContext, SingletonEntity};
|
|
||||||
use serde::Serialize;
|
|
||||||
use galaxyui::platform::TerminationMode;
|
use galaxyui::platform::TerminationMode;
|
||||||
use galaxyui::{AppContext, SingletonEntity};
|
use galaxyui::{AppContext, SingletonEntity};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::auth::auth_manager::{AuthManager, AuthManagerEvent};
|
use crate::auth::auth_manager::{AuthManager, AuthManagerEvent};
|
||||||
use crate::auth::user::PrincipalType;
|
use crate::auth::user::PrincipalType;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use std::time::Duration;
|
|||||||
use anyhow::{anyhow, Context as _};
|
use anyhow::{anyhow, Context as _};
|
||||||
use comfy_table::Cell;
|
use comfy_table::Cell;
|
||||||
use futures::{future, StreamExt};
|
use futures::{future, StreamExt};
|
||||||
|
use galaxy_core::channel::ChannelState;
|
||||||
|
use galaxy_core::features::FeatureFlag;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use warp_cli::agent::{Harness, OutputFormat, Prompt, RunCloudArgs};
|
use warp_cli::agent::{Harness, OutputFormat, Prompt, RunCloudArgs};
|
||||||
use warp_cli::json_filter::JsonOutput;
|
use warp_cli::json_filter::JsonOutput;
|
||||||
@@ -15,8 +17,6 @@ use warp_cli::task::{
|
|||||||
RunSourceArg, RunStateArg, TaskGetArgs,
|
RunSourceArg, RunStateArg, TaskGetArgs,
|
||||||
};
|
};
|
||||||
use warp_cli::{GlobalOptions, SortOrderArg};
|
use warp_cli::{GlobalOptions, SortOrderArg};
|
||||||
use galaxy_core::channel::ChannelState;
|
|
||||||
use galaxy_core::features::FeatureFlag;
|
|
||||||
use warpui::platform::TerminationMode;
|
use warpui::platform::TerminationMode;
|
||||||
use warpui::r#async::{Spawnable, Timer};
|
use warpui::r#async::{Spawnable, Timer};
|
||||||
use warpui::{AppContext, ModelContext, SingletonEntity};
|
use warpui::{AppContext, ModelContext, SingletonEntity};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use galaxy_cli::agent::OutputFormat;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use galaxy_cli::agent::OutputFormat;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ fn create_conversation_metadata(
|
|||||||
token_usage: vec![],
|
token_usage: vec![],
|
||||||
tool_usage_metadata: Default::default(),
|
tool_usage_metadata: Default::default(),
|
||||||
context_window_segments: Vec::new(),
|
context_window_segments: Vec::new(),
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
metadata: create_mock_server_metadata(),
|
metadata: create_mock_server_metadata(),
|
||||||
creator: None,
|
creator: None,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ use anyhow::{anyhow, Context as _};
|
|||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use futures::future::{self, join_all, Either};
|
use futures::future::{self, join_all, Either};
|
||||||
use futures::FutureExt as _;
|
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 handlebars::get_arguments;
|
||||||
use itertools::Itertools as _;
|
use itertools::Itertools as _;
|
||||||
use oneshot::{Canceled, Receiver};
|
use oneshot::{Canceled, Receiver};
|
||||||
@@ -26,8 +28,6 @@ use warp_cli::agent::{Harness, OutputFormat};
|
|||||||
use warp_cli::mcp::MCPSpec;
|
use warp_cli::mcp::MCPSpec;
|
||||||
use warp_cli::share::ShareRequest;
|
use warp_cli::share::ShareRequest;
|
||||||
use warp_cli::skill::SkillSpec;
|
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_graphql::ai::AgentTaskState;
|
||||||
use warp_managed_secrets::ManagedSecretValue;
|
use warp_managed_secrets::ManagedSecretValue;
|
||||||
use warp_util::local_or_remote_path::LocalOrRemotePath;
|
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::channel::oneshot;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use repo_metadata::repositories::{DetectedRepositories, RepoDetectionSource};
|
|
||||||
use galaxy_cli::agent::Harness;
|
use galaxy_cli::agent::Harness;
|
||||||
use galaxy_completer::completer::CommandExitStatus;
|
use galaxy_completer::completer::CommandExitStatus;
|
||||||
use galaxy_core::command::ExitCode;
|
use galaxy_core::command::ExitCode;
|
||||||
use galaxy_core::{safe_info, safe_warn};
|
use galaxy_core::{safe_info, safe_warn};
|
||||||
use galaxyui::r#async::FutureExt;
|
use galaxyui::r#async::FutureExt;
|
||||||
use galaxyui::{ModelContext, ModelSpawner, SingletonEntity};
|
use galaxyui::{ModelContext, ModelSpawner, SingletonEntity};
|
||||||
|
use repo_metadata::repositories::{DetectedRepositories, RepoDetectionSource};
|
||||||
|
|
||||||
use super::terminal::TerminalDriver;
|
use super::terminal::TerminalDriver;
|
||||||
use super::AgentDriverError;
|
use super::AgentDriverError;
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ use std::sync::Arc;
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use galaxy_cli::agent::Harness;
|
use galaxy_cli::agent::Harness;
|
||||||
|
use galaxy_managed_secrets::ManagedSecretValue;
|
||||||
use galaxyui::{ModelHandle, ModelSpawner};
|
use galaxyui::{ModelHandle, ModelSpawner};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use galaxy_managed_secrets::ManagedSecretValue;
|
|
||||||
|
|
||||||
use super::super::terminal::{CommandHandle, TerminalDriver};
|
use super::super::terminal::{CommandHandle, TerminalDriver};
|
||||||
use super::super::{AgentDriver, AgentDriverError};
|
use super::super::{AgentDriver, AgentDriverError};
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use std::sync::{Arc, OnceLock};
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use galaxy_core::features::FeatureFlag;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use warp_cli::agent::Harness;
|
use warp_cli::agent::Harness;
|
||||||
use galaxy_core::features::FeatureFlag;
|
|
||||||
use warp_managed_secrets::ManagedSecretValue;
|
use warp_managed_secrets::ManagedSecretValue;
|
||||||
use warpui::{ModelHandle, ModelSpawner, SingletonEntity};
|
use warpui::{ModelHandle, ModelSpawner, SingletonEntity};
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ use std::sync::Arc;
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use galaxy_cli::agent::Harness;
|
use galaxy_cli::agent::Harness;
|
||||||
use galaxy_managed_secrets::ManagedSecretValue;
|
|
||||||
use galaxyui::{ModelHandle, ModelSpawner, SingletonEntity};
|
|
||||||
use tempfile::NamedTempFile;
|
|
||||||
use galaxy_cli::{
|
use galaxy_cli::{
|
||||||
OZ_CLI_ENV, OZ_HARNESS_ENV, OZ_PARENT_RUN_ID_ENV, OZ_RUN_ID_ENV, SERVER_ROOT_URL_OVERRIDE_ENV,
|
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,
|
SESSION_SHARING_SERVER_URL_OVERRIDE_ENV, WS_SERVER_URL_OVERRIDE_ENV,
|
||||||
};
|
};
|
||||||
use galaxy_core::channel::ChannelState;
|
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::terminal::{CommandHandle, TerminalDriver};
|
||||||
use super::{
|
use super::{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use warp_cli::agent::Harness;
|
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;
|
use crate::ai::agent_sdk::driver::AgentDriverError;
|
||||||
|
|
||||||
fn assert_harness_setup_failed(err: &AgentDriverError) -> (&str, &str) {
|
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 serde_json::{json, Value};
|
||||||
use strum_macros::{EnumDiscriminants, EnumIter};
|
use strum_macros::{EnumDiscriminants, EnumIter};
|
||||||
use galaxy_core::telemetry::{EnablementState, TelemetryEvent, TelemetryEventDesc};
|
|
||||||
|
|
||||||
/// Telemetry events emitted by the third-party harness runtime layer.
|
/// Telemetry events emitted by the third-party harness runtime layer.
|
||||||
#[derive(Debug, EnumDiscriminants)]
|
#[derive(Debug, EnumDiscriminants)]
|
||||||
|
|||||||
@@ -564,17 +564,19 @@ pub mod text {
|
|||||||
|
|
||||||
pub mod json {
|
pub mod json {
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::io::{self, Write};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::ai::agent::comment::ReviewComment;
|
use crate::ai::agent::comment::ReviewComment;
|
||||||
use crate::ai::agent::{
|
use crate::ai::agent::{
|
||||||
AIAgentActionType, AIAgentInput, AIAgentOutput, AIAgentOutputMessage,
|
AIAgentActionResultType, AIAgentActionType, AIAgentInput, AIAgentOutput,
|
||||||
AIAgentOutputMessageType, AIAgentTodo, ArtifactCreatedData, CallMCPToolResult, FileContext,
|
AIAgentOutputMessage, AIAgentOutputMessageType, AIAgentTodo, ArtifactCreatedData,
|
||||||
FileGlobResult, FileGlobV2Result, GrepResult, ReadFilesResult, ReadMCPResourceResult,
|
CallMCPToolResult, FileContext, FileGlobResult, FileGlobV2Result, GrepResult,
|
||||||
RequestCommandOutputResult, RequestFileEditsResult, SearchCodebaseResult, SubagentCall,
|
ReadFilesResult, ReadMCPResourceResult, RequestCommandOutputResult, RequestFileEditsResult,
|
||||||
TodoOperation, UploadArtifactResult, WriteToLongRunningShellCommandResult,
|
SearchCodebaseResult, SubagentCall, TodoOperation, UploadArtifactResult,
|
||||||
|
WriteToLongRunningShellCommandResult,
|
||||||
};
|
};
|
||||||
use crate::code::buffer_location::LocalOrRemotePath;
|
use crate::code::buffer_location::LocalOrRemotePath;
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ use anyhow::{Context as _, Result};
|
|||||||
use command::r#async::Command;
|
use command::r#async::Command;
|
||||||
use command::Stdio;
|
use command::Stdio;
|
||||||
use futures::future::join_all;
|
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 galaxy_core::report_error;
|
||||||
use galaxyui::r#async::executor::Background;
|
use galaxyui::r#async::executor::Background;
|
||||||
use galaxyui::r#async::FutureExt as _;
|
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::agent_sdk::retry::with_bounded_retry;
|
||||||
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
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();
|
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);
|
target_map.insert(file.filename.clone(), target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1006,7 +1006,7 @@ async fn upload_gathered_snapshot(
|
|||||||
chunk.len(),
|
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);
|
target_map.insert(file.filename.clone(), target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ use std::task::{Context, Poll};
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use futures::channel::oneshot;
|
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_cli::share::{ShareAccessLevel, ShareRequest, ShareSubject};
|
||||||
use galaxy_completer::completer::CommandOutput;
|
use galaxy_completer::completer::CommandOutput;
|
||||||
use galaxy_core::command::ExitCode;
|
use galaxy_core::command::ExitCode;
|
||||||
@@ -18,6 +16,8 @@ use galaxy_terminal::model::grid::Dimensions;
|
|||||||
use galaxy_util::path::ShellFamily;
|
use galaxy_util::path::ShellFamily;
|
||||||
use galaxyui::r#async::FutureExt;
|
use galaxyui::r#async::FutureExt;
|
||||||
use galaxyui::{AppContext, Entity, ModelContext, ModelHandle, SingletonEntity as _, ViewHandle};
|
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 super::AgentDriverError;
|
||||||
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
use crate::ai::ambient_agents::AmbientAgentTaskId;
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ use std::time::Duration;
|
|||||||
use cloud_object_models::CodeForge;
|
use cloud_object_models::CodeForge;
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use repo_metadata::{DirectoryWatcher, RepoMetadataEvent, RepoMetadataModel, RepositoryIdentifier};
|
|
||||||
use tempfile::TempDir;
|
|
||||||
use galaxy_cli::agent::Harness;
|
use galaxy_cli::agent::Harness;
|
||||||
use galaxy_cli::mcp::MCPSpec;
|
use galaxy_cli::mcp::MCPSpec;
|
||||||
use galaxy_cli::skill::SkillSpec;
|
use galaxy_cli::skill::SkillSpec;
|
||||||
@@ -25,6 +23,8 @@ use galaxy_graphql::response_context::ResponseContext;
|
|||||||
use galaxy_managed_secrets::ManagedSecretValue;
|
use galaxy_managed_secrets::ManagedSecretValue;
|
||||||
use galaxy_util::standardized_path::StandardizedPath;
|
use galaxy_util::standardized_path::StandardizedPath;
|
||||||
use galaxyui::{App, SingletonEntity as _};
|
use galaxyui::{App, SingletonEntity as _};
|
||||||
|
use repo_metadata::{DirectoryWatcher, RepoMetadataEvent, RepoMetadataModel, RepositoryIdentifier};
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
build_secret_env_vars, AgentDriver, AgentDriverError, IdleTimeoutSender,
|
build_secret_env_vars, AgentDriver, AgentDriverError, IdleTimeoutSender,
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use comfy_table::Cell;
|
use comfy_table::Cell;
|
||||||
use cynic::QueryBuilder;
|
use cynic::QueryBuilder;
|
||||||
use inquire::error::InquireError;
|
|
||||||
use inquire::{Confirm, Select};
|
|
||||||
use serde::Serialize;
|
|
||||||
use galaxy_cli::agent::OutputFormat;
|
use galaxy_cli::agent::OutputFormat;
|
||||||
use galaxy_cli::environment::{EnvironmentCommand, ImageCommand};
|
use galaxy_cli::environment::{EnvironmentCommand, ImageCommand};
|
||||||
use galaxy_cli::scope::ObjectScope;
|
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 galaxy_graphql::queries::user_repo_auth_status::UserRepoAuthStatusEnum;
|
||||||
use galaxyui::r#async::FutureExt;
|
use galaxyui::r#async::FutureExt;
|
||||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
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::driver::WARP_DRIVE_SYNC_TIMEOUT;
|
||||||
use crate::ai::agent_sdk::oauth_flow::poll_oauth_until_terminal;
|
use crate::ai::agent_sdk::oauth_flow::poll_oauth_until_terminal;
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
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::agent::OutputFormat;
|
||||||
|
use galaxy_cli::federate::{FederateCommand, IssueGcpTokenArgs, IssueTokenArgs};
|
||||||
use galaxy_cli::GlobalOptions;
|
use galaxy_cli::GlobalOptions;
|
||||||
use galaxy_core::features::FeatureFlag;
|
use galaxy_core::features::FeatureFlag;
|
||||||
use galaxy_core::report_error;
|
use galaxy_core::report_error;
|
||||||
|
use galaxy_managed_secrets::ManagedSecretManager;
|
||||||
use galaxyui::platform::TerminationMode;
|
use galaxyui::platform::TerminationMode;
|
||||||
use galaxyui::{AppContext, SingletonEntity as _};
|
use galaxyui::{AppContext, SingletonEntity as _};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use super::common::set_ambient_task_context_from_run_id;
|
use super::common::set_ambient_task_context_from_run_id;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use comfy_table::presets::UTF8_FULL;
|
use comfy_table::presets::UTF8_FULL;
|
||||||
use comfy_table::{Cell, Table};
|
use comfy_table::{Cell, Table};
|
||||||
use serde::Serialize;
|
|
||||||
use serde_json::{Map, Value};
|
|
||||||
use galaxy_cli::agent::OutputFormat;
|
use galaxy_cli::agent::OutputFormat;
|
||||||
use galaxy_graphql::queries::get_simple_integrations::{
|
use galaxy_graphql::queries::get_simple_integrations::{
|
||||||
ListedSimpleIntegrationConfig, SimpleIntegration, SimpleIntegrationConnectionStatus,
|
ListedSimpleIntegrationConfig, SimpleIntegration, SimpleIntegrationConnectionStatus,
|
||||||
SimpleIntegrationsOutput,
|
SimpleIntegrationsOutput,
|
||||||
};
|
};
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||||
use crate::util::time_format::format_approx_duration_from_now_utc;
|
use crate::util::time_format::format_approx_duration_from_now_utc;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use comfy_table::Cell;
|
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::mcp::MCPCommand;
|
||||||
use galaxy_cli::GlobalOptions;
|
use galaxy_cli::GlobalOptions;
|
||||||
|
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||||
use crate::ai::mcp::TemplatableMCPServerManager;
|
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(crate) use driver::harness::{task_env_vars, validate_cli_installed, ClaudeHarness};
|
||||||
pub use driver::AgentDriver;
|
pub use driver::AgentDriver;
|
||||||
use driver::AgentDriverError;
|
use driver::AgentDriverError;
|
||||||
|
use galaxy_core::features::FeatureFlag;
|
||||||
use telemetry::CliTelemetryEvent;
|
use telemetry::CliTelemetryEvent;
|
||||||
use tracing::Instrument as _;
|
use tracing::Instrument as _;
|
||||||
use warp_cli::agent::{
|
use warp_cli::agent::{
|
||||||
@@ -32,7 +33,6 @@ use warp_cli::secret::SecretCommand;
|
|||||||
use warp_cli::share::ShareRequest;
|
use warp_cli::share::ShareRequest;
|
||||||
use warp_cli::task::{MessageCommand, TaskCommand};
|
use warp_cli::task::{MessageCommand, TaskCommand};
|
||||||
use warp_cli::{CliCommand, GlobalOptions, OZ_HARNESS_ENV};
|
use warp_cli::{CliCommand, GlobalOptions, OZ_HARNESS_ENV};
|
||||||
use galaxy_core::features::FeatureFlag;
|
|
||||||
use warp_graphql::object_permissions::OwnerType;
|
use warp_graphql::object_permissions::OwnerType;
|
||||||
use warp_isolation_platform::IsolationPlatformError;
|
use warp_isolation_platform::IsolationPlatformError;
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use serde_json::json;
|
|
||||||
use galaxy_cli::agent::Harness;
|
use galaxy_cli::agent::Harness;
|
||||||
use galaxy_cli::artifact::{
|
use galaxy_cli::artifact::{
|
||||||
ArtifactCommand, DownloadArtifactArgs, GetArtifactArgs, UploadArtifactArgs,
|
ArtifactCommand, DownloadArtifactArgs, GetArtifactArgs, UploadArtifactArgs,
|
||||||
@@ -6,6 +5,7 @@ use galaxy_cli::artifact::{
|
|||||||
use galaxy_cli::task::{MessageCommand, MessageSendArgs, MessageWatchArgs, TaskCommand};
|
use galaxy_cli::task::{MessageCommand, MessageSendArgs, MessageWatchArgs, TaskCommand};
|
||||||
use galaxy_cli::CliCommand;
|
use galaxy_cli::CliCommand;
|
||||||
use galaxy_core::telemetry::TelemetryEvent;
|
use galaxy_core::telemetry::TelemetryEvent;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use super::{command_requires_auth, command_to_telemetry_event, reconcile_task_harness};
|
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::modifiers::UTF8_ROUND_CORNERS;
|
||||||
use comfy_table::presets::UTF8_FULL;
|
use comfy_table::presets::UTF8_FULL;
|
||||||
use comfy_table::{Cell, ContentArrangement, Table};
|
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 jaq_json directly to ensure serde support is included.
|
||||||
use galaxy_cli::agent::OutputFormat;
|
use galaxy_cli::agent::OutputFormat;
|
||||||
use galaxy_cli::json_filter::{JqFilter, JsonOutput};
|
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 jaq_json::{write as jaq_write, Val};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tabwriter::TabWriter;
|
use tabwriter::TabWriter;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use comfy_table::Cell;
|
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::agent::AgentProfileCommand;
|
||||||
use galaxy_cli::GlobalOptions;
|
use galaxy_cli::GlobalOptions;
|
||||||
|
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||||
use crate::ai::execution_profiles::profiles::AIExecutionProfilesModel;
|
use crate::ai::execution_profiles::profiles::AIExecutionProfilesModel;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
//! Provider command for linking third-party services.
|
//! Provider command for linking third-party services.
|
||||||
use comfy_table::Cell;
|
use comfy_table::Cell;
|
||||||
use serde::Serialize;
|
|
||||||
use galaxy_cli::provider::{ProviderCommand, ProviderType};
|
use galaxy_cli::provider::{ProviderCommand, ProviderType};
|
||||||
use galaxy_cli::GlobalOptions;
|
use galaxy_cli::GlobalOptions;
|
||||||
use galaxy_core::channel::ChannelState;
|
use galaxy_core::channel::ChannelState;
|
||||||
use galaxyui::platform::TerminationMode;
|
use galaxyui::platform::TerminationMode;
|
||||||
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
use galaxyui::{AppContext, ModelContext, SingletonEntity};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::ai::agent_sdk::output::{self, TableFormat};
|
use crate::ai::agent_sdk::output::{self, TableFormat};
|
||||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use comfy_table::Cell;
|
use comfy_table::Cell;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use serde::Serialize;
|
|
||||||
use galaxy_cli::agent::OutputFormat;
|
use galaxy_cli::agent::OutputFormat;
|
||||||
use galaxy_cli::schedule::{
|
use galaxy_cli::schedule::{
|
||||||
CreateScheduleArgs, DeleteScheduleArgs, GetScheduleArgs, PauseScheduleArgs, ScheduleCommand,
|
CreateScheduleArgs, DeleteScheduleArgs, GetScheduleArgs, PauseScheduleArgs, ScheduleCommand,
|
||||||
@@ -11,6 +10,7 @@ use galaxy_cli::GlobalOptions;
|
|||||||
use galaxy_graphql::queries::get_scheduled_agent_history::ScheduledAgentHistory;
|
use galaxy_graphql::queries::get_scheduled_agent_history::ScheduledAgentHistory;
|
||||||
use galaxyui::platform::TerminationMode;
|
use galaxyui::platform::TerminationMode;
|
||||||
use galaxyui::{AppContext, SingletonEntity};
|
use galaxyui::{AppContext, SingletonEntity};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::common::{EnvironmentChoice, ResolveConfigurationError};
|
use super::common::{EnvironmentChoice, ResolveConfigurationError};
|
||||||
use super::output::{self, TableFormat};
|
use super::output::{self, TableFormat};
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ use std::io::{self, IsTerminal as _, Read};
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use comfy_table::Cell;
|
use comfy_table::Cell;
|
||||||
use inquire::{Confirm, InquireError, Password};
|
|
||||||
use serde::Serialize;
|
|
||||||
use galaxy_cli::agent::OutputFormat;
|
use galaxy_cli::agent::OutputFormat;
|
||||||
use galaxy_cli::scope::ObjectScope;
|
use galaxy_cli::scope::ObjectScope;
|
||||||
use galaxy_cli::secret::{
|
use galaxy_cli::secret::{
|
||||||
@@ -20,6 +18,8 @@ use galaxy_managed_secrets::client::SecretOwner;
|
|||||||
use galaxy_managed_secrets::{ManagedSecretManager, ManagedSecretValue};
|
use galaxy_managed_secrets::{ManagedSecretManager, ManagedSecretValue};
|
||||||
use galaxyui::platform::TerminationMode;
|
use galaxyui::platform::TerminationMode;
|
||||||
use galaxyui::{AppContext, SingletonEntity as _};
|
use galaxyui::{AppContext, SingletonEntity as _};
|
||||||
|
use inquire::{Confirm, InquireError, Password};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::output::{self, TableFormat};
|
use super::output::{self, TableFormat};
|
||||||
use crate::auth::UserUid;
|
use crate::auth::UserUid;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use galaxy_core::telemetry::{EnablementState, TelemetryEvent, TelemetryEventDesc};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use strum_macros::{EnumDiscriminants, EnumIter};
|
use strum_macros::{EnumDiscriminants, EnumIter};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use ai::index::full_source_code_embedding::manager::CodebaseIndexManager;
|
use ai::index::full_source_code_embedding::manager::CodebaseIndexManager;
|
||||||
use markdown_parser::FormattedTextFragment;
|
use markdown_parser::FormattedTextFragment;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
use warpui::keymap::Keystroke;
|
use warpui::keymap::Keystroke;
|
||||||
use warpui::r#async::{SpawnedFutureHandle, Timer};
|
use warpui::r#async::{SpawnedFutureHandle, Timer};
|
||||||
use warpui::{AppContext, Entity, ModelContext, SingletonEntity};
|
use warpui::{AppContext, Entity, ModelContext, SingletonEntity};
|
||||||
@@ -624,7 +625,6 @@ impl AITipModel<crate::terminal::view::ambient_agent::CloudModeTip> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Select a random tip
|
// Select a random tip
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
self.current_tip = self.tips.choose(&mut rng).cloned();
|
self.current_tip = self.tips.choose(&mut rng).cloned();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pathfinder_geometry::vector::vec2f;
|
|
||||||
use galaxy_core::ui::icons;
|
use galaxy_core::ui::icons;
|
||||||
use galaxy_core::ui::icons::ICON_DIMENSIONS;
|
use galaxy_core::ui::icons::ICON_DIMENSIONS;
|
||||||
use galaxy_core::ui::theme::Fill as ThemeFill;
|
use galaxy_core::ui::theme::Fill as ThemeFill;
|
||||||
@@ -20,6 +19,7 @@ use galaxyui::{
|
|||||||
id, AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
|
id, AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View,
|
||||||
ViewContext, ViewHandle,
|
ViewContext, ViewHandle,
|
||||||
};
|
};
|
||||||
|
use pathfinder_geometry::vector::vec2f;
|
||||||
|
|
||||||
use crate::ai::agent::conversation::AIConversationId;
|
use crate::ai::agent::conversation::AIConversationId;
|
||||||
use crate::ai::blocklist::agent_view::AgentViewEntryOrigin;
|
use crate::ai::blocklist::agent_view::AgentViewEntryOrigin;
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ pub use cloud_object_models::{
|
|||||||
};
|
};
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use serde_json::{Map, Value};
|
|
||||||
use galaxy_graphql::queries::get_scheduled_agent_history::ScheduledAgentHistory;
|
use galaxy_graphql::queries::get_scheduled_agent_history::ScheduledAgentHistory;
|
||||||
use galaxyui::{AppContext, Entity, ModelContext, ModelHandle, SingletonEntity};
|
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::generic_string_model::StringModel;
|
||||||
use crate::cloud_object::model::json_model::JsonModel;
|
use crate::cloud_object::model::json_model::JsonModel;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use futures::StreamExt;
|
||||||
use session_sharing_protocol::common::SessionId;
|
use session_sharing_protocol::common::SessionId;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@@ -10,7 +11,9 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::ai::agent::UserQueryMode;
|
use crate::ai::agent::UserQueryMode;
|
||||||
use crate::ai::ambient_agents::{AmbientAgentTask, AmbientAgentTaskState};
|
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::ai::{MockAIClient, SpawnAgentResponse, TaskStatusMessage};
|
||||||
|
use crate::server::server_api::presigned_upload::HttpStatusError;
|
||||||
use crate::terminal::shared_session;
|
use crate::terminal::shared_session;
|
||||||
|
|
||||||
fn task_with(
|
fn task_with(
|
||||||
@@ -127,7 +130,6 @@ async fn followup_submits_before_polling_and_ignores_previous_session_id() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn followup_api_error_does_not_poll() {
|
async fn followup_api_error_does_not_poll() {
|
||||||
|
|
||||||
let mut mock = MockAIClient::new();
|
let mut mock = MockAIClient::new();
|
||||||
mock.expect_submit_run_followup()
|
mock.expect_submit_run_followup()
|
||||||
.times(1)
|
.times(1)
|
||||||
@@ -154,7 +156,6 @@ async fn followup_api_error_does_not_poll() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn followup_terminal_failure_surfaces_status_message() {
|
async fn followup_terminal_failure_surfaces_status_message() {
|
||||||
|
|
||||||
// Post-fix, a follow-up only surfaces a terminal-state failure after observing at least
|
// 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
|
// 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
|
// 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]
|
#[tokio::test]
|
||||||
async fn followup_without_previous_session_id_accepts_joinable_session() {
|
async fn followup_without_previous_session_id_accepts_joinable_session() {
|
||||||
|
|
||||||
let session_id = SessionId::new();
|
let session_id = SessionId::new();
|
||||||
let expected_session_id = session_id;
|
let expected_session_id = session_id;
|
||||||
let mut mock = MockAIClient::new();
|
let mut mock = MockAIClient::new();
|
||||||
@@ -285,7 +285,6 @@ async fn followup_without_previous_session_id_accepts_joinable_session() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn followup_without_previous_session_id_errors_if_run_finishes_before_session() {
|
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
|
// 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
|
// must first observe a working state before a terminal `Succeeded` is interpreted as
|
||||||
// the follow-up's outcome.
|
// the follow-up's outcome.
|
||||||
@@ -356,7 +355,6 @@ async fn followup_without_previous_session_id_errors_if_run_finishes_before_sess
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn followup_skips_prior_terminal_state_until_working_then_attaches() {
|
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
|
// 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
|
// 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
|
// 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]
|
#[tokio::test]
|
||||||
async fn followup_skips_prior_terminal_then_surfaces_real_failure() {
|
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
|
// 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
|
// 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.
|
// 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]
|
#[tokio::test]
|
||||||
async fn followup_cancelled_state_breaks_skip_loop() {
|
async fn followup_cancelled_state_breaks_skip_loop() {
|
||||||
|
|
||||||
// `Cancelled` is a carve-out: even before a working state has been observed it falls
|
// `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
|
// through to terminal handling so a user-initiated cancellation can never leak an
|
||||||
// infinite poll loop.
|
// infinite poll loop.
|
||||||
@@ -581,7 +577,6 @@ async fn followup_cancelled_state_breaks_skip_loop() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn followup_bounded_skip_for_server_stall() {
|
async fn followup_bounded_skip_for_server_stall() {
|
||||||
|
|
||||||
// If the server is wedged on the prior terminal state, the bounded-skip counter must
|
// 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.
|
// eventually give up so the stream doesn't poll forever.
|
||||||
let call_count = Arc::new(AtomicUsize::new(0));
|
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 {
|
fn transient_http_error() -> anyhow::Error {
|
||||||
use crate::server::server_api::presigned_upload::HttpStatusError;
|
|
||||||
anyhow::Error::new(HttpStatusError {
|
anyhow::Error::new(HttpStatusError {
|
||||||
status: 429,
|
status: 429,
|
||||||
body: "Too Many Requests".to_string(),
|
body: "Too Many Requests".to_string(),
|
||||||
@@ -660,9 +654,6 @@ fn permanent_http_error() -> anyhow::Error {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn poll_retries_transient_429_errors() {
|
async fn poll_retries_transient_429_errors() {
|
||||||
|
|
||||||
use crate::server::retry_strategies::MAX_ATTEMPTS;
|
|
||||||
|
|
||||||
let mut mock = MockAIClient::new();
|
let mut mock = MockAIClient::new();
|
||||||
let call_count = Arc::new(AtomicUsize::new(0));
|
let call_count = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
@@ -739,7 +730,6 @@ async fn poll_retries_transient_429_errors() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn poll_fails_on_permanent_http_error() {
|
async fn poll_fails_on_permanent_http_error() {
|
||||||
|
|
||||||
let mut mock = MockAIClient::new();
|
let mut mock = MockAIClient::new();
|
||||||
|
|
||||||
mock.expect_spawn_agent().returning(|_| {
|
mock.expect_spawn_agent().returning(|_| {
|
||||||
@@ -801,8 +791,6 @@ async fn poll_fails_on_permanent_http_error() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn poll_gives_up_after_max_transient_retries() {
|
async fn poll_gives_up_after_max_transient_retries() {
|
||||||
|
|
||||||
|
|
||||||
let mut mock = MockAIClient::new();
|
let mut mock = MockAIClient::new();
|
||||||
let call_count = Arc::new(AtomicUsize::new(0));
|
let call_count = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
@@ -871,7 +859,6 @@ async fn poll_gives_up_after_max_transient_retries() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn poll_stops_on_terminal_failure_like_state() {
|
async fn poll_stops_on_terminal_failure_like_state() {
|
||||||
|
|
||||||
let mut mock = MockAIClient::new();
|
let mut mock = MockAIClient::new();
|
||||||
|
|
||||||
mock.expect_spawn_agent().returning(|_| {
|
mock.expect_spawn_agent().returning(|_| {
|
||||||
@@ -1001,7 +988,6 @@ fn session_join_info_ignores_empty_link_and_invalid_session_id() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn poll_for_session_join_info_waits_until_link_is_available() {
|
async fn poll_for_session_join_info_waits_until_link_is_available() {
|
||||||
|
|
||||||
let mut mock = MockAIClient::new();
|
let mut mock = MockAIClient::new();
|
||||||
|
|
||||||
let call_count = Arc::new(AtomicUsize::new(0));
|
let call_count = Arc::new(AtomicUsize::new(0));
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ use chrono::{DateTime, Duration as ChronoDuration, Utc};
|
|||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
pub use cloud_object_models::HarnessModelConfig;
|
pub use cloud_object_models::HarnessModelConfig;
|
||||||
pub use cloud_object_models::{AgentConfigSnapshot, HarnessAuthSecretsConfig, HarnessConfig};
|
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 iso8601_duration::Duration as Iso8601Duration;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use session_sharing_protocol::common::SessionId;
|
use session_sharing_protocol::common::SessionId;
|
||||||
use url::Url;
|
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 super::AmbientAgentTaskId;
|
||||||
use crate::ai::artifacts::{deserialize_artifacts, Artifact};
|
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::Serialize;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use strum_macros::{EnumDiscriminants, EnumIter};
|
use strum_macros::{EnumDiscriminants, EnumIter};
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ use aws_credential_types::provider::error::CredentialsError;
|
|||||||
use aws_credential_types::provider::ProvideCredentials;
|
use aws_credential_types::provider::ProvideCredentials;
|
||||||
use futures::channel::oneshot::channel;
|
use futures::channel::oneshot::channel;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use tokio::sync::Mutex;
|
|
||||||
use vec1::vec1;
|
|
||||||
use galaxy_managed_secrets::client::IdentityTokenOptions;
|
use galaxy_managed_secrets::client::IdentityTokenOptions;
|
||||||
use galaxy_managed_secrets::ManagedSecretManager;
|
use galaxy_managed_secrets::ManagedSecretManager;
|
||||||
use galaxyui::{ModelContext, ModelHandle, SingletonEntity};
|
use galaxyui::{ModelContext, ModelHandle, SingletonEntity};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use vec1::vec1;
|
||||||
|
|
||||||
use crate::settings::{AISettings, AISettingsChangedEvent};
|
use crate::settings::{AISettings, AISettingsChangedEvent};
|
||||||
use crate::terminal::event::{AfterBlockCompletedEvent, BlockType, UserBlockCompleted};
|
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 region_provider = aws_config::meta::region::RegionProviderChain::default_provider();
|
||||||
let loader =
|
let loader =
|
||||||
aws_config::defaults(aws_config::BehaviorVersion::latest()).region(region_provider);
|
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
|
loader // Let AWS SDK use its default behavior
|
||||||
} else {
|
} else {
|
||||||
loader.profile_name(profile)
|
loader.profile_name(profile)
|
||||||
|
|||||||
@@ -2,17 +2,17 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use aws_config::BehaviorVersion;
|
use aws_config::BehaviorVersion;
|
||||||
|
use aws_credential_types::provider::ProvideCredentials;
|
||||||
use aws_sdk_bedrockruntime::config::Region;
|
use aws_sdk_bedrockruntime::config::Region;
|
||||||
use aws_sdk_bedrockruntime::Client as BedrockRuntimeClient;
|
use aws_sdk_bedrockruntime::Client as BedrockRuntimeClient;
|
||||||
|
|
||||||
use crate::settings::ai::BedrockAuthMethod;
|
|
||||||
|
|
||||||
use super::convert::{build_converse_request, CachingConfig, ConversationMessage, ToolDefinition};
|
use super::convert::{build_converse_request, CachingConfig, ConversationMessage, ToolDefinition};
|
||||||
use super::diagnostic::BedrockDiagnosticLogger;
|
use super::diagnostic::BedrockDiagnosticLogger;
|
||||||
use super::external_config::ExternalBedrockConfig;
|
use super::external_config::ExternalBedrockConfig;
|
||||||
use super::models::apply_cross_region_prefix;
|
use super::models::apply_cross_region_prefix;
|
||||||
use super::response_translator::bedrock_stream_to_response_events;
|
use super::response_translator::bedrock_stream_to_response_events;
|
||||||
use crate::ai::agent::api::ResponseStream;
|
use crate::ai::agent::api::ResponseStream;
|
||||||
|
use crate::settings::ai::BedrockAuthMethod;
|
||||||
|
|
||||||
fn strip_context_marker(model_id: &str) -> String {
|
fn strip_context_marker(model_id: &str) -> String {
|
||||||
if let Some(base) = model_id.strip_suffix("[1m]") {
|
if let Some(base) = model_id.strip_suffix("[1m]") {
|
||||||
@@ -36,6 +36,7 @@ pub struct BedrockClientConfig {
|
|||||||
pub region: String,
|
pub region: String,
|
||||||
pub access_key_id: String,
|
pub access_key_id: String,
|
||||||
pub secret_access_key: String,
|
pub secret_access_key: String,
|
||||||
|
pub session_token: Option<String>,
|
||||||
pub cross_region_inference: bool,
|
pub cross_region_inference: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,10 +87,23 @@ pub enum BedrockError {
|
|||||||
|
|
||||||
impl BedrockClient {
|
impl BedrockClient {
|
||||||
pub async fn from_config(config: BedrockClientConfig) -> Result<Self, BedrockError> {
|
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 {
|
let aws_config = match config.auth_method {
|
||||||
BedrockAuthMethod::Profile | BedrockAuthMethod::Sso => {
|
BedrockAuthMethod::Profile | BedrockAuthMethod::Sso => {
|
||||||
let mut loader =
|
let mut loader = aws_config::defaults(BehaviorVersion::latest());
|
||||||
aws_config::defaults(BehaviorVersion::latest()).profile_name(&config.profile);
|
|
||||||
|
if !config.profile.is_empty() && config.profile != "default" {
|
||||||
|
loader = loader.profile_name(&config.profile);
|
||||||
|
}
|
||||||
|
|
||||||
if !config.region.is_empty() {
|
if !config.region.is_empty() {
|
||||||
loader = loader.region(Region::new(config.region.clone()));
|
loader = loader.region(Region::new(config.region.clone()));
|
||||||
@@ -105,7 +119,7 @@ impl BedrockClient {
|
|||||||
let creds = aws_credential_types::Credentials::new(
|
let creds = aws_credential_types::Credentials::new(
|
||||||
&config.access_key_id,
|
&config.access_key_id,
|
||||||
&config.secret_access_key,
|
&config.secret_access_key,
|
||||||
None,
|
config.session_token,
|
||||||
None,
|
None,
|
||||||
"warp-bedrock-static",
|
"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
|
let region = aws_config
|
||||||
.region()
|
.region()
|
||||||
.map(|r| r.to_string())
|
.map(|r| r.to_string())
|
||||||
@@ -136,6 +168,7 @@ impl BedrockClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn converse_stream(
|
pub async fn converse_stream(
|
||||||
&self,
|
&self,
|
||||||
model_id: &str,
|
model_id: &str,
|
||||||
@@ -174,6 +207,13 @@ impl BedrockClient {
|
|||||||
tools.len()
|
tools.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"[bedrock] Sending request payload to Bedrock:\nSystem Prompt: {:?}\nMessages: {:#?}\nTools: {:#?}",
|
||||||
|
system_prompt,
|
||||||
|
messages,
|
||||||
|
tools
|
||||||
|
);
|
||||||
|
|
||||||
let converted = build_converse_request(
|
let converted = build_converse_request(
|
||||||
messages.clone(),
|
messages.clone(),
|
||||||
system_prompt.clone(),
|
system_prompt.clone(),
|
||||||
@@ -302,15 +342,13 @@ impl BedrockClient {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut response_text = String::new();
|
let mut response_text = String::new();
|
||||||
if let Some(output_msg) = output.output() {
|
if let Some(aws_sdk_bedrockruntime::types::ConverseOutput::Message(msg)) = output.output() {
|
||||||
if let aws_sdk_bedrockruntime::types::ConverseOutput::Message(msg) = output_msg {
|
|
||||||
for block in msg.content() {
|
for block in msg.content() {
|
||||||
if let aws_sdk_bedrockruntime::types::ContentBlock::Text(text) = block {
|
if let aws_sdk_bedrockruntime::types::ContentBlock::Text(text) = block {
|
||||||
response_text.push_str(text);
|
response_text.push_str(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let (input_tokens, output_tokens) = output
|
let (input_tokens, output_tokens) = output
|
||||||
.usage()
|
.usage()
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use aws_smithy_types::Document;
|
|||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
use super::external_config::ExternalBedrockConfig;
|
use super::external_config::ExternalBedrockConfig;
|
||||||
|
|
||||||
// Re-export shared provider types so existing imports from bedrock::convert continue to work.
|
// Re-export shared provider types so existing imports from bedrock::convert continue to work.
|
||||||
pub use crate::ai::provider::types::{
|
pub use crate::ai::provider::types::{
|
||||||
ContentPart, ConversationMessage, MessageContent, MessageRole, ToolDefinition,
|
ContentPart, ConversationMessage, MessageContent, MessageRole, ToolDefinition,
|
||||||
@@ -47,6 +46,7 @@ pub struct ConvertedRequest {
|
|||||||
pub tool_config: Option<ToolConfiguration>,
|
pub tool_config: Option<ToolConfiguration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn build_converse_request(
|
pub fn build_converse_request(
|
||||||
messages: Vec<ConversationMessage>,
|
messages: Vec<ConversationMessage>,
|
||||||
system_prompt: Option<String>,
|
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 serde_json::json;
|
||||||
|
|
||||||
use super::convert::*;
|
use super::convert::*;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
use chrono::{Local, Utc};
|
#![allow(dead_code)]
|
||||||
use serde_json::Value as JsonValue;
|
|
||||||
use std::fs::{self, File, OpenOptions};
|
use std::fs::{self, File, OpenOptions};
|
||||||
use std::io::{BufWriter, Read, Seek, SeekFrom, Write};
|
use std::io::{BufWriter, Read, Seek, SeekFrom, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use chrono::{Local, Utc};
|
||||||
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
use super::convert::{ConversationMessage, MessageContent, MessageRole, ToolDefinition};
|
use super::convert::{ConversationMessage, MessageContent, MessageRole, ToolDefinition};
|
||||||
|
|
||||||
const ENV_VAR: &str = "GALAXY_BEDROCK_DIAGNOSTICS";
|
const ENV_VAR: &str = "GALAXY_BEDROCK_DIAGNOSTICS";
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::path::PathBuf;
|
use warp_multi_agent_api as api;
|
||||||
|
|
||||||
use super::client::{BedrockClient, BedrockClientConfig};
|
use super::client::{BedrockClient, BedrockClientConfig};
|
||||||
use super::convert::{ConversationMessage, MessageContent, MessageRole, ToolDefinition};
|
use super::convert::{ConversationMessage, MessageContent, MessageRole, ToolDefinition};
|
||||||
use crate::settings::ai::BedrockAuthMethod;
|
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 {
|
fn make_user_query_message(id: &str, task_id: &str, query: &str) -> api::Message {
|
||||||
api::Message {
|
api::Message {
|
||||||
@@ -24,6 +24,7 @@ fn make_user_query_message(id: &str, task_id: &str, query: &str) -> api::Message
|
|||||||
mode: None,
|
mode: None,
|
||||||
intended_agent: 0,
|
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(),
|
output: output.into(),
|
||||||
exit_code,
|
exit_code,
|
||||||
command_id: String::new(),
|
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_bundled_skills: false,
|
||||||
supports_research_agent: false,
|
supports_research_agent: false,
|
||||||
supports_orchestration_v2: false,
|
supports_orchestration_v2: false,
|
||||||
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,6 +267,7 @@ fn get_test_config() -> Option<BedrockClientConfig> {
|
|||||||
region,
|
region,
|
||||||
access_key_id: String::new(),
|
access_key_id: String::new(),
|
||||||
secret_access_key: String::new(),
|
secret_access_key: String::new(),
|
||||||
|
session_token: None,
|
||||||
cross_region_inference: false,
|
cross_region_inference: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -691,7 +699,7 @@ impl AgentSimulation {
|
|||||||
match name {
|
match name {
|
||||||
"run_shell_command" => {
|
"run_shell_command" => {
|
||||||
let command = input["command"].as_str().unwrap_or("echo 'no 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("-c")
|
||||||
.arg(command)
|
.arg(command)
|
||||||
.current_dir(&self.project_path)
|
.current_dir(&self.project_path)
|
||||||
@@ -759,7 +767,7 @@ impl AgentSimulation {
|
|||||||
.unwrap_or(self.project_path.to_str().unwrap_or("."));
|
.unwrap_or(self.project_path.to_str().unwrap_or("."));
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
for query in queries {
|
for query in queries {
|
||||||
let output = std::process::Command::new("grep")
|
let output = command::blocking::Command::new("grep")
|
||||||
.args(["-rn", query, path])
|
.args(["-rn", query, path])
|
||||||
.output();
|
.output();
|
||||||
if let Ok(out) = 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 tool_use_id = format!("tool_{}", total_turns);
|
||||||
let (result, is_error) = match tool.name.as_str() {
|
let (result, is_error) = match tool.name.as_str() {
|
||||||
"run_shell_command" => {
|
"run_shell_command" => {
|
||||||
let ls_output = std::process::Command::new("ls")
|
let ls_output = command::blocking::Command::new("ls")
|
||||||
.arg("-la")
|
.arg("-la")
|
||||||
.current_dir(&project_path)
|
.current_dir(&project_path)
|
||||||
.output()
|
.output()
|
||||||
@@ -1075,7 +1083,7 @@ async fn test_agent_multi_turn_tool_use_produces_output() {
|
|||||||
// 2. No partial reasoning fragments leak to the UI
|
// 2. No partial reasoning fragments leak to the UI
|
||||||
// 3. The stream protocol is correct (Init, CreateTask, content, Finished)
|
// 3. The stream protocol is correct (Init, CreateTask, content, Finished)
|
||||||
assert!(
|
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"
|
"Agent should either produce text or make multiple tool calls to explore"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1160,9 +1168,7 @@ async fn test_reasoning_model_produces_substantial_output() {
|
|||||||
while let Some(event_result) = stream.next().await {
|
while let Some(event_result) = stream.next().await {
|
||||||
event_count += 1;
|
event_count += 1;
|
||||||
let event = event_result.expect("event should be Ok");
|
let event = event_result.expect("event should be Ok");
|
||||||
if let Some(event_type) = &event.r#type {
|
if let Some(api::response_event::Type::ClientActions(actions)) = &event.r#type {
|
||||||
match event_type {
|
|
||||||
api::response_event::Type::ClientActions(actions) => {
|
|
||||||
for action in &actions.actions {
|
for action in &actions.actions {
|
||||||
if let Some(action_type) = &action.action {
|
if let Some(action_type) = &action.action {
|
||||||
match action_type {
|
match action_type {
|
||||||
@@ -1192,9 +1198,6 @@ async fn test_reasoning_model_produces_substantial_output() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("[E2E] Events received: {event_count}");
|
println!("[E2E] Events received: {event_count}");
|
||||||
@@ -1610,7 +1613,7 @@ async fn test_slash_create_new_project() {
|
|||||||
|
|
||||||
if !events.is_empty() {
|
if !events.is_empty() {
|
||||||
assert!(
|
assert!(
|
||||||
text.len() > 0
|
!text.is_empty()
|
||||||
|| events
|
|| events
|
||||||
.iter()
|
.iter()
|
||||||
.any(|e| matches!(e.event_type, StreamEventType::ToolCallMessage { .. })),
|
.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");
|
assert_valid_stream(&events, "slash_auto_code_diff");
|
||||||
|
|
||||||
if !events.is_empty() {
|
if !events.is_empty() {
|
||||||
let has_action = text.len() > 0
|
let has_action = !text.is_empty()
|
||||||
|| events
|
|| events
|
||||||
.iter()
|
.iter()
|
||||||
.any(|e| matches!(e.event_type, StreamEventType::ToolCallMessage { .. }));
|
.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");
|
assert_valid_stream(&events, "slash_query_with_canned_response");
|
||||||
|
|
||||||
if !events.is_empty() {
|
if !events.is_empty() {
|
||||||
let has_output = text.len() > 0
|
let has_output = !text.is_empty()
|
||||||
|| events
|
|| events
|
||||||
.iter()
|
.iter()
|
||||||
.any(|e| matches!(e.event_type, StreamEventType::ToolCallMessage { .. }));
|
.any(|e| matches!(e.event_type, StreamEventType::ToolCallMessage { .. }));
|
||||||
|
|||||||
@@ -144,7 +144,6 @@ fn parse_claude_code_model_map(
|
|||||||
model_id: arn,
|
model_id: arn,
|
||||||
display_name,
|
display_name,
|
||||||
vision_supported: true,
|
vision_supported: true,
|
||||||
context_size: 200_000,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ fn get_test_config() -> Option<BedrockClientConfig> {
|
|||||||
region,
|
region,
|
||||||
access_key_id: String::new(),
|
access_key_id: String::new(),
|
||||||
secret_access_key: String::new(),
|
secret_access_key: String::new(),
|
||||||
|
session_token: None,
|
||||||
cross_region_inference: false,
|
cross_region_inference: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -81,6 +82,7 @@ async fn collect_stream_output(
|
|||||||
while let Some(event) = stream.next().await {
|
while let Some(event) = stream.next().await {
|
||||||
let event = event.expect("stream event should be Ok");
|
let event = event.expect("stream event should be Ok");
|
||||||
if let Some(event_type) = event.r#type {
|
if let Some(event_type) = event.r#type {
|
||||||
|
use warp_multi_agent_api::message::Message;
|
||||||
use warp_multi_agent_api::response_event::Type;
|
use warp_multi_agent_api::response_event::Type;
|
||||||
match event_type {
|
match event_type {
|
||||||
Type::ClientActions(actions) => {
|
Type::ClientActions(actions) => {
|
||||||
@@ -90,26 +92,18 @@ async fn collect_stream_output(
|
|||||||
match action_type {
|
match action_type {
|
||||||
Action::AddMessagesToTask(add) => {
|
Action::AddMessagesToTask(add) => {
|
||||||
for msg in add.messages {
|
for msg in add.messages {
|
||||||
if let Some(msg_content) = msg.message {
|
if let Some(Message::AgentOutput(output)) = msg.message {
|
||||||
use warp_multi_agent_api::message::Message;
|
|
||||||
match msg_content {
|
|
||||||
Message::AgentOutput(output) => {
|
|
||||||
text.push_str(&output.text);
|
text.push_str(&output.text);
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::AppendToMessageContent(append) => {
|
Action::AppendToMessageContent(append) => {
|
||||||
if let Some(msg) = append.message {
|
if let Some(Message::AgentOutput(output)) =
|
||||||
if let Some(msg_content) = msg.message {
|
append.message.and_then(|m| m.message)
|
||||||
if let Message::AgentOutput(output) = msg_content {
|
{
|
||||||
text.push_str(&output.text);
|
text.push_str(&output.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -553,9 +547,10 @@ async fn test_arn_based_model() {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let arn = std::env::var("BEDROCK_TEST_ARN").unwrap_or_else(|_| {
|
let Some(arn) = std::env::var("BEDROCK_TEST_ARN").ok() else {
|
||||||
"arn:aws:bedrock:us-east-1:156729649053:application-inference-profile/1tim45pgo320".into()
|
eprintln!("Skipping: BEDROCK_TEST_ARN not set");
|
||||||
});
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let client = BedrockClient::from_config(config)
|
let client = BedrockClient::from_config(config)
|
||||||
.await
|
.await
|
||||||
@@ -696,3 +691,100 @@ async fn test_all_tools_visible_to_model() {
|
|||||||
tools.len()
|
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 super::external_config::ExternalBedrockConfig;
|
||||||
|
use crate::settings::ai::BedrockModelConfig;
|
||||||
|
|
||||||
pub struct DefaultModel {
|
pub struct DefaultModel {
|
||||||
pub model_id: &'static str,
|
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(),
|
model_id: m.model_id.to_string(),
|
||||||
display_name: m.display_name.to_string(),
|
display_name: m.display_name.to_string(),
|
||||||
vision_supported: m.vision_supported,
|
vision_supported: m.vision_supported,
|
||||||
context_size: m.context_size,
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
for default in defaults {
|
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(),
|
model_id: m.model_id.to_string(),
|
||||||
display_name: m.display_name.to_string(),
|
display_name: m.display_name.to_string(),
|
||||||
vision_supported: m.vision_supported,
|
vision_supported: m.vision_supported,
|
||||||
context_size: m.context_size,
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ fn test_get_effective_models_custom_overrides() {
|
|||||||
model_id: "custom.model-v1:0".to_string(),
|
model_id: "custom.model-v1:0".to_string(),
|
||||||
display_name: "Custom Model".to_string(),
|
display_name: "Custom Model".to_string(),
|
||||||
vision_supported: false,
|
vision_supported: false,
|
||||||
context_size: 200_000,
|
|
||||||
}];
|
}];
|
||||||
let models = get_effective_models(&custom);
|
let models = get_effective_models(&custom);
|
||||||
assert_eq!(models.len(), 1);
|
assert_eq!(models.len(), 1);
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use warp_multi_agent_api as api;
|
use warp_multi_agent_api as api;
|
||||||
|
|
||||||
use super::convert::{
|
use super::convert::{
|
||||||
@@ -357,6 +361,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::ToolCallResult(
|
message: Some(api::message::Message::ToolCallResult(
|
||||||
api::message::ToolCallResult {
|
api::message::ToolCallResult {
|
||||||
tool_call_id: result.tool_call_id.clone(),
|
tool_call_id: result.tool_call_id.clone(),
|
||||||
@@ -382,6 +387,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::UserQuery(
|
message: Some(api::message::Message::UserQuery(
|
||||||
api::message::UserQuery {
|
api::message::UserQuery {
|
||||||
query: query.query.clone(),
|
query: query.query.clone(),
|
||||||
@@ -422,6 +428,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::UserQuery(
|
message: Some(api::message::Message::UserQuery(
|
||||||
api::message::UserQuery {
|
api::message::UserQuery {
|
||||||
query: query_text,
|
query: query_text,
|
||||||
@@ -445,6 +452,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
||||||
query: query.query.clone(),
|
query: query.query.clone(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -462,6 +470,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::ToolCallResult(
|
message: Some(api::message::Message::ToolCallResult(
|
||||||
api::message::ToolCallResult {
|
api::message::ToolCallResult {
|
||||||
tool_call_id: result.tool_call_id.clone(),
|
tool_call_id: result.tool_call_id.clone(),
|
||||||
@@ -492,6 +501,7 @@ fn extract_input_messages(request: &api::Request) -> Vec<api::Message> {
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
||||||
query: prompt,
|
query: prompt,
|
||||||
..Default::default()
|
..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.
|
/// 4. Removes trailing assistant tool_use messages that have no following user message.
|
||||||
/// 5. Ensures strict user/assistant role alternation.
|
/// 5. Ensures strict user/assistant role alternation.
|
||||||
fn ensure_tool_results_paired(messages: &mut Vec<ConversationMessage>) {
|
fn ensure_tool_results_paired(messages: &mut Vec<ConversationMessage>) {
|
||||||
|
|
||||||
// Collect all tool_result IDs that exist anywhere in the conversation.
|
// Collect all tool_result IDs that exist anywhere in the conversation.
|
||||||
let mut all_result_ids = HashSet::new();
|
let mut all_result_ids = HashSet::new();
|
||||||
for msg in messages.iter() {
|
for msg in messages.iter() {
|
||||||
@@ -1035,7 +1044,7 @@ pub fn extract_tools(request: &api::Request) -> Vec<ToolDefinition> {
|
|||||||
let input_schema = tool
|
let input_schema = tool
|
||||||
.input_schema
|
.input_schema
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| prost_struct_to_json(s))
|
.map(prost_struct_to_json)
|
||||||
.unwrap_or_else(|| serde_json::json!({"type": "object", "properties": {}}));
|
.unwrap_or_else(|| serde_json::json!({"type": "object", "properties": {}}));
|
||||||
tools.push(ToolDefinition {
|
tools.push(ToolDefinition {
|
||||||
name,
|
name,
|
||||||
@@ -1057,7 +1066,7 @@ pub fn extract_tools(request: &api::Request) -> Vec<ToolDefinition> {
|
|||||||
let input_schema = tool
|
let input_schema = tool
|
||||||
.input_schema
|
.input_schema
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| prost_struct_to_json(s))
|
.map(prost_struct_to_json)
|
||||||
.unwrap_or_else(|| serde_json::json!({"type": "object", "properties": {}}));
|
.unwrap_or_else(|| serde_json::json!({"type": "object", "properties": {}}));
|
||||||
tools.push(ToolDefinition {
|
tools.push(ToolDefinition {
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use aws_sdk_bedrockruntime::operation::converse_stream::ConverseStreamOutput;
|
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::response_event::stream_finished;
|
||||||
use warp_multi_agent_api::{self as api, ClientAction, ResponseEvent};
|
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::convert::{ContentPart, ConversationMessage, MessageContent, MessageRole};
|
||||||
use super::diagnostic::BedrockDiagnosticLogger;
|
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 {
|
fn json_to_prost_struct(value: &serde_json::Value) -> prost_types::Struct {
|
||||||
let fields = match value.as_object() {
|
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(
|
pub fn bedrock_stream_to_response_events(
|
||||||
mut output: ConverseStreamOutput,
|
mut output: ConverseStreamOutput,
|
||||||
task_id: String,
|
task_id: String,
|
||||||
@@ -129,9 +131,7 @@ pub fn bedrock_stream_to_response_events(
|
|||||||
}
|
}
|
||||||
StreamEvent::ContentBlockStart(block_start) => {
|
StreamEvent::ContentBlockStart(block_start) => {
|
||||||
log::debug!("[bedrock] Event #{event_count}: ContentBlockStart");
|
log::debug!("[bedrock] Event #{event_count}: ContentBlockStart");
|
||||||
if let Some(start) = block_start.start() {
|
if let Some(ContentBlockStart::ToolUse(tool_start)) = block_start.start() {
|
||||||
match start {
|
|
||||||
ContentBlockStart::ToolUse(tool_start) => {
|
|
||||||
_has_tool_calls = true;
|
_has_tool_calls = true;
|
||||||
if !buffered_text.is_empty() {
|
if !buffered_text.is_empty() {
|
||||||
let msg_id = current_text_message_id
|
let msg_id = current_text_message_id
|
||||||
@@ -162,9 +162,6 @@ pub fn bedrock_stream_to_response_events(
|
|||||||
current_tool_name = tool_start.name().to_string();
|
current_tool_name = tool_start.name().to_string();
|
||||||
current_tool_input_json.clear();
|
current_tool_input_json.clear();
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
StreamEvent::ContentBlockDelta(delta) => {
|
StreamEvent::ContentBlockDelta(delta) => {
|
||||||
log::trace!("[bedrock] Event #{event_count}: ContentBlockDelta");
|
log::trace!("[bedrock] Event #{event_count}: ContentBlockDelta");
|
||||||
@@ -187,7 +184,7 @@ pub fn bedrock_stream_to_response_events(
|
|||||||
// AddMessagesToTask carries enough content for
|
// AddMessagesToTask carries enough content for
|
||||||
// the exchange to be fully registered before
|
// the exchange to be fully registered before
|
||||||
// subsequent AppendToMessageContent events arrive.
|
// subsequent AppendToMessageContent events arrive.
|
||||||
if buffered_text.len() >= 1 {
|
if !buffered_text.is_empty() {
|
||||||
let msg_id = Uuid::new_v4().to_string();
|
let msg_id = Uuid::new_v4().to_string();
|
||||||
current_text_message_id = Some(msg_id.clone());
|
current_text_message_id = Some(msg_id.clone());
|
||||||
text_flushed = true;
|
text_flushed = true;
|
||||||
@@ -201,11 +198,9 @@ pub fn bedrock_stream_to_response_events(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ContentBlockDelta::ReasoningContent(reasoning) => {
|
ContentBlockDelta::ReasoningContent(ReasoningContentBlockDelta::Text(text)) => {
|
||||||
if let ReasoningContentBlockDelta::Text(text) = reasoning {
|
|
||||||
log::trace!("[bedrock] Reasoning delta ({} chars) - not displayed to user", text.len());
|
log::trace!("[bedrock] Reasoning delta ({} chars) - not displayed to user", text.len());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ContentBlockDelta::ToolUse(tool_delta) => {
|
ContentBlockDelta::ToolUse(tool_delta) => {
|
||||||
current_tool_input_json.push_str(tool_delta.input());
|
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,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
message: Some(api::message::Message::UserQuery(api::message::UserQuery {
|
||||||
query: query_text.to_string(),
|
query: query_text.to_string(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -682,10 +678,14 @@ pub fn build_stream_finished(
|
|||||||
context_window_usage: context_usage,
|
context_window_usage: context_usage,
|
||||||
summarized: is_summarization,
|
summarized: is_summarization,
|
||||||
credits_spent: 0.0,
|
credits_spent: 0.0,
|
||||||
|
platform_credits_spent: 0.0,
|
||||||
|
total_input_tokens: input_tokens as u32,
|
||||||
token_usage: vec![],
|
token_usage: vec![],
|
||||||
tool_usage_metadata: None,
|
tool_usage_metadata: None,
|
||||||
warp_token_usage: std::collections::HashMap::new(),
|
warp_token_usage: std::collections::HashMap::new(),
|
||||||
byok_token_usage,
|
byok_token_usage,
|
||||||
|
custom_endpoint_token_usage: std::collections::HashMap::new(),
|
||||||
|
context_window_segments: vec![],
|
||||||
});
|
});
|
||||||
|
|
||||||
ResponseEvent {
|
ResponseEvent {
|
||||||
@@ -757,6 +757,7 @@ fn build_add_agent_output_message(
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::AgentOutput(
|
message: Some(api::message::Message::AgentOutput(
|
||||||
api::message::AgentOutput {
|
api::message::AgentOutput {
|
||||||
text: initial_text.to_string(),
|
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,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::AgentOutput(
|
message: Some(api::message::Message::AgentOutput(
|
||||||
api::message::AgentOutput {
|
api::message::AgentOutput {
|
||||||
text: text_delta.to_string(),
|
text: text_delta.to_string(),
|
||||||
@@ -1227,6 +1229,7 @@ pub fn build_tool_call_message(
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::ToolCall(api::message::ToolCall {
|
message: Some(api::message::Message::ToolCall(api::message::ToolCall {
|
||||||
tool_call_id: effective_tool_call_id,
|
tool_call_id: effective_tool_call_id,
|
||||||
tool: Some(tool_variant),
|
tool: Some(tool_variant),
|
||||||
@@ -1243,6 +1246,7 @@ pub fn build_tool_call_message(
|
|||||||
timestamp: None,
|
timestamp: None,
|
||||||
server_message_data: String::new(),
|
server_message_data: String::new(),
|
||||||
citations: vec![],
|
citations: vec![],
|
||||||
|
fetched_memories: vec![],
|
||||||
message: Some(api::message::Message::AgentOutput(
|
message: Some(api::message::Message::AgentOutput(
|
||||||
api::message::AgentOutput {
|
api::message::AgentOutput {
|
||||||
text: format!(
|
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::*;
|
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::convert::CachingConfig;
|
||||||
use crate::ai::bedrock::external_config::ExternalBedrockConfig;
|
use crate::ai::bedrock::external_config::ExternalBedrockConfig;
|
||||||
use crate::appearance::Appearance;
|
use crate::appearance::Appearance;
|
||||||
use crate::ui_components::blended_colors;
|
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 {
|
pub struct SettingsView {
|
||||||
external_config: ExternalBedrockConfig,
|
external_config: ExternalBedrockConfig,
|
||||||
|
|||||||
@@ -9,16 +9,5 @@ pub fn multiply(a: i32, b: i32) -> i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
#[path = "lib_tests.rs"]
|
||||||
use super::*;
|
mod tests;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_add() {
|
|
||||||
assert_eq!(add(2, 3), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_multiply() {
|
|
||||||
assert_eq!(multiply(3, 4), 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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 std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use warp_multi_agent_api as api;
|
use warp_multi_agent_api as api;
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ pub use execute::{
|
|||||||
StartAgentExecutorEvent, StartAgentRequest, StartAgentRequestId,
|
StartAgentExecutorEvent, StartAgentRequest, StartAgentRequestId,
|
||||||
};
|
};
|
||||||
use futures::future::{join_all, BoxFuture};
|
use futures::future::{join_all, BoxFuture};
|
||||||
|
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parking_lot::FairMutex;
|
use parking_lot::FairMutex;
|
||||||
use preprocess::{PendingPreprocessedActions, PreprocessId};
|
use preprocess::{PendingPreprocessedActions, PreprocessId};
|
||||||
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
|
||||||
|
|
||||||
use self::execute::ask_user_question::AskUserQuestionExecutor;
|
use self::execute::ask_user_question::AskUserQuestionExecutor;
|
||||||
use self::execute::search_codebase::SearchCodebaseExecutor;
|
use self::execute::search_codebase::SearchCodebaseExecutor;
|
||||||
|
|||||||
@@ -40,9 +40,20 @@ use futures::future::BoxFuture;
|
|||||||
#[cfg(feature = "local_fs")]
|
#[cfg(feature = "local_fs")]
|
||||||
use futures::AsyncReadExt;
|
use futures::AsyncReadExt;
|
||||||
use futures::FutureExt;
|
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;
|
use grep::GrepExecutor;
|
||||||
#[cfg(feature = "local_fs")]
|
#[cfg(feature = "local_fs")]
|
||||||
use mime_guess::from_path;
|
use mime_guess::from_path;
|
||||||
|
use notebooks::NotebookExecutor;
|
||||||
use parking_lot::FairMutex;
|
use parking_lot::FairMutex;
|
||||||
use read_documents::ReadDocumentsExecutor;
|
use read_documents::ReadDocumentsExecutor;
|
||||||
pub(super) use read_files::ReadFilesExecutor;
|
pub(super) use read_files::ReadFilesExecutor;
|
||||||
@@ -69,16 +80,6 @@ pub use suggest_prompt::PromptSuggestionExecutor;
|
|||||||
use upload_artifact::UploadArtifactExecutor;
|
use upload_artifact::UploadArtifactExecutor;
|
||||||
use use_computer::UseComputerExecutor;
|
use use_computer::UseComputerExecutor;
|
||||||
use wait_for_events::WaitForEventsExecutor;
|
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 self::search_codebase::SearchCodebaseExecutor;
|
||||||
use crate::ai::agent::conversation::AIConversationId;
|
use crate::ai::agent::conversation::AIConversationId;
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ use galaxyui::{Entity, EntityId, ModelContext, SingletonEntity};
|
|||||||
|
|
||||||
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
|
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
|
||||||
use crate::ai::agent::{AIAgentActionResultType, AIAgentActionType};
|
use crate::ai::agent::{AIAgentActionResultType, AIAgentActionType};
|
||||||
|
use crate::ai::blocklist::orchestration_events::OrchestrationEventService;
|
||||||
use crate::ai::blocklist::BlocklistAIPermissions;
|
use crate::ai::blocklist::BlocklistAIPermissions;
|
||||||
|
use crate::BlocklistAIHistoryModel;
|
||||||
|
|
||||||
pub enum AskUserQuestionDecision {
|
pub enum AskUserQuestionDecision {
|
||||||
Completed(Vec<AskUserQuestionAnswerItem>),
|
Completed(Vec<AskUserQuestionAnswerItem>),
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ fn build_action(action_id: &str) -> AIAgentAction {
|
|||||||
},
|
},
|
||||||
task_id: TaskId::new(format!("task-{action_id}")),
|
task_id: TaskId::new(format!("task-{action_id}")),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
use itertools::Itertools;
|
|
||||||
#[cfg(not(target_family = "wasm"))]
|
|
||||||
use galaxyui::SingletonEntity;
|
use galaxyui::SingletonEntity;
|
||||||
use galaxyui::{Entity, EntityId, ModelContext, ModelHandle};
|
use galaxyui::{Entity, EntityId, ModelContext, ModelHandle};
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
use super::get_server_output_id;
|
use super::get_server_output_id;
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use galaxy_core::features::FeatureFlag;
|
||||||
use galaxyui::r#async::FutureExt as AsyncFutureExt;
|
use galaxyui::r#async::FutureExt as AsyncFutureExt;
|
||||||
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use galaxy_core::features::FeatureFlag;
|
|
||||||
|
|
||||||
use crate::ai::agent::conversation::AIConversationId;
|
use crate::ai::agent::conversation::AIConversationId;
|
||||||
use crate::ai::agent::{
|
use crate::ai::agent::{
|
||||||
|
|||||||
@@ -3,25 +3,22 @@
|
|||||||
//! These tools interact with Galaxy Drive CloudNotebook objects directly,
|
//! These tools interact with Galaxy Drive CloudNotebook objects directly,
|
||||||
//! as opposed to the plan tools which work through AIDocumentModel.
|
//! 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 galaxyui::{Entity, ModelContext, SingletonEntity};
|
||||||
|
|
||||||
use crate::{
|
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
|
||||||
ai::{
|
use crate::ai::agent::{
|
||||||
agent::{
|
|
||||||
AIAgentAction, AIAgentActionType, CreateDocumentsRequest, CreateDocumentsResult,
|
AIAgentAction, AIAgentActionType, CreateDocumentsRequest, CreateDocumentsResult,
|
||||||
DocumentContext, EditDocumentsRequest, EditDocumentsResult, ReadDocumentsRequest,
|
DocumentContext, EditDocumentsRequest, EditDocumentsResult, ReadDocumentsRequest,
|
||||||
ReadDocumentsResult,
|
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 crate::ai::document::ai_document_model::AIDocumentVersion;
|
||||||
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
|
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;
|
pub struct NotebookExecutor;
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ fn read_action(document_id: AIDocumentId) -> AIAgentAction {
|
|||||||
action: AIAgentActionType::ReadDocuments(ReadDocumentsRequest {
|
action: AIAgentActionType::ReadDocuments(ReadDocumentsRequest {
|
||||||
document_ids: vec![document_id],
|
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 ai::skills::{parse_skill, ParsedSkill, SkillProvider, SkillReference, SkillScope};
|
||||||
use async_channel::unbounded;
|
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::features::FeatureFlag;
|
||||||
use galaxy_core::HostId;
|
use galaxy_core::HostId;
|
||||||
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
|
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
|
||||||
use galaxy_util::remote_path::RemotePath;
|
use galaxy_util::remote_path::RemotePath;
|
||||||
use galaxy_util::standardized_path::StandardizedPath;
|
use galaxy_util::standardized_path::StandardizedPath;
|
||||||
use galaxyui::{App, ModelHandle};
|
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 watcher::HomeDirectoryWatcher;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -36,7 +36,7 @@ fn initialize_app(app: &mut App) {
|
|||||||
app.add_singleton_model(|_| DetectedRepositories::default());
|
app.add_singleton_model(|_| DetectedRepositories::default());
|
||||||
app.add_singleton_model(RepoMetadataModel::new);
|
app.add_singleton_model(RepoMetadataModel::new);
|
||||||
app.add_singleton_model(HomeDirectoryWatcher::new_for_test);
|
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);
|
app.add_singleton_model(SkillManager::new);
|
||||||
}
|
}
|
||||||
fn add_test_read_skill_executor(app: &mut App) -> ModelHandle<ReadSkillExecutor> {
|
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()),
|
task_id: TaskId::new("test-task-id".to_string()),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let input = ExecuteActionInput {
|
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()),
|
task_id: TaskId::new("test-task-id".to_string()),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
};
|
};
|
||||||
let input = ExecuteActionInput {
|
let input = ExecuteActionInput {
|
||||||
action: &action,
|
action: &action,
|
||||||
@@ -259,6 +261,7 @@ fn remote_session_reads_remote_bundled_skill_catalog() {
|
|||||||
}),
|
}),
|
||||||
task_id: TaskId::new("test-task-id".to_string()),
|
task_id: TaskId::new("test-task-id".to_string()),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
};
|
};
|
||||||
let input = ExecuteActionInput {
|
let input = ExecuteActionInput {
|
||||||
action: &action,
|
action: &action,
|
||||||
@@ -307,6 +310,7 @@ fn test_read_skill_executor_reads_enabled_bundled_skill() {
|
|||||||
}),
|
}),
|
||||||
task_id: TaskId::new("test-task-id".to_string()),
|
task_id: TaskId::new("test-task-id".to_string()),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let input = ExecuteActionInput {
|
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}")),
|
task_id: TaskId::new(format!("test-task-id-{skill_id}")),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let input = ExecuteActionInput {
|
let input = ExecuteActionInput {
|
||||||
@@ -386,6 +391,7 @@ fn test_read_skill_executor_file_not_found() {
|
|||||||
}),
|
}),
|
||||||
task_id: TaskId::new("test-task-id".to_string()),
|
task_id: TaskId::new("test-task-id".to_string()),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let input = ExecuteActionInput {
|
let input = ExecuteActionInput {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ pub(crate) use diff_application::{apply_edits, FileReadResult};
|
|||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use galaxy_core::send_telemetry_from_ctx;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
pub(crate) use telemetry::MalformedFinalLineProxyEvent;
|
pub(crate) use telemetry::MalformedFinalLineProxyEvent;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@@ -21,7 +22,6 @@ pub use telemetry::{
|
|||||||
RequestFileEditsTelemetryEvent,
|
RequestFileEditsTelemetryEvent,
|
||||||
};
|
};
|
||||||
use vec1::{vec1, Vec1};
|
use vec1::{vec1, Vec1};
|
||||||
use galaxy_core::send_telemetry_from_ctx;
|
|
||||||
use warp_util::file::FileSaveError;
|
use warp_util::file::FileSaveError;
|
||||||
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity as _, ViewHandle};
|
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity as _, ViewHandle};
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ use ai::agent::orchestration_config::OrchestrationConfig;
|
|||||||
use ai::skills::SkillReference;
|
use ai::skills::SkillReference;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use galaxy_core::execution_mode::AppExecutionMode;
|
||||||
use settings::Setting;
|
use settings::Setting;
|
||||||
use warp_cli::agent::Harness;
|
use warp_cli::agent::Harness;
|
||||||
use galaxy_core::execution_mode::AppExecutionMode;
|
|
||||||
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
use warpui::{Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
||||||
|
|
||||||
use super::start_agent::{StartAgentExecutor, StartAgentOutcome};
|
use super::start_agent::{StartAgentExecutor, StartAgentOutcome};
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use ai::agent::action::{RunAgentsAgentRunConfig, RunAgentsExecutionMode, RunAgen
|
|||||||
use ai::agent::orchestration_config::{
|
use ai::agent::orchestration_config::{
|
||||||
OrchestrationConfig, OrchestrationConfigStatus, OrchestrationExecutionMode,
|
OrchestrationConfig, OrchestrationConfigStatus, OrchestrationExecutionMode,
|
||||||
};
|
};
|
||||||
use settings::Setting;
|
|
||||||
use galaxy_core::execution_mode::ExecutionMode;
|
use galaxy_core::execution_mode::ExecutionMode;
|
||||||
use galaxy_core::features::FeatureFlag;
|
use galaxy_core::features::FeatureFlag;
|
||||||
|
use settings::Setting;
|
||||||
use warpui::{App, Entity, EntityId, ModelHandle};
|
use warpui::{App, Entity, EntityId, ModelHandle};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -239,6 +239,7 @@ fn remote_run_agents_action(harness_type: &str) -> AIAgentAction {
|
|||||||
plan_id: String::new(),
|
plan_id: String::new(),
|
||||||
harness_auth_secret_name: None,
|
harness_auth_secret_name: None,
|
||||||
}),
|
}),
|
||||||
|
tool_name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|||||||
@@ -249,6 +249,8 @@ impl ShellCommandExecutor {
|
|||||||
block_id: model.block_list().active_block().id().clone(),
|
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(),
|
output: "Error: Cannot execute command because another command is still running in the terminal.".to_string(),
|
||||||
exit_code: ExitCode::from(1),
|
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::future::BoxFuture;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use shell_words::split as split_shell_words;
|
|
||||||
use galaxy_cli::agent::Harness;
|
use galaxy_cli::agent::Harness;
|
||||||
use galaxyui::{Entity, ModelContext, ModelHandle, SingletonEntity};
|
use galaxyui::{Entity, ModelContext, ModelHandle, SingletonEntity};
|
||||||
|
use shell_words::split as split_shell_words;
|
||||||
|
|
||||||
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
|
use super::{ActionExecution, AnyActionExecution, ExecuteActionInput, PreprocessActionInput};
|
||||||
use crate::ai::agent::conversation::{AIConversationId, ConversationStatus};
|
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
|
// 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.
|
// 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 (sender, receiver) = async_channel::bounded(1);
|
||||||
let request_id = self.next_request_id();
|
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()),
|
task_id: TaskId::new("start-agent-task".to_string()),
|
||||||
requires_result: false,
|
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()),
|
task_id: TaskId::new("upload-artifact-task".to_string()),
|
||||||
requires_result: false,
|
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()),
|
task_id: TaskId::new("wait-task".to_string()),
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let execution = executor.update(&mut app, |executor, ctx| {
|
let execution = executor.update(&mut app, |executor, ctx| {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ fn create_test_action(id: AIAgentActionId) -> AIAgentAction {
|
|||||||
citations: vec![],
|
citations: vec![],
|
||||||
},
|
},
|
||||||
requires_result: false,
|
requires_result: false,
|
||||||
|
tool_name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
//! Uses the shared [`ChipConfigurator`] with `LeftRightZones` layout to let users
|
//! Uses the shared [`ChipConfigurator`] with `LeftRightZones` layout to let users
|
||||||
//! drag/drop chips between left, right, and unused banks.
|
//! drag/drop chips between left, right, and unused banks.
|
||||||
|
|
||||||
use settings::Setting as _;
|
|
||||||
use galaxyui::keymap::FixedBinding;
|
use galaxyui::keymap::FixedBinding;
|
||||||
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
||||||
|
use settings::Setting as _;
|
||||||
|
|
||||||
use super::toolbar_item::AgentToolbarItemKind;
|
use super::toolbar_item::AgentToolbarItemKind;
|
||||||
use crate::appearance::AppearanceEvent;
|
use crate::appearance::AppearanceEvent;
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use std::sync::Arc;
|
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::send_telemetry_from_ctx;
|
||||||
use galaxy_core::ui::color::blend::Blend;
|
use galaxy_core::ui::color::blend::Blend;
|
||||||
use galaxy_core::ui::theme::Fill;
|
use galaxy_core::ui::theme::Fill;
|
||||||
@@ -14,6 +11,9 @@ use galaxyui::{
|
|||||||
AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
||||||
ViewHandle,
|
ViewHandle,
|
||||||
};
|
};
|
||||||
|
use pathfinder_color::ColorU;
|
||||||
|
use pathfinder_geometry::vector::vec2f;
|
||||||
|
use settings::Setting;
|
||||||
|
|
||||||
use super::{AgentInputButtonTheme, AmbientAgentViewModel};
|
use super::{AgentInputButtonTheme, AmbientAgentViewModel};
|
||||||
use crate::ai::ambient_agents::telemetry::CloudAgentTelemetryEvent;
|
use crate::ai::ambient_agents::telemetry::CloudAgentTelemetryEvent;
|
||||||
|
|||||||
@@ -13,17 +13,6 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use ai::document::{AIDocumentId, AIDocumentVersion};
|
use ai::document::{AIDocumentId, AIDocumentVersion};
|
||||||
use chrono::{DateTime, Local};
|
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_cli::agent::Harness;
|
||||||
use galaxy_core::context_flag::ContextFlag;
|
use galaxy_core::context_flag::ContextFlag;
|
||||||
use galaxy_core::report_if_error;
|
use galaxy_core::report_if_error;
|
||||||
@@ -43,6 +32,17 @@ use galaxyui::{
|
|||||||
AppContext, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
AppContext, Entity, EntityId, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
||||||
ViewHandle,
|
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")]
|
#[cfg(feature = "local_fs")]
|
||||||
pub(crate) use self::environment_selector::sort_environments_by_recency;
|
pub(crate) use self::environment_selector::sort_environments_by_recency;
|
||||||
@@ -233,6 +233,9 @@ pub struct AgentInputFooter {
|
|||||||
// `Workspace::start_local_to_cloud_handoff`.
|
// `Workspace::start_local_to_cloud_handoff`.
|
||||||
handoff_to_cloud_button: ViewHandle<ActionButton>,
|
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).
|
// CLI agent voice input state (self-contained, bypasses editor voice flow).
|
||||||
#[cfg(feature = "voice_input")]
|
#[cfg(feature = "voice_input")]
|
||||||
cli_voice_input_state: CLIVoiceInputState,
|
cli_voice_input_state: CLIVoiceInputState,
|
||||||
@@ -579,7 +582,7 @@ impl AgentInputFooter {
|
|||||||
let start_remote_control_button = ctx.add_typed_action_view(|_ctx| {
|
let start_remote_control_button = ctx.add_typed_action_view(|_ctx| {
|
||||||
ActionButton::new("/remote-control", RemoteControlButtonTheme)
|
ActionButton::new("/remote-control", RemoteControlButtonTheme)
|
||||||
.with_icon(Icon::Phone01)
|
.with_icon(Icon::Phone01)
|
||||||
.with_tooltip(START_REMOTE_CONTROL_TOOLTIP)
|
.with_tooltip("Start remote control")
|
||||||
.with_size(cli_button_size)
|
.with_size(cli_button_size)
|
||||||
.with_tooltip_alignment(TooltipAlignment::Left)
|
.with_tooltip_alignment(TooltipAlignment::Left)
|
||||||
.on_click(|ctx| {
|
.on_click(|ctx| {
|
||||||
@@ -845,6 +848,8 @@ impl AgentInputFooter {
|
|||||||
display_chip_config,
|
display_chip_config,
|
||||||
fast_forward_button,
|
fast_forward_button,
|
||||||
handoff_to_cloud_button,
|
handoff_to_cloud_button,
|
||||||
|
start_remote_control_button,
|
||||||
|
stop_remote_control_button,
|
||||||
#[cfg(feature = "voice_input")]
|
#[cfg(feature = "voice_input")]
|
||||||
cli_voice_input_state: CLIVoiceInputState::default(),
|
cli_voice_input_state: CLIVoiceInputState::default(),
|
||||||
#[cfg(feature = "voice_input")]
|
#[cfg(feature = "voice_input")]
|
||||||
@@ -2299,6 +2304,8 @@ pub enum AgentInputFooterAction {
|
|||||||
ShowContextMenu {
|
ShowContextMenu {
|
||||||
position: Vector2F,
|
position: Vector2F,
|
||||||
},
|
},
|
||||||
|
StartRemoteControl,
|
||||||
|
StopRemoteControl,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedActionView for AgentInputFooter {
|
impl TypedActionView for AgentInputFooter {
|
||||||
@@ -2497,6 +2504,12 @@ impl TypedActionView for AgentInputFooter {
|
|||||||
position: *position,
|
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
|
/// source conversation with content) or activates `&` compose mode
|
||||||
/// (preserving any in-flight prompt).
|
/// (preserving any in-flight prompt).
|
||||||
HandoffChipClicked,
|
HandoffChipClicked,
|
||||||
|
StartRemoteControl,
|
||||||
|
StopRemoteControl,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entity for AgentInputFooter {
|
impl Entity for AgentInputFooter {
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ pub enum AgentToolbarItemKind {
|
|||||||
|
|
||||||
// Agent view only – "Hand off to cloud" chip.
|
// Agent view only – "Hand off to cloud" chip.
|
||||||
HandoffToCloud,
|
HandoffToCloud,
|
||||||
|
|
||||||
|
// Agent view only – "Share session" button.
|
||||||
|
ShareSession,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AgentToolbarItemKind {
|
impl AgentToolbarItemKind {
|
||||||
@@ -81,7 +84,8 @@ impl AgentToolbarItemKind {
|
|||||||
| Self::NLDToggle
|
| Self::NLDToggle
|
||||||
| Self::ContextWindowUsage
|
| Self::ContextWindowUsage
|
||||||
| Self::FastForwardToggle
|
| Self::FastForwardToggle
|
||||||
| Self::HandoffToCloud => ToolbarAvailability::AgentViewOnly,
|
| Self::HandoffToCloud
|
||||||
|
| Self::ShareSession => ToolbarAvailability::AgentViewOnly,
|
||||||
Self::FileExplorer | Self::RichInput | Self::Settings => {
|
Self::FileExplorer | Self::RichInput | Self::Settings => {
|
||||||
ToolbarAvailability::CLIAgentOnly
|
ToolbarAvailability::CLIAgentOnly
|
||||||
}
|
}
|
||||||
@@ -102,6 +106,7 @@ impl AgentToolbarItemKind {
|
|||||||
Self::FastForwardToggle => !status.is_viewer() || status.is_executor(),
|
Self::FastForwardToggle => !status.is_viewer() || status.is_executor(),
|
||||||
// Handoff is host-initiated; viewers cannot hand off another user's conversation.
|
// Handoff is host-initiated; viewers cannot hand off another user's conversation.
|
||||||
Self::HandoffToCloud => !status.is_viewer(),
|
Self::HandoffToCloud => !status.is_viewer(),
|
||||||
|
Self::ShareSession => !status.is_viewer(),
|
||||||
Self::ContextChip(_)
|
Self::ContextChip(_)
|
||||||
| Self::ModelSelector
|
| Self::ModelSelector
|
||||||
| Self::NLDToggle
|
| Self::NLDToggle
|
||||||
@@ -124,6 +129,7 @@ impl AgentToolbarItemKind {
|
|||||||
Self::Settings => "Settings",
|
Self::Settings => "Settings",
|
||||||
Self::FastForwardToggle => "Fast Forward",
|
Self::FastForwardToggle => "Fast Forward",
|
||||||
Self::HandoffToCloud => "Hand off to cloud",
|
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
|
// 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.
|
// closest fit among the existing icons for V0; design may swap it later.
|
||||||
Self::HandoffToCloud => Some(Icon::UploadCloud),
|
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::elements::{Container, Element, Empty, MouseStateHandle};
|
||||||
use galaxyui::keymap::Keystroke;
|
use galaxyui::keymap::Keystroke;
|
||||||
use galaxyui::platform::OperatingSystem;
|
use galaxyui::platform::OperatingSystem;
|
||||||
use galaxyui::{AppContext, Entity, ModelHandle, SingletonEntity, View, ViewContext};
|
|
||||||
use parking_lot::FairMutex;
|
|
||||||
use galaxyui::{
|
use galaxyui::{
|
||||||
AppContext, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
AppContext, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
||||||
};
|
};
|
||||||
|
use parking_lot::FairMutex;
|
||||||
|
|
||||||
use super::{AgentViewState, EphemeralMessageModel, EphemeralMessageModelEvent};
|
use super::{AgentViewState, EphemeralMessageModel, EphemeralMessageModelEvent};
|
||||||
use crate::ai::agent::conversation::AIConversation;
|
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::appearance::Appearance;
|
||||||
use galaxy_core::ui::Icon;
|
use galaxy_core::ui::Icon;
|
||||||
use galaxyui::elements::{
|
use galaxyui::elements::{
|
||||||
@@ -16,6 +13,9 @@ use galaxyui::{
|
|||||||
AppContext, Element, Entity, EntityId, EventContext, ModelHandle, SingletonEntity,
|
AppContext, Element, Entity, EntityId, EventContext, ModelHandle, SingletonEntity,
|
||||||
TypedActionView, View, ViewContext,
|
TypedActionView, View, ViewContext,
|
||||||
};
|
};
|
||||||
|
use pathfinder_color::ColorU;
|
||||||
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
|
use settings::Setting;
|
||||||
|
|
||||||
use super::{AgentViewController, AgentViewEntryOrigin};
|
use super::{AgentViewController, AgentViewEntryOrigin};
|
||||||
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
|
use crate::ai::active_agent_views_model::ActiveAgentViewsModel;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use instant::Instant;
|
|
||||||
use parking_lot::FairMutex;
|
|
||||||
use galaxy_core::ui::appearance::Appearance;
|
use galaxy_core::ui::appearance::Appearance;
|
||||||
use galaxyui::keymap::Keystroke;
|
use galaxyui::keymap::Keystroke;
|
||||||
use galaxyui::r#async::SpawnedFutureHandle;
|
use galaxyui::r#async::SpawnedFutureHandle;
|
||||||
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
use galaxyui::{AppContext, Entity, EntityId, ModelContext, ModelHandle, SingletonEntity};
|
||||||
|
use instant::Instant;
|
||||||
|
use parking_lot::FairMutex;
|
||||||
|
|
||||||
use super::{DismissalStrategy, EphemeralMessage, EphemeralMessageModel};
|
use super::{DismissalStrategy, EphemeralMessage, EphemeralMessageModel};
|
||||||
use crate::ai::agent::conversation::AIConversationId;
|
use crate::ai::agent::conversation::AIConversationId;
|
||||||
@@ -1021,7 +1021,6 @@ fn exit_confirmation_message(
|
|||||||
) -> Message {
|
) -> Message {
|
||||||
use galaxyui::SingletonEntity;
|
use galaxyui::SingletonEntity;
|
||||||
|
|
||||||
|
|
||||||
let appearance = Appearance::handle(app).as_ref(app);
|
let appearance = Appearance::handle(app).as_ref(app);
|
||||||
|
|
||||||
let (keystroke, text) = match trigger {
|
let (keystroke, text) = match trigger {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ai::agent::action::{AIAgentActionType, ShellCommandDelay};
|
use ai::agent::action::{AIAgentActionType, ShellCommandDelay};
|
||||||
use parking_lot::FairMutex;
|
|
||||||
use galaxy_core::ui::appearance::Appearance;
|
use galaxy_core::ui::appearance::Appearance;
|
||||||
use galaxyui::elements::{CornerRadius, Radius};
|
use galaxyui::elements::{CornerRadius, Radius};
|
||||||
use galaxyui::{
|
use galaxyui::{
|
||||||
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, View, ViewContext,
|
AppContext, Element, Entity, EntityId, ModelHandle, SingletonEntity, View, ViewContext,
|
||||||
};
|
};
|
||||||
|
use parking_lot::FairMutex;
|
||||||
|
|
||||||
use crate::ai::agent::icons;
|
use crate::ai::agent::icons;
|
||||||
use crate::ai::blocklist::block::cli_controller::LongRunningCommandControlState;
|
use crate::ai::blocklist::block::cli_controller::LongRunningCommandControlState;
|
||||||
|
|||||||
@@ -22,15 +22,15 @@ pub use agent_view_block::*;
|
|||||||
pub use controller::*;
|
pub use controller::*;
|
||||||
pub(crate) use conversation_selection::AgentViewConversationSelection;
|
pub(crate) use conversation_selection::AgentViewConversationSelection;
|
||||||
pub use ephemeral_message_model::*;
|
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::appearance::Appearance;
|
||||||
use galaxy_core::ui::color::blend::Blend;
|
use galaxy_core::ui::color::blend::Blend;
|
||||||
use galaxy_core::ui::theme::Fill;
|
use galaxy_core::ui::theme::Fill;
|
||||||
|
use galaxyui::fonts::Properties;
|
||||||
use galaxyui::keymap::Keystroke;
|
use galaxyui::keymap::Keystroke;
|
||||||
use galaxyui::{AppContext, SingletonEntity};
|
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::*;
|
pub use zero_state_block::*;
|
||||||
|
|
||||||
use crate::terminal::model::TerminalModel;
|
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::appearance::Appearance;
|
||||||
use galaxy_core::ui::theme::Fill;
|
use galaxy_core::ui::theme::Fill;
|
||||||
use galaxyui::elements::{
|
use galaxyui::elements::{
|
||||||
@@ -11,6 +9,8 @@ use galaxyui::fonts::Weight::Bold;
|
|||||||
use galaxyui::platform::Cursor;
|
use galaxyui::platform::Cursor;
|
||||||
use galaxyui::text_layout::ClipConfig;
|
use galaxyui::text_layout::ClipConfig;
|
||||||
use galaxyui::{AppContext, Element, EntityId, EventContext, SingletonEntity};
|
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::api::ServerConversationToken;
|
||||||
use crate::ai::agent::conversation::{AIConversation, AIConversationId};
|
use crate::ai::agent::conversation::{AIConversation, AIConversationId};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user