Complete Rig tool lifecycle migration

This commit is contained in:
2026-08-04 16:00:20 -05:00
parent 91d8bd0381
commit a3c68e9c30
30 changed files with 1494 additions and 176 deletions
+20 -2
View File
@@ -24,7 +24,7 @@ use mcp::TemplatableMCPServerInfo;
pub use r#impl::generate_multi_agent_output;
use serde::Serialize;
use super::{AIAgentInput, MCPContext, MCPServer, RequestMetadata, Suggestions};
use super::{AIAgentAction, AIAgentInput, MCPContext, MCPServer, RequestMetadata, Suggestions};
use crate::ai::agent::conversation::AIConversationId;
use crate::ai::ambient_agents::AmbientAgentTaskId;
use crate::ai::blocklist::{BlocklistAIPermissions, RequestInput, SessionContext};
@@ -162,17 +162,35 @@ pub struct RequestParams {
pub global_rules: Vec<(String, String)>,
}
pub type Event = Result<warp_multi_agent_api::ResponseEvent, Arc<AIApiError>>;
/// Provider/runtime events consumed by the local conversation controller.
///
/// The legacy response envelope remains at the UI boundary while the local Rig runtime emits
/// executable tool proposals directly as Galaxy domain actions. This avoids translating Rig tool
/// calls into protobuf only to immediately translate them back before execution.
#[derive(Debug)]
pub enum StreamEvent {
Response(warp_multi_agent_api::ResponseEvent),
ToolProposed(AIAgentAction),
}
pub type Event = Result<StreamEvent, Arc<AIApiError>>;
pub type LegacyEvent = Result<warp_multi_agent_api::ResponseEvent, Arc<AIApiError>>;
#[cfg(not(target_family = "wasm"))]
pub type ResponseStream = Pin<Box<dyn Stream<Item = Event> + Send + 'static>>;
#[cfg(not(target_family = "wasm"))]
pub type LegacyResponseStream = Pin<Box<dyn Stream<Item = LegacyEvent> + Send + 'static>>;
// The WASM version of this type has no bound on `Send`, which is an unnecessary bound when
// targeting wasm because the browser is single-threaded (and we don't leverage WebWorkers for async
// execution in WoW).
#[cfg(target_family = "wasm")]
pub type ResponseStream = Pin<Box<dyn Stream<Item = Event>>>;
#[cfg(target_family = "wasm")]
pub type LegacyResponseStream = Pin<Box<dyn Stream<Item = LegacyEvent>>>;
#[derive(Debug, Clone)]
pub struct ConversationData {
pub id: AIConversationId,
+7 -3
View File
@@ -6,7 +6,7 @@ use galaxy_core::features::FeatureFlag;
use warp_multi_agent_api as api;
use super::convert_to::convert_input;
use super::{ConvertToAPITypeError, RequestParams, ResponseStream};
use super::{ConvertToAPITypeError, RequestParams, ResponseStream, StreamEvent};
use crate::ai::agent::redaction;
use crate::ai::openai::translator as openai_translator;
use crate::ai::provider::ProviderConfig;
@@ -164,7 +164,9 @@ pub async fn generate_multi_agent_output(
match openai_translator::execute(translator_request, &mut request).await {
Ok(stream) => {
let output_stream = stream.take_until(cancellation_rx);
let output_stream = stream
.map(|event| event.map(StreamEvent::Response))
.take_until(cancellation_rx);
Ok(Box::pin(output_stream))
}
Err(e) => {
@@ -196,7 +198,9 @@ pub async fn generate_multi_agent_output(
match crate::ai::bedrock::translator::execute(translator_request, &mut request).await {
Ok(stream) => {
let output_stream = stream.take_until(cancellation_rx);
let output_stream = stream
.map(|event| event.map(StreamEvent::Response))
.take_until(cancellation_rx);
Ok(Box::pin(output_stream))
}
Err(e) => {
+41
View File
@@ -2227,6 +2227,47 @@ impl AIConversation {
Ok(())
}
pub fn apply_domain_tool_proposal(
&mut self,
stream_id: &ResponseStreamId,
terminal_surface_id: EntityId,
action: AIAgentAction,
ctx: &mut ModelContext<BlocklistAIHistoryModel>,
) -> Result<(), UpdateConversationError> {
let added_exchanges = self
.added_exchanges_by_response
.get(stream_id)
.ok_or(UpdateConversationError::NoPendingRequest)?;
let exchange_id = added_exchanges
.iter()
.find(|added| added.task_id == action.task_id)
.map(|added| added.exchange_id)
.ok_or(UpdateConversationError::TaskNotFound)?;
let message_id = MessageId::new(action.id.to_string());
let exchange = self.get_exchange_to_update(exchange_id)?;
match &exchange.output_status {
AIAgentOutputStatus::Streaming {
output: Some(output),
} => output
.get_mut()
.messages
.push(AIAgentOutputMessage::action(message_id, action)),
AIAgentOutputStatus::Streaming { output: None } => {
return Err(UpdateConversationError::OutputNeverInitialized);
}
AIAgentOutputStatus::Finished { .. } => {
return Err(UpdateConversationError::OutputAlreadyFinished);
}
}
ctx.emit(BlocklistAIHistoryEvent::UpdatedStreamingExchange {
exchange_id,
terminal_surface_id,
conversation_id: self.id,
is_hidden: self.hidden_exchanges.contains(&exchange_id),
});
Ok(())
}
pub fn update_cost_and_usage_for_request(
&mut self,
request_cost: Option<RequestCost>,