first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -1,27 +1,24 @@
|
||||
//! Manages how we serialize blocklist AI data for persistence.
|
||||
#![cfg_attr(not(feature = "local_fs"), allow(dead_code))]
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use uuid::Uuid;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use chrono::{DateTime, Local};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
ai::{
|
||||
agent::{
|
||||
conversation::AIConversationId, AIAgentActionType, AIAgentAttachment, AIAgentContext,
|
||||
AIAgentExchangeId, AIAgentInput, AIAgentPtyWriteMode, AskUserQuestionItem,
|
||||
FileLocations, PassiveSuggestionResultType, ReadFilesRequest,
|
||||
RequestComputerUseRequest, SearchCodebaseRequest, UseComputerRequest, UserQueryMode,
|
||||
},
|
||||
llms::LLMId,
|
||||
},
|
||||
terminal::model::block::{BlockId, SerializedBlock},
|
||||
};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::AIQueryHistoryOutputStatus;
|
||||
use crate::ai::agent::conversation::AIConversationId;
|
||||
use crate::ai::agent::{
|
||||
AIAgentActionType, AIAgentAttachment, AIAgentContext, AIAgentExchangeId, AIAgentInput,
|
||||
AIAgentPtyWriteMode, AskUserQuestionItem, FileLocations, PassiveSuggestionResultType,
|
||||
ReadFilesRequest, RequestComputerUseRequest, SearchCodebaseRequest, UseComputerRequest,
|
||||
UserQueryMode,
|
||||
};
|
||||
use crate::ai::llms::LLMId;
|
||||
use crate::terminal::model::block::{BlockId, SerializedBlock};
|
||||
/// Data we persist for each [`AIAgentExchange`] for use in history. Does not contain output data.
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct PersistedAIInput {
|
||||
@@ -93,7 +90,8 @@ impl TryFrom<&AIAgentInput> for PersistedAIInputType {
|
||||
| AIAgentInput::InvokeSkill { .. }
|
||||
| AIAgentInput::StartFromAmbientRunPrompt { .. }
|
||||
| AIAgentInput::MessagesReceivedFromAgents { .. }
|
||||
| AIAgentInput::EventsFromAgents { .. } => Err(anyhow::anyhow!(
|
||||
| AIAgentInput::EventsFromAgents { .. }
|
||||
| AIAgentInput::OrchestrationConfigUpdate { .. } => Err(anyhow::anyhow!(
|
||||
"This input type is not persisted. Only Query inputs are persisted for up-arrow history."
|
||||
)),
|
||||
}
|
||||
@@ -200,7 +198,8 @@ pub(crate) enum PersistedAIAgentActionType {
|
||||
InitProject,
|
||||
UseComputer {
|
||||
action_summary: String,
|
||||
actions: Vec<computer_use::Action>,
|
||||
#[serde(deserialize_with = "deserialize_targeted_actions")]
|
||||
actions: Vec<computer_use::TargetedAction>,
|
||||
screenshot_params: Option<computer_use::ScreenshotParams>,
|
||||
},
|
||||
RequestComputerUse {
|
||||
@@ -219,6 +218,45 @@ pub(crate) enum PersistedAIAgentActionType {
|
||||
NotPersisted,
|
||||
}
|
||||
|
||||
/// Deserializes the persisted `UseComputer` actions, accepting both the current `{ action, target }`
|
||||
/// shape and the legacy bare-`Action` shape.
|
||||
///
|
||||
/// Conversations persisted before `actions` became `Vec<TargetedAction>` stored each element as a
|
||||
/// bare [`computer_use::Action`]; those decode with the target defaulting to `Target::Screen`. New
|
||||
/// data round-trips unchanged, and serialization still emits the `{ action, target }` shape via the
|
||||
/// derived `Serialize` impl.
|
||||
fn deserialize_targeted_actions<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Vec<computer_use::TargetedAction>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// Accepts either the new `{ action, target }` wrapper (with `target` optional) or a bare legacy
|
||||
// `Action` value. `Action`'s variant names never collide with the `action`/`target` keys, so
|
||||
// the untagged match is unambiguous.
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum TargetedActionCompat {
|
||||
Targeted {
|
||||
action: computer_use::Action,
|
||||
#[serde(default)]
|
||||
target: computer_use::Target,
|
||||
},
|
||||
Bare(computer_use::Action),
|
||||
}
|
||||
|
||||
let actions = Vec::<TargetedActionCompat>::deserialize(deserializer)?;
|
||||
Ok(actions
|
||||
.into_iter()
|
||||
.map(|compat| match compat {
|
||||
TargetedActionCompat::Targeted { action, target } => {
|
||||
computer_use::TargetedAction { action, target }
|
||||
}
|
||||
TargetedActionCompat::Bare(action) => computer_use::TargetedAction::screen(action),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
impl From<&AIAgentActionType> for PersistedAIAgentActionType {
|
||||
fn from(value: &AIAgentActionType) -> Self {
|
||||
match value {
|
||||
@@ -319,6 +357,13 @@ impl From<&AIAgentActionType> for PersistedAIAgentActionType {
|
||||
},
|
||||
AIAgentActionType::StartAgent { .. } => Self::NotPersisted,
|
||||
AIAgentActionType::SendMessageToAgent { .. } => Self::NotPersisted,
|
||||
// Orchestrate is rendered from the in-history tool call message;
|
||||
// there is no per-action state we need to persist locally.
|
||||
AIAgentActionType::RunAgents(_) => Self::NotPersisted,
|
||||
// The wait is dropped on restart; the unresolved tool call
|
||||
// stays in the transcript as an orphan until the next
|
||||
// outbound request triggers the server's supersede.
|
||||
AIAgentActionType::WaitForEvents { .. } => Self::NotPersisted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user