Make direct-provider agent runs durable

This commit is contained in:
2026-08-14 22:02:15 -05:00
parent f4a04d0240
commit b079f036fa
50 changed files with 9473 additions and 3189 deletions
+3
View File
@@ -1079,6 +1079,9 @@ pub struct AcpConversationData {
pub struct AgentConversationData {
#[serde(default, skip_serializing_if = "AgentBackend::is_provider")]
pub agent_backend: AgentBackend,
/// Versioned application-owned snapshot for an active direct-provider run.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub active_provider_run_json: Option<String>,
pub server_conversation_token: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub conversation_usage_metadata: Option<ConversationUsageMetadata>,
+31
View File
@@ -137,6 +137,7 @@ fn is_restorable_accepts_empty_and_single_task_conversations() {
fn agent_conversation_data_roundtrips_last_event_sequence() {
let data = AgentConversationData {
agent_backend: Default::default(),
active_provider_run_json: None,
server_conversation_token: None,
conversation_usage_metadata: None,
reverted_action_ids: None,
@@ -181,6 +182,31 @@ fn agent_conversation_data_defaults_legacy_rows_to_provider_backend() {
assert_eq!(data.agent_backend, AgentBackend::Provider);
}
#[test]
fn agent_conversation_data_defaults_legacy_rows_without_provider_run_snapshot() {
let data: AgentConversationData = serde_json::from_str(r#"{"server_conversation_token":null}"#)
.expect("legacy rows must deserialize");
assert_eq!(data.active_provider_run_json, None);
}
#[test]
fn agent_conversation_data_roundtrips_provider_run_snapshot() {
let snapshot = r#"{"version":1,"run_id":"run-1"}"#;
let data = AgentConversationData {
active_provider_run_json: Some(snapshot.to_string()),
..Default::default()
};
let json = serde_json::to_string(&data).expect("serialize");
let roundtripped: AgentConversationData = serde_json::from_str(&json).expect("deserialize");
assert_eq!(
roundtripped.active_provider_run_json.as_deref(),
Some(snapshot)
);
}
#[test]
fn agent_conversation_data_roundtrips_acp_backend() {
let data = AgentConversationData {
@@ -214,6 +240,7 @@ fn agent_conversation_data_omits_default_provider_backend() {
fn agent_conversation_data_roundtrips_remote_child_marker() {
let data = AgentConversationData {
agent_backend: Default::default(),
active_provider_run_json: None,
server_conversation_token: None,
conversation_usage_metadata: None,
reverted_action_ids: None,
@@ -241,6 +268,7 @@ fn agent_conversation_data_roundtrips_remote_child_marker() {
fn agent_conversation_data_roundtrips_optimistic_root_marker() {
let data = AgentConversationData {
agent_backend: Default::default(),
active_provider_run_json: None,
server_conversation_token: None,
conversation_usage_metadata: None,
reverted_action_ids: None,
@@ -280,6 +308,7 @@ fn agent_conversation_data_deserializes_legacy_payload_without_last_event_sequen
fn agent_conversation_data_skips_serializing_none_last_event_sequence() {
let data = AgentConversationData {
agent_backend: Default::default(),
active_provider_run_json: None,
server_conversation_token: None,
conversation_usage_metadata: None,
reverted_action_ids: None,
@@ -309,6 +338,7 @@ fn agent_conversation_data_skips_serializing_none_last_event_sequence() {
fn agent_conversation_data_roundtrips_pinned() {
let data = AgentConversationData {
agent_backend: Default::default(),
active_provider_run_json: None,
server_conversation_token: None,
conversation_usage_metadata: None,
reverted_action_ids: None,
@@ -336,6 +366,7 @@ fn agent_conversation_data_roundtrips_pinned() {
fn agent_conversation_data_skips_serializing_unpinned() {
let data = AgentConversationData {
agent_backend: Default::default(),
active_provider_run_json: None,
server_conversation_token: None,
conversation_usage_metadata: None,
reverted_action_ids: None,