first pass of merging in warp (doesn't build)
This commit is contained in:
+73
-60
@@ -1,44 +1,35 @@
|
||||
pub mod helper;
|
||||
pub mod transaction;
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Display,
|
||||
ops::Deref,
|
||||
};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Display;
|
||||
use std::ops::Deref;
|
||||
|
||||
use chrono::DateTime;
|
||||
use ai::skills::SkillPathOrigin;
|
||||
use field_mask::{FieldMaskError, FieldMaskOperation};
|
||||
use helper::{MessageExt, SubagentExt, ToolCallExt};
|
||||
use itertools::Itertools;
|
||||
use prost_types::FieldMask;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use warp_multi_agent_api::{
|
||||
self as api,
|
||||
message::{tool_call::subagent::Metadata, Message},
|
||||
};
|
||||
use warp_multi_agent_api::message::tool_call::subagent::Metadata;
|
||||
use warp_multi_agent_api::message::Message;
|
||||
use warp_multi_agent_api::{self as api};
|
||||
|
||||
use crate::{
|
||||
ai::{
|
||||
agent::comment::CodeReview,
|
||||
document::ai_document_model::{AIDocumentId, AIDocumentVersion},
|
||||
},
|
||||
server::datetime_ext::DateTimeExt,
|
||||
terminal::model::block::BlockId,
|
||||
AIAgentTodoList,
|
||||
use super::api::convert_conversation::convert_tool_call_result_to_input;
|
||||
use super::api::{
|
||||
user_inputs_from_messages, ConversionParams, ConvertAPIMessageToClientOutputMessage,
|
||||
};
|
||||
|
||||
use super::comment::CodeReview;
|
||||
use super::conversation::{context_in_exchanges, update_todo_list_from_todo_op};
|
||||
use super::{
|
||||
api::{
|
||||
convert_conversation::convert_tool_call_result_to_input, user_inputs_from_messages,
|
||||
ConversionParams, ConvertAPIMessageToClientOutputMessage,
|
||||
},
|
||||
conversation::{context_in_exchanges, update_todo_list_from_todo_op},
|
||||
AIAgentContext, AIAgentExchange, AIAgentExchangeId, AIAgentOutput, AIAgentOutputMessage,
|
||||
AIAgentOutputStatus, MaybeAIAgentOutputMessage, MessageId, MessageToAIAgentOutputMessageError,
|
||||
Shared,
|
||||
};
|
||||
use crate::ai::document::ai_document_model::{AIDocumentId, AIDocumentVersion};
|
||||
use crate::terminal::model::block::BlockId;
|
||||
use crate::AIAgentTodoList;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct TaskId(String);
|
||||
@@ -128,7 +119,6 @@ struct ServerTask {
|
||||
}
|
||||
|
||||
mod optimistic {
|
||||
use crate::terminal::model::block::BlockId;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) struct CLIAgentSubtask {
|
||||
@@ -176,6 +166,12 @@ pub struct Task {
|
||||
/// List of `AIAgentExchange`s corresponding to messages contained in this task.
|
||||
exchanges: Vec<AIAgentExchange>,
|
||||
}
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) struct TaskMessageContext<'a> {
|
||||
pub(super) current_todo_list: Option<&'a AIAgentTodoList>,
|
||||
pub(super) active_code_review: Option<&'a CodeReview>,
|
||||
pub(super) skill_path_origin: &'a SkillPathOrigin,
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub(super) fn new_optimistic_root() -> Self {
|
||||
@@ -236,6 +232,7 @@ impl Task {
|
||||
parent_task: Option<&api::Task>,
|
||||
current_todo_list: Option<&AIAgentTodoList>,
|
||||
active_code_review: Option<&CodeReview>,
|
||||
skill_path_origin: &SkillPathOrigin,
|
||||
) -> Result<Self, UpgradeOptimisticTaskError> {
|
||||
match self.data {
|
||||
TaskImpl::Optimistic(optimistic::Task::Root) => {
|
||||
@@ -281,8 +278,11 @@ impl Task {
|
||||
if let Err(e) = self.update_exchange_from_messages(
|
||||
messages,
|
||||
exchange_id,
|
||||
current_todo_list,
|
||||
active_code_review,
|
||||
TaskMessageContext {
|
||||
current_todo_list,
|
||||
active_code_review,
|
||||
skill_path_origin,
|
||||
},
|
||||
false,
|
||||
) {
|
||||
log::error!(
|
||||
@@ -315,7 +315,8 @@ impl Task {
|
||||
parent_task: &api::Task,
|
||||
existing_exchange: &AIAgentExchange,
|
||||
current_todo_list: Option<&AIAgentTodoList>,
|
||||
current_comment_state: Option<&CodeReview>,
|
||||
active_code_review: Option<&CodeReview>,
|
||||
skill_path_origin: &SkillPathOrigin,
|
||||
should_convert_input_messages: bool,
|
||||
) -> Self {
|
||||
let subagent_call_and_id = parent_task.messages.iter().find_map(|message| {
|
||||
@@ -330,7 +331,7 @@ impl Task {
|
||||
input: vec![],
|
||||
output_status: AIAgentOutputStatus::Streaming { output: None },
|
||||
added_message_ids: Default::default(),
|
||||
start_time: DateTime::now().into(),
|
||||
start_time: chrono::Local::now(),
|
||||
finish_time: None,
|
||||
time_to_first_token_ms: None,
|
||||
working_directory: existing_exchange.working_directory.clone(),
|
||||
@@ -368,8 +369,11 @@ impl Task {
|
||||
me.update_exchange_from_messages(
|
||||
messages_clone,
|
||||
new_exchange_id,
|
||||
current_todo_list,
|
||||
current_comment_state,
|
||||
TaskMessageContext {
|
||||
current_todo_list,
|
||||
active_code_review,
|
||||
skill_path_origin,
|
||||
},
|
||||
should_convert_input_messages,
|
||||
)
|
||||
.expect("Exchange exists and output is in 'streaming' state.");
|
||||
@@ -462,7 +466,7 @@ impl Task {
|
||||
input: vec![],
|
||||
output_status: AIAgentOutputStatus::Streaming { output: None },
|
||||
added_message_ids: Default::default(),
|
||||
start_time: DateTime::now().into(),
|
||||
start_time: chrono::Local::now(),
|
||||
finish_time: None,
|
||||
time_to_first_token_ms: None,
|
||||
working_directory: existing_exchange.working_directory.clone(),
|
||||
@@ -603,6 +607,19 @@ impl Task {
|
||||
self.try_get_source().ok()
|
||||
}
|
||||
|
||||
pub(super) fn source_for_persistence(&self) -> Option<api::Task> {
|
||||
match &self.data {
|
||||
TaskImpl::Server(server_data) => Some(server_data.source.clone()),
|
||||
// Optimistic root tasks have a client-generated UUID and no
|
||||
// server-side identity yet. Persisting a stub `api::Task` for them
|
||||
// produces an orphan row in `agent_tasks` that survives the later
|
||||
// server-side upgrade and breaks restore by competing with the
|
||||
// real server root for parentless-task selection. See QUALITY-774.
|
||||
TaskImpl::Optimistic(optimistic::Task::Root) => None,
|
||||
TaskImpl::Optimistic(optimistic::Task::CLIAgent(_)) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn messages(&self) -> impl Iterator<Item = &api::Message> {
|
||||
self.source()
|
||||
.into_iter()
|
||||
@@ -677,8 +694,7 @@ impl Task {
|
||||
&mut self,
|
||||
messages: Vec<api::Message>,
|
||||
exchange_id: AIAgentExchangeId,
|
||||
current_todo_list: Option<&AIAgentTodoList>,
|
||||
current_comments: Option<&CodeReview>,
|
||||
message_context: TaskMessageContext<'_>,
|
||||
should_convert_input_messages: bool,
|
||||
) -> Result<(), UpdateTaskError> {
|
||||
if self.source().is_none() {
|
||||
@@ -687,8 +703,7 @@ impl Task {
|
||||
self.update_exchange_from_messages(
|
||||
messages.clone(),
|
||||
exchange_id,
|
||||
current_todo_list,
|
||||
current_comments,
|
||||
message_context,
|
||||
should_convert_input_messages,
|
||||
)?;
|
||||
self.try_get_source_mut()?.messages.extend(messages);
|
||||
@@ -699,8 +714,7 @@ impl Task {
|
||||
&mut self,
|
||||
message: api::Message,
|
||||
exchange_id: AIAgentExchangeId,
|
||||
current_todo_list: Option<&AIAgentTodoList>,
|
||||
current_comments: Option<&CodeReview>,
|
||||
message_context: TaskMessageContext<'_>,
|
||||
mask: FieldMask,
|
||||
should_convert_input_messages: bool,
|
||||
) -> Result<&api::Message, UpdateTaskError> {
|
||||
@@ -714,8 +728,7 @@ impl Task {
|
||||
self.add_messages(
|
||||
vec![message.clone()],
|
||||
exchange_id,
|
||||
current_todo_list,
|
||||
current_comments,
|
||||
message_context,
|
||||
should_convert_input_messages,
|
||||
)?;
|
||||
return self
|
||||
@@ -734,10 +747,13 @@ impl Task {
|
||||
.exchange_mut(exchange_id)
|
||||
.ok_or(UpdateTaskError::ExchangeNotFound)?;
|
||||
exchange_to_update.upsert_output_for_message(
|
||||
&id,
|
||||
&updated_message,
|
||||
current_todo_list,
|
||||
current_comments,
|
||||
ConversionParams {
|
||||
task_id: &id,
|
||||
current_todo_list: message_context.current_todo_list,
|
||||
active_code_review: message_context.active_code_review,
|
||||
skill_path_origin: message_context.skill_path_origin,
|
||||
},
|
||||
)?;
|
||||
|
||||
// Task message updates can carry tool call result updates with them,
|
||||
@@ -782,8 +798,7 @@ impl Task {
|
||||
&mut self,
|
||||
message: api::Message,
|
||||
exchange_id: AIAgentExchangeId,
|
||||
current_todo_list: Option<&AIAgentTodoList>,
|
||||
current_comments: Option<&CodeReview>,
|
||||
message_context: TaskMessageContext<'_>,
|
||||
mask: FieldMask,
|
||||
) -> Result<&api::Message, UpdateTaskError> {
|
||||
let Some((idx, existing_message)) = self
|
||||
@@ -836,10 +851,13 @@ impl Task {
|
||||
.exchange_mut(exchange_id)
|
||||
.ok_or(UpdateTaskError::ExchangeNotFound)?;
|
||||
exchange_to_update.upsert_output_for_message(
|
||||
&id,
|
||||
&updated_message,
|
||||
current_todo_list,
|
||||
current_comments,
|
||||
ConversionParams {
|
||||
task_id: &id,
|
||||
current_todo_list: message_context.current_todo_list,
|
||||
active_code_review: message_context.active_code_review,
|
||||
skill_path_origin: message_context.skill_path_origin,
|
||||
},
|
||||
)?;
|
||||
|
||||
let source = self.try_get_source_mut()?;
|
||||
@@ -964,8 +982,7 @@ impl Task {
|
||||
&mut self,
|
||||
messages: Vec<api::Message>,
|
||||
exchange_id: AIAgentExchangeId,
|
||||
current_todo_list: Option<&AIAgentTodoList>,
|
||||
active_code_review: Option<&CodeReview>,
|
||||
message_context: TaskMessageContext<'_>,
|
||||
should_convert_input_messages: bool,
|
||||
) -> Result<(), UpdateTaskError> {
|
||||
let exchange = self
|
||||
@@ -1007,8 +1024,9 @@ impl Task {
|
||||
.filter_map(|m| {
|
||||
match m.to_client_output_message(ConversionParams {
|
||||
task_id: &self.id,
|
||||
current_todo_list,
|
||||
active_code_review,
|
||||
current_todo_list: message_context.current_todo_list,
|
||||
active_code_review: message_context.active_code_review,
|
||||
skill_path_origin: message_context.skill_path_origin,
|
||||
}) {
|
||||
Ok(MaybeAIAgentOutputMessage::Message(m)) => Some(Ok(m)),
|
||||
Ok(MaybeAIAgentOutputMessage::NoClientRepresentation) => None,
|
||||
@@ -1043,10 +1061,8 @@ impl AIAgentExchange {
|
||||
/// Note: this means updates will insert a new entry after previously added entries.
|
||||
fn upsert_output_for_message(
|
||||
&self,
|
||||
task_id: &TaskId,
|
||||
task_message: &api::Message,
|
||||
todo_list: Option<&AIAgentTodoList>,
|
||||
comments: Option<&CodeReview>,
|
||||
conversion_params: super::api::ConversionParams<'_>,
|
||||
) -> Result<(), UpdateTaskError> {
|
||||
if let AIAgentOutputStatus::Streaming {
|
||||
output: Some(output),
|
||||
@@ -1079,11 +1095,8 @@ impl AIAgentExchange {
|
||||
|
||||
match task_message
|
||||
.clone()
|
||||
.to_client_output_message(ConversionParams {
|
||||
current_todo_list: todo_list,
|
||||
active_code_review: comments,
|
||||
task_id,
|
||||
})? {
|
||||
.to_client_output_message(conversion_params)?
|
||||
{
|
||||
MaybeAIAgentOutputMessage::Message(m) => {
|
||||
log::info!(
|
||||
"[bedrock-debug] upsert_output_for_message: client_message_type={:?}",
|
||||
|
||||
Reference in New Issue
Block a user