diff --git a/crates/op-host-services/src/chat_agent_loop.rs b/crates/op-host-services/src/chat_agent_loop.rs index bd3876ff5..58c587a7a 100644 --- a/crates/op-host-services/src/chat_agent_loop.rs +++ b/crates/op-host-services/src/chat_agent_loop.rs @@ -306,7 +306,8 @@ async fn report_quality_credential( quality: &QualitySummary, remaining: usize, ) { - if let Some(line) = crate::quality_credential::quality_credential_line(quality, Some(remaining)) + if let Some(line) = + crate::quality_credential::quality_credential_line_with_records(quality, Some(remaining)) { let _ = tx.send(ChatDelta::TextDelta(line)).await; } diff --git a/crates/op-host-services/src/chat_agent_loop_tests.rs b/crates/op-host-services/src/chat_agent_loop_tests.rs index a0c05506b..162eefca0 100644 --- a/crates/op-host-services/src/chat_agent_loop_tests.rs +++ b/crates/op-host-services/src/chat_agent_loop_tests.rs @@ -121,6 +121,8 @@ impl ScriptedExecutor { .iter() .map(|(c, n)| ((*c).to_string(), *n)) .collect(), + records: Vec::new(), + notes: Vec::new(), }); self } diff --git a/crates/op-host-services/src/web_chat_standard_events.rs b/crates/op-host-services/src/web_chat_standard_events.rs index 0a628e9be..4d89d2a98 100644 --- a/crates/op-host-services/src/web_chat_standard_events.rs +++ b/crates/op-host-services/src/web_chat_standard_events.rs @@ -110,11 +110,21 @@ pub(super) fn progress_label(p: &Progress) -> String { // The classic path's quality credential. `remaining` is `None` on // purpose: the promise-delivery check runs later in the pipeline, so // claiming anything about leftover work here would be a guess. - Progress::QualityChecked { checks, repairs } => { - crate::quality_credential::quality_credential_line( + Progress::QualityChecked { + checks, + repairs, + records, + notes, + } => { + // `_with_records`: this label is the web host's ONLY channel to + // the user, and it lands in the thinking stream where `▸` + // sub-lines become the credential step's expandable detail. + crate::quality_credential::quality_credential_line_with_records( &op_ai::chat_provider::QualitySummary { checks: checks.clone(), repairs: repairs.clone(), + records: records.clone(), + notes: notes.clone(), }, None, ) diff --git a/crates/op-orchestrator/src/types.rs b/crates/op-orchestrator/src/types.rs index 809347283..e560ba693 100644 --- a/crates/op-orchestrator/src/types.rs +++ b/crates/op-orchestrator/src/types.rs @@ -423,6 +423,16 @@ pub enum Progress { /// `(check family, document edits applied)` for families that /// repaired something. repairs: Vec<(String, usize)>, + /// One already-rendered line per applied edit, in application order + /// (`crate::repair_record::RepairRecord::line`). The itemized half of + /// the same tally `repairs` counts — see `RepairSummary`, where both + /// are derived from one list so they cannot disagree. + records: Vec, + /// Statements about the run that are not edits — today, the + /// deliberate skip of a whole pass tier for authored template input + /// (`crate::repair_tier`). Never counted as repairs; rendered ahead + /// of them, because "this was not run" outranks "this was". + notes: Vec, }, // ── S3c: Vision-validation progress variants ───────────────────────────── /// 视觉校验阶段开始(pre-validation 将在此之后立即运行)。