Fix chat display: restore incremental sync with change detection
sync_from_agent now detects changed entries by comparing token counts (cheap proxy for content changes during streaming). Changed entries get popped and re-pushed. Extracted push_routed/pop_routed helpers. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
31e813f57d
commit
5f5a8a807c
1 changed files with 61 additions and 25 deletions
|
|
@ -456,6 +456,43 @@ impl InteractScreen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_routed(&mut self, node: &AstNode) {
|
||||||
|
for (target, text, marker) in Self::route_node(node) {
|
||||||
|
match target {
|
||||||
|
PaneTarget::Conversation => {
|
||||||
|
self.conversation.current_color = Color::Cyan;
|
||||||
|
self.conversation.append_text(&text);
|
||||||
|
self.conversation.pending_marker = marker;
|
||||||
|
self.conversation.flush_pending();
|
||||||
|
},
|
||||||
|
PaneTarget::ConversationAssistant => {
|
||||||
|
self.conversation.current_color = Color::Reset;
|
||||||
|
self.conversation.append_text(&text);
|
||||||
|
self.conversation.pending_marker = marker;
|
||||||
|
self.conversation.flush_pending();
|
||||||
|
},
|
||||||
|
PaneTarget::Tools =>
|
||||||
|
self.tools.push_line(text, Color::Yellow),
|
||||||
|
PaneTarget::ToolResult => {
|
||||||
|
for line in text.lines().take(20) {
|
||||||
|
self.tools.push_line(format!(" {}", line), Color::DarkGray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_routed(&mut self, node: &AstNode) {
|
||||||
|
for (target, _, _) in Self::route_node(node) {
|
||||||
|
match target {
|
||||||
|
PaneTarget::Conversation | PaneTarget::ConversationAssistant
|
||||||
|
=> self.conversation.pop_line(),
|
||||||
|
PaneTarget::Tools | PaneTarget::ToolResult
|
||||||
|
=> self.tools.pop_line(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn sync_from_agent(&mut self) {
|
fn sync_from_agent(&mut self) {
|
||||||
for _ in 0..self.pending_display_count {
|
for _ in 0..self.pending_display_count {
|
||||||
self.conversation.pop_line();
|
self.conversation.pop_line();
|
||||||
|
|
@ -476,38 +513,37 @@ impl InteractScreen {
|
||||||
(generation, ctx.conversation().to_vec())
|
(generation, ctx.conversation().to_vec())
|
||||||
};
|
};
|
||||||
|
|
||||||
if generation != self.last_generation || entries.len() < self.last_entries.len() {
|
// Full reset on generation change
|
||||||
|
if generation != self.last_generation {
|
||||||
self.conversation = PaneState::new(true);
|
self.conversation = PaneState::new(true);
|
||||||
self.autonomous = PaneState::new(true);
|
self.autonomous = PaneState::new(true);
|
||||||
self.tools = PaneState::new(false);
|
self.tools = PaneState::new(false);
|
||||||
self.last_entries.clear();
|
self.last_entries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = self.last_entries.len();
|
// Detect changed entries (streaming updates mutate the last entry)
|
||||||
for node in entries.iter().skip(start) {
|
// Walk backwards from the end, pop any that differ
|
||||||
for (target, text, marker) in Self::route_node(node) {
|
let mut pop_from = self.last_entries.len();
|
||||||
match target {
|
for i in (0..self.last_entries.len()).rev() {
|
||||||
PaneTarget::Conversation => {
|
if i >= entries.len() {
|
||||||
self.conversation.current_color = Color::Cyan;
|
pop_from = i;
|
||||||
self.conversation.append_text(&text);
|
continue;
|
||||||
self.conversation.pending_marker = marker;
|
|
||||||
self.conversation.flush_pending();
|
|
||||||
},
|
|
||||||
PaneTarget::ConversationAssistant => {
|
|
||||||
self.conversation.current_color = Color::Reset;
|
|
||||||
self.conversation.append_text(&text);
|
|
||||||
self.conversation.pending_marker = marker;
|
|
||||||
self.conversation.flush_pending();
|
|
||||||
},
|
|
||||||
PaneTarget::Tools =>
|
|
||||||
self.tools.push_line(text, Color::Yellow),
|
|
||||||
PaneTarget::ToolResult => {
|
|
||||||
for line in text.lines().take(20) {
|
|
||||||
self.tools.push_line(format!(" {}", line), Color::DarkGray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Compare token count as a cheap change detector
|
||||||
|
if self.last_entries[i].tokens() != entries[i].tokens() {
|
||||||
|
pop_from = i;
|
||||||
|
} else {
|
||||||
|
break; // entries before this haven't changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while self.last_entries.len() > pop_from {
|
||||||
|
let popped = self.last_entries.pop().unwrap();
|
||||||
|
self.pop_routed(&popped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push new/changed entries
|
||||||
|
for node in entries.iter().skip(self.last_entries.len()) {
|
||||||
|
self.push_routed(node);
|
||||||
self.last_entries.push(node.clone());
|
self.last_entries.push(node.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue