first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -2,34 +2,33 @@
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use ai::agent::action::{LifecycleEventType as StartAgentLifecycleEventType, ReadSkillRequest};
|
||||
use ai::agent::action_result::StartAgentVersion;
|
||||
use ai::agent::convert::ToolToAIAgentActionError;
|
||||
use ai::agent::UnknownCitationTypeError;
|
||||
use ai::skills::{
|
||||
skill_reference_from_api_skill_ref, skill_reference_from_read_skill_ref, SkillPathOrigin,
|
||||
};
|
||||
use api::ask_user_question::question::QuestionType;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
use crate::ai::agent::api::convert_conversation::{
|
||||
convert_input_context, convert_tool_call_result_to_input,
|
||||
};
|
||||
use crate::ai::agent::comment::CodeReview;
|
||||
use crate::ai::agent::task::TaskId;
|
||||
use crate::ai::agent::todos::AIAgentTodoList;
|
||||
use crate::ai::agent::util::parse_markdown_into_text_and_code_sections;
|
||||
use crate::ai::agent::{
|
||||
util::parse_markdown_into_text_and_code_sections, AIAgentAction, AIAgentActionType,
|
||||
AIAgentCitation, AIAgentInput, AIAgentOutputMessage, AIAgentText, AIAgentTodo,
|
||||
ArtifactCreatedData, MessageId, StartAgentExecutionMode, SuggestedAgentModeWorkflow,
|
||||
SuggestedRule, Suggestions, TodoOperation,
|
||||
};
|
||||
use crate::ai::agent::{
|
||||
CloneRepositoryURL, SubagentCall, SubagentType, SummarizationType, WebFetchStatus,
|
||||
WebSearchStatus,
|
||||
AIAgentAction, AIAgentActionType, AIAgentAttachment, AIAgentCitation, AIAgentInput,
|
||||
AIAgentOutputMessage, AIAgentText, AIAgentTodo, ArtifactCreatedData, CloneRepositoryURL,
|
||||
MessageId, RunAgentsAgentRunConfig, RunAgentsExecutionMode, RunAgentsRequest,
|
||||
StartAgentExecutionMode, SubagentCall, SubagentType, SuggestedAgentModeWorkflow, SuggestedRule,
|
||||
Suggestions, SummarizationType, TodoOperation, UserQueryMode, WebFetchStatus, WebSearchStatus,
|
||||
};
|
||||
use crate::ai::artifact_download::sanitized_basename;
|
||||
use crate::ai::document::ai_document_model::{AIDocumentId, AIDocumentVersion};
|
||||
use ai::agent::action::LifecycleEventType as StartAgentLifecycleEventType;
|
||||
use ai::agent::action_result::StartAgentVersion;
|
||||
use ai::agent::convert::ToolToAIAgentActionError;
|
||||
use ai::agent::UnknownCitationTypeError;
|
||||
use ai::skills::SkillReference;
|
||||
use api::ask_user_question::question::QuestionType;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use warp_multi_agent_api as api;
|
||||
|
||||
use crate::ai::agent::{AIAgentAttachment, UserQueryMode};
|
||||
|
||||
impl TryFrom<api::Attachment> for AIAgentAttachment {
|
||||
type Error = anyhow::Error;
|
||||
@@ -53,6 +52,18 @@ impl TryFrom<api::Attachment> for AIAgentAttachment {
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_read_skill(
|
||||
read_skill: api::message::tool_call::ReadSkill,
|
||||
skill_path_origin: &SkillPathOrigin,
|
||||
) -> Result<AIAgentActionType, ToolToAIAgentActionError> {
|
||||
let Some(reference) = read_skill.skill_reference else {
|
||||
return Err(ToolToAIAgentActionError::MissingSkillReference);
|
||||
};
|
||||
let skill = skill_reference_from_read_skill_ref(reference, skill_path_origin)
|
||||
.map_err(|_| ToolToAIAgentActionError::MissingSkillReference)?;
|
||||
Ok(AIAgentActionType::ReadSkill(ReadSkillRequest { skill }))
|
||||
}
|
||||
|
||||
/// Converts proto UserQueryMode to the internal UserQueryMode type
|
||||
pub(crate) fn convert_user_query_mode(mode: Option<&api::UserQueryMode>) -> UserQueryMode {
|
||||
let Some(mode) = mode else {
|
||||
@@ -81,6 +92,22 @@ fn convert_start_agent_v2_harness_type(
|
||||
.filter(|harness_type| !harness_type.trim().is_empty())
|
||||
}
|
||||
|
||||
/// Maps the proto `Harness` oneof to a client-side string identifier
|
||||
/// (e.g. "oz", "claude"). Returns `None` for an unset variant.
|
||||
pub(crate) fn convert_run_agents_harness(harness: Option<&api::Harness>) -> Option<String> {
|
||||
let variant = harness?.variant.as_ref()?;
|
||||
Some(
|
||||
match variant {
|
||||
api::harness::Variant::Oz(_) => "oz",
|
||||
api::harness::Variant::ClaudeCode(_) => "claude",
|
||||
api::harness::Variant::OpenCode(_) => "opencode",
|
||||
api::harness::Variant::Gemini(_) => "gemini",
|
||||
api::harness::Variant::Codex(_) => "codex",
|
||||
}
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
fn convert_start_agent_execution_mode(
|
||||
execution_mode: Option<api::start_agent::ExecutionMode>,
|
||||
) -> StartAgentExecutionMode {
|
||||
@@ -94,8 +121,62 @@ fn convert_start_agent_execution_mode(
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_run_agents_execution_mode(
|
||||
execution_mode: Option<api::run_agents::ExecutionMode>,
|
||||
) -> RunAgentsExecutionMode {
|
||||
match execution_mode {
|
||||
Some(api::run_agents::ExecutionMode::Remote(remote)) => RunAgentsExecutionMode::Remote {
|
||||
environment_id: remote.environment_id,
|
||||
worker_host: remote.worker_host,
|
||||
computer_use_enabled: remote.computer_use_enabled,
|
||||
},
|
||||
Some(api::run_agents::ExecutionMode::Local(_)) | None => RunAgentsExecutionMode::Local,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_run_agents(
|
||||
run_agents: api::RunAgents,
|
||||
skill_path_origin: &SkillPathOrigin,
|
||||
) -> AIAgentActionType {
|
||||
let api::RunAgents {
|
||||
summary,
|
||||
base_prompt,
|
||||
skills,
|
||||
model_id,
|
||||
harness,
|
||||
agent_run_configs,
|
||||
execution_mode,
|
||||
plan_id,
|
||||
} = run_agents;
|
||||
AIAgentActionType::RunAgents(RunAgentsRequest {
|
||||
summary,
|
||||
base_prompt,
|
||||
skills: skills
|
||||
.into_iter()
|
||||
.filter_map(|skill| skill_reference_from_api_skill_ref(skill, skill_path_origin))
|
||||
.collect(),
|
||||
model_id,
|
||||
harness_type: convert_run_agents_harness(harness.as_ref()).unwrap_or_default(),
|
||||
execution_mode: convert_run_agents_execution_mode(execution_mode),
|
||||
agent_run_configs: agent_run_configs
|
||||
.into_iter()
|
||||
.map(|config| RunAgentsAgentRunConfig {
|
||||
name: config.name,
|
||||
prompt: config.prompt,
|
||||
title: config.title,
|
||||
})
|
||||
.collect(),
|
||||
plan_id,
|
||||
// Auth secret is a client-side dispatch concern populated by the
|
||||
// confirmation card from `CloudAgentSettings.last_selected_auth_secret`
|
||||
// before Accept. The proto does not carry it.
|
||||
harness_auth_secret_name: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_start_agent_v2_execution_mode(
|
||||
execution_mode: Option<api::start_agent_v2::ExecutionMode>,
|
||||
skill_path_origin: &SkillPathOrigin,
|
||||
) -> StartAgentExecutionMode {
|
||||
match execution_mode.and_then(|execution_mode| execution_mode.mode) {
|
||||
Some(api::start_agent_v2::execution_mode::Mode::Remote(remote)) => {
|
||||
@@ -104,7 +185,9 @@ fn convert_start_agent_v2_execution_mode(
|
||||
skill_references: remote
|
||||
.skills
|
||||
.into_iter()
|
||||
.filter_map(convert_skill_reference)
|
||||
.filter_map(|skill| {
|
||||
skill_reference_from_api_skill_ref(skill, skill_path_origin)
|
||||
})
|
||||
.collect(),
|
||||
model_id: remote.model_id,
|
||||
computer_use_enabled: remote.computer_use_enabled,
|
||||
@@ -112,6 +195,9 @@ fn convert_start_agent_v2_execution_mode(
|
||||
harness_type: convert_start_agent_v2_harness_type(remote.harness)
|
||||
.unwrap_or_default(),
|
||||
title: remote.title,
|
||||
// Auth secret is plumbed client-side via `RunAgentsRequest`;
|
||||
// StartAgentV2 from the server never carries it.
|
||||
auth_secret_name: None,
|
||||
}
|
||||
}
|
||||
Some(api::start_agent_v2::execution_mode::Mode::Local(local)) => {
|
||||
@@ -123,16 +209,6 @@ fn convert_start_agent_v2_execution_mode(
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_skill_reference(skill_ref: api::SkillRef) -> Option<SkillReference> {
|
||||
match skill_ref.skill_reference {
|
||||
Some(api::skill_ref::SkillReference::Path(path)) => Some(SkillReference::Path(path.into())),
|
||||
Some(api::skill_ref::SkillReference::BundledSkillId(id)) => {
|
||||
Some(SkillReference::BundledSkillId(id))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Unexpected errors when trying to convert an [`api::Message`] to an [`AIAgentOutputMessage`].
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum MessageToAIAgentOutputMessageError {
|
||||
@@ -167,6 +243,7 @@ pub struct ConversionParams<'a> {
|
||||
pub task_id: &'a TaskId,
|
||||
pub current_todo_list: Option<&'a AIAgentTodoList>,
|
||||
pub active_code_review: Option<&'a CodeReview>,
|
||||
pub skill_path_origin: &'a SkillPathOrigin,
|
||||
}
|
||||
|
||||
/// Trait for converting an [`api::Message`] to an [`AIAgentOutputMessage`].
|
||||
@@ -569,7 +646,11 @@ impl ConvertAPIMessageToClientOutputMessage for api::Message {
|
||||
| api::message::Message::CodeReview(_)
|
||||
| api::message::Message::ServerEvent(_)
|
||||
| api::message::Message::InvokeSkill(_)
|
||||
| api::message::Message::PassiveSuggestionResult(_) => {
|
||||
| api::message::Message::PassiveSuggestionResult(_)
|
||||
// Stage 2 plan-card config snapshot: hydrated separately by the
|
||||
// plan card's `AIDocumentModel` subscription, not via the
|
||||
// exchange/output stream. No client output message representation.
|
||||
| api::message::Message::OrchestrationConfigSnapshot(_) => {
|
||||
Ok(MaybeAIAgentOutputMessage::NoClientRepresentation)
|
||||
}
|
||||
}
|
||||
@@ -600,7 +681,7 @@ trait ConvertAPIToolCallToAIAgentAction {
|
||||
) -> Result<MaybeAIAgentAction, ToolToAIAgentActionError>;
|
||||
}
|
||||
|
||||
/// Trys to convert an [`api::message::ToolCall`] to an [`AIAgentAction`].
|
||||
/// Tries to convert an [`api::message::ToolCall`] to an [`AIAgentAction`].
|
||||
///
|
||||
/// A [`Result::Error`] indicates an unexpected problem, while [`Ok(None)`]
|
||||
/// indicates a tool call that we aren't expected to parse.
|
||||
@@ -700,6 +781,7 @@ impl ConvertAPIToolCallToAIAgentAction for api::message::ToolCall {
|
||||
create_standard_action(request_computer_use.into())
|
||||
}
|
||||
api::message::tool_call::Tool::Subagent(subagent) => {
|
||||
use api::message::tool_call::subagent::conversation_search_metadata::Target;
|
||||
use api::message::tool_call::subagent::Metadata;
|
||||
let subagent_type = match subagent.metadata {
|
||||
Some(Metadata::Cli(_)) => SubagentType::Cli,
|
||||
@@ -713,14 +795,23 @@ impl ConvertAPIToolCallToAIAgentAction for api::message::ToolCall {
|
||||
} else {
|
||||
Some(cs_meta.query)
|
||||
};
|
||||
let conversation_id = if cs_meta.conversation_id.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(cs_meta.conversation_id)
|
||||
let (conversation_id, agent_run_id) = match cs_meta.target {
|
||||
Some(Target::ConversationId(conversation_id))
|
||||
if !conversation_id.is_empty() =>
|
||||
{
|
||||
(Some(conversation_id), None)
|
||||
}
|
||||
Some(Target::AgentRunId(agent_run_id)) if !agent_run_id.is_empty() => {
|
||||
(None, Some(agent_run_id))
|
||||
}
|
||||
Some(Target::ConversationId(_))
|
||||
| Some(Target::AgentRunId(_))
|
||||
| None => (None, None),
|
||||
};
|
||||
SubagentType::ConversationSearch {
|
||||
query,
|
||||
conversation_id,
|
||||
agent_run_id,
|
||||
}
|
||||
}
|
||||
Some(Metadata::WarpDocumentationSearch(_)) => {
|
||||
@@ -757,6 +848,7 @@ impl ConvertAPIToolCallToAIAgentAction for api::message::ToolCall {
|
||||
prompt: start_agent.prompt,
|
||||
execution_mode: convert_start_agent_v2_execution_mode(
|
||||
start_agent.execution_mode,
|
||||
params.skill_path_origin,
|
||||
),
|
||||
lifecycle_subscription: start_agent.lifecycle_subscription.map(
|
||||
|subscription| {
|
||||
@@ -769,6 +861,9 @@ impl ConvertAPIToolCallToAIAgentAction for api::message::ToolCall {
|
||||
),
|
||||
})
|
||||
}
|
||||
api::message::tool_call::Tool::RunAgents(orchestrate) => {
|
||||
create_standard_action(convert_run_agents(orchestrate, params.skill_path_origin))
|
||||
}
|
||||
api::message::tool_call::Tool::SendMessageToAgent(send_message) => {
|
||||
create_standard_action(AIAgentActionType::SendMessageToAgent {
|
||||
addresses: send_message.addresses,
|
||||
@@ -780,7 +875,7 @@ impl ConvertAPIToolCallToAIAgentAction for api::message::ToolCall {
|
||||
create_standard_action(insert_review_comments.into())
|
||||
}
|
||||
api::message::tool_call::Tool::ReadSkill(read_skill) => {
|
||||
create_standard_action(read_skill.try_into()?)
|
||||
create_standard_action(convert_read_skill(read_skill, params.skill_path_origin)?)
|
||||
}
|
||||
api::message::tool_call::Tool::FetchConversation(fetch_conversation) => {
|
||||
create_standard_action(fetch_conversation.into())
|
||||
@@ -798,6 +893,12 @@ impl ConvertAPIToolCallToAIAgentAction for api::message::ToolCall {
|
||||
api::message::tool_call::Tool::Server(_) => {
|
||||
Ok(MaybeAIAgentAction::NoClientRepresentation)
|
||||
}
|
||||
api::message::tool_call::Tool::WaitForEvents(payload) => {
|
||||
create_standard_action(AIAgentActionType::WaitForEvents {
|
||||
tool_call_id: self.tool_call_id.clone(),
|
||||
idle_timeout_seconds: payload.idle_timeout_seconds,
|
||||
})
|
||||
}
|
||||
_ => Err(ToolToAIAgentActionError::UnexpectedTool),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user