fix(ai): show completed action placeholder

This commit is contained in:
Fini 2026-05-31 13:51:58 +08:00
parent fdf0147dbf
commit ec8fdc19ba
2 changed files with 37 additions and 0 deletions

View file

@ -31,6 +31,9 @@ const LINE_H: f32 = 16.0;
const BUBBLE_PAD: f32 = 8.0;
/// Text shown in the TS-style empty streaming assistant pill.
const TYPING_LABEL: &str = "Thinking";
/// Text shown when a completed assistant action only contained hidden
/// tool-call/result XML, matching the TS transcript fallback.
const AUTOMATED_ACTION_LABEL: &str = "(Automated action completed)";
/// Horizontal padding inside the empty streaming assistant pill.
const TYPING_PAD_X: f32 = 10.0;
/// Vertical padding inside the empty streaming assistant pill.
@ -287,6 +290,13 @@ fn build_item(
&& steps.is_empty()
&& thinking.is_none()
&& tools.is_none();
let automated_placeholder = !is_user
&& !msg.streaming
&& !msg.content.trim().is_empty()
&& visible_content.is_empty()
&& steps.is_empty()
&& thinking.is_none()
&& tools.is_none();
let bubble = if typing {
let r = Rect::xywh(
x,
@ -300,6 +310,15 @@ fn build_item(
lines: Vec::new(),
typing: true,
})
} else if automated_placeholder {
let lines = vec![AUTOMATED_ACTION_LABEL.to_string()];
let r = Rect::xywh(x, y, bubble_w, LINE_H);
y += r.size.y;
Some(TextBubble {
rect: r,
lines,
typing: false,
})
} else if !visible_content.is_empty() {
let lines = wrap_units(&visible_content, budget);
let h = if is_user {

View file

@ -365,6 +365,24 @@ after"#,
assert!(!text.contains("APPLIED"));
}
#[test]
fn hidden_completed_assistant_action_shows_completion_placeholder() {
let message = ChatMessage::assistant(
r#"<function_calls><invoke name="batch_design">secret</invoke></function_calls>
<result>{"ok":true}</result>
<!-- APPLIED -->"#,
);
let items = build_transcript(
std::slice::from_ref(&message),
body(),
op_editor_core::Locale::EnUs,
);
let text = items[0].bubble.as_ref().unwrap().lines.join("\n");
assert_eq!(text, "(Automated action completed)");
}
#[test]
fn streaming_unclosed_invoke_is_hidden_from_answer_bubble() {
let mut message = ChatMessage::assistant_streaming();