feat: moved a2ui surface to a separate panel

This commit is contained in:
Georg Bauer
2026-07-27 12:58:46 +02:00
parent ef1c574a7f
commit f69623ad02
5 changed files with 93 additions and 17 deletions

View File

@@ -149,8 +149,9 @@ fn sync_a2ui_message(
database: &mut Option<Database>,
session_id: Option<i32>,
message: &mut ChatMessage,
) {
) -> bool {
let lines = crate::a2ui::extract_lines(&message.content);
let mut renderable_surface_updated = false;
for (index, line) in lines.iter().enumerate().skip(message.a2ui_lines_processed) {
let applied = match &line.value {
Ok(value) => store.apply(value.clone(), line.raw.clone(), message.id),
@@ -158,6 +159,13 @@ fn sync_a2ui_message(
};
match applied {
Ok(applied) => {
renderable_surface_updated |= line.value.as_ref().is_ok_and(|value| {
crate::a2ui::message_surface_id(value).is_some_and(|id| {
store.active_surface().is_some_and(|surface| {
surface.id == id && surface.components.contains_key("root")
})
})
});
if let Some(reply) = applied.reply {
message.a2ui_replies.push(reply);
}
@@ -185,6 +193,7 @@ fn sync_a2ui_message(
}
message.a2ui_lines_processed = lines.len();
message.refresh_markdown();
renderable_surface_updated
}
#[cfg(target_os = "macos")]
@@ -300,6 +309,7 @@ impl App {
));
return;
}
self.a2ui_auto_switch_pending = true;
#[cfg(target_os = "macos")]
self.tool_cards.clear();
#[cfg(target_os = "macos")]
@@ -617,13 +627,17 @@ impl App {
&& self.config.a2ui_enabled
&& let Some(message) = self.conversation.last_mut()
{
sync_a2ui_message(
let renderable_surface_updated = sync_a2ui_message(
&mut self.a2ui,
&mut self.database,
self.selected_session,
message,
);
a2ui_changed = true;
if self.a2ui_auto_switch_pending && renderable_surface_updated {
self.detail_tab = DetailTab::A2ui;
self.a2ui_auto_switch_pending = false;
}
}
}
Ok(GenerationEvent::Context {
@@ -943,6 +957,9 @@ impl App {
);
let assistant_reasoning = effective.turn.reasoning_mode != ReasoningMode::Direct;
let queued = queued_prompt(self.queued_inputs.drain(..));
if queued.is_some() {
self.a2ui_auto_switch_pending = true;
}
let reminders = if self.system_prompt_reminder_due() {
self.system_prompt_reminders(model)
} else {
@@ -1576,6 +1593,7 @@ mod tests {
use super::{
ChatMessage, TOOL_PROTOCOL_CORRECTION, compacted_context_start, correction_already_sent,
has_chat_after_last_compaction, has_misplaced_tool_call, is_empty_response, queued_prompt,
sync_a2ui_message,
};
use crate::model::ModelChoice;
@@ -1672,6 +1690,36 @@ mod tests {
assert_eq!(rows.len(), 2);
}
#[test]
fn a2ui_auto_switch_waits_for_a_renderable_surface() {
let mut store = crate::a2ui::Store::default();
let mut database = None;
let mut message = assistant(
None,
r#"```a2ui
{"version":"v1.0","createSurface":{"surfaceId":"answer","catalogId":"https://ds4server.local/a2ui/v1_0/catalog.json"}}
```"#,
);
assert!(!sync_a2ui_message(
&mut store,
&mut database,
None,
&mut message
));
message.content = r#"```a2ui
{"version":"v1.0","createSurface":{"surfaceId":"answer","catalogId":"https://ds4server.local/a2ui/v1_0/catalog.json"}}
{"version":"v1.0","updateComponents":{"surfaceId":"answer","components":[{"id":"root","component":"Text","text":"Ready"}]}}
```"#
.to_owned();
assert!(sync_a2ui_message(
&mut store,
&mut database,
None,
&mut message
));
}
#[test]
fn last_compaction_selects_its_tail_without_hiding_history() {
let message = |id: i32, compaction: bool, tail: Option<i32>| ChatMessage {