Compare commits

...

1 Commits

Author SHA1 Message Date
Owen Lin
195dc38d41 fix(app-server): add stdout and stderr to FileChange items 2025-12-04 11:56:53 -08:00
3 changed files with 45 additions and 2 deletions

View File

@@ -1126,6 +1126,10 @@ pub enum ThreadItem {
id: String,
changes: Vec<FileUpdateChange>,
status: PatchApplyStatus,
/// Captured stdout (summary printed by the underlying `apply_patch` tool call).
stdout: Option<String>,
/// Captured stderr (parser errors, IO failures, etc.).
stderr: Option<String>,
},
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]

View File

@@ -136,6 +136,8 @@ pub(crate) async fn apply_bespoke_event_handling(
id: item_id.clone(),
changes: patch_changes.clone(),
status: PatchApplyStatus::InProgress,
stdout: None,
stderr: None,
};
let notification = ItemStartedNotification {
thread_id: conversation_id.to_string(),
@@ -462,6 +464,8 @@ pub(crate) async fn apply_bespoke_event_handling(
id: item_id.clone(),
changes: convert_patch_changes(&patch_begin_event.changes),
status: PatchApplyStatus::InProgress,
stdout: None,
stderr: None,
};
let notification = ItemStartedNotification {
thread_id: conversation_id.to_string(),
@@ -489,6 +493,8 @@ pub(crate) async fn apply_bespoke_event_handling(
item_id,
changes,
status,
Some(patch_end_event.stdout),
Some(patch_end_event.stderr),
event_turn_id.clone(),
outgoing.as_ref(),
&turn_summary_store,
@@ -738,11 +744,14 @@ async fn emit_turn_completed_with_status(
.await;
}
#[allow(clippy::too_many_arguments)]
async fn complete_file_change_item(
conversation_id: ConversationId,
item_id: String,
changes: Vec<FileUpdateChange>,
status: PatchApplyStatus,
stdout: Option<String>,
stderr: Option<String>,
turn_id: String,
outgoing: &OutgoingMessageSender,
turn_summary_store: &TurnSummaryStore,
@@ -758,6 +767,8 @@ async fn complete_file_change_item(
id: item_id,
changes,
status,
stdout,
stderr,
};
let notification = ItemCompletedNotification {
thread_id: conversation_id.to_string(),
@@ -1068,6 +1079,8 @@ async fn on_file_change_request_approval_response(
item_id,
changes,
status,
None,
None,
event_turn_id.clone(),
outgoing.as_ref(),
&turn_summary_store,

View File

@@ -688,12 +688,16 @@ async fn turn_start_file_change_approval_v2() -> Result<()> {
ref id,
status,
ref changes,
stdout,
stderr,
} = started_file_change
else {
unreachable!("loop ensures we break on file change items");
};
assert_eq!(id, "patch-call");
assert_eq!(status, PatchApplyStatus::InProgress);
assert!(stdout.is_none());
assert!(stderr.is_none());
let started_changes = changes.clone();
let server_req = timeout(
@@ -763,11 +767,20 @@ async fn turn_start_file_change_approval_v2() -> Result<()> {
}
})
.await??;
let ThreadItem::FileChange { ref id, status, .. } = completed_file_change else {
let ThreadItem::FileChange {
ref id,
status,
stdout,
stderr,
..
} = completed_file_change
else {
unreachable!("loop ensures we break on file change items");
};
assert_eq!(id, "patch-call");
assert_eq!(status, PatchApplyStatus::Completed);
assert!(stdout.is_some());
assert!(stderr.is_some());
timeout(
DEFAULT_READ_TIMEOUT,
@@ -854,12 +867,16 @@ async fn turn_start_file_change_approval_decline_v2() -> Result<()> {
ref id,
status,
ref changes,
stdout,
stderr,
} = started_file_change
else {
unreachable!("loop ensures we break on file change items");
};
assert_eq!(id, "patch-call");
assert_eq!(status, PatchApplyStatus::InProgress);
assert!(stdout.is_none());
assert!(stderr.is_none());
let started_changes = changes.clone();
let server_req = timeout(
@@ -909,11 +926,20 @@ async fn turn_start_file_change_approval_decline_v2() -> Result<()> {
}
})
.await??;
let ThreadItem::FileChange { ref id, status, .. } = completed_file_change else {
let ThreadItem::FileChange {
ref id,
status,
stdout,
stderr,
..
} = completed_file_change
else {
unreachable!("loop ensures we break on file change items");
};
assert_eq!(id, "patch-call");
assert_eq!(status, PatchApplyStatus::Declined);
assert!(stdout.is_none());
assert!(stderr.is_none());
timeout(
DEFAULT_READ_TIMEOUT,