feat: replay pre-compressed messages as well when resuming sessions for users to see

This commit is contained in:
2026-07-22 13:05:06 -06:00
parent ab0b89dd67
commit c21fd47b42
3 changed files with 71 additions and 125 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ pub use self::request_context::{RenderMode, RequestContext, should_inject_skill_
pub use self::role::{ pub use self::role::{
CODE_ROLE, CREATE_TITLE_ROLE, EXPLAIN_SHELL_ROLE, Role, RoleLike, SHELL_ROLE, CODE_ROLE, CREATE_TITLE_ROLE, EXPLAIN_SHELL_ROLE, Role, RoleLike, SHELL_ROLE,
}; };
use self::session::Session; pub use self::session::Session;
#[allow(unused_imports)] #[allow(unused_imports)]
pub use self::skill::Skill; pub use self::skill::Skill;
#[allow(unused_imports)] #[allow(unused_imports)]
+12 -124
View File
@@ -1,15 +1,13 @@
mod completer; mod completer;
mod highlighter; mod highlighter;
mod prompt; mod prompt;
mod replay;
use self::completer::ReplCompleter; use self::completer::ReplCompleter;
use self::highlighter::ReplHighlighter; use self::highlighter::ReplHighlighter;
use self::prompt::ReplPrompt; use self::prompt::ReplPrompt;
use crate::client::{ use crate::client::{call_chat_completions, call_chat_completions_streaming, init_client, oauth};
Message, MessageRole, call_chat_completions, call_chat_completions_streaming, init_client,
oauth,
};
use crate::config::{ use crate::config::{
AgentVariables, AppConfig, AssertState, Input, LastMessage, RequestContext, StateFlags, AgentVariables, AppConfig, AssertState, Input, LastMessage, RequestContext, StateFlags,
macro_execute, macro_execute,
@@ -362,54 +360,16 @@ Type ".help" for additional help.
} }
{ {
let (messages_snapshot, compressed_count) = { let (compressed, active) = {
let ctx = self.ctx.read(); let ctx = self.ctx.read();
if let Some(session) = &ctx.session { match &ctx.session {
let msgs: Vec<Message> = session Some(session) => replay::snapshot(session),
.messages() None => (Vec::new(), Vec::new()),
.iter()
.filter(|m| !m.role.is_system())
.cloned()
.collect();
let compressed = session.compressed_messages().len();
(msgs, compressed)
} else {
(vec![], 0)
} }
}; };
if !compressed.is_empty() || !active.is_empty() {
if !messages_snapshot.is_empty() || compressed_count > 0 {
let app = Arc::clone(&self.ctx.read().app.config); let app = Arc::clone(&self.ctx.read().app.config);
if compressed_count > 0 { replay::render(app.as_ref(), &compressed, &active)?;
println!(
"{}",
dimmed_text(&format!(
"({compressed_count} earlier messages not shown; compressed for context)"
))
);
println!();
}
for message in &messages_snapshot {
match message.role {
MessageRole::User => {
if let Some(text) = message.content.as_text() {
println!("{}", dimmed_text("You:"));
println!("{text}");
println!();
}
}
MessageRole::Assistant => {
if let Some(text) = message.content.as_text() {
app.print_markdown(text)?;
println!();
}
}
_ => {}
}
}
println!("{}", dimmed_text("─── ↑ previous conversation ↑ ───"));
println!();
} }
} }
@@ -859,44 +819,8 @@ pub async fn run_repl_command(
} }
} }
if let Some(session) = &ctx.session { if let Some(session) = &ctx.session {
let messages_snapshot: Vec<Message> = session let (compressed, active) = replay::snapshot(session);
.messages() replay::render(app.as_ref(), &compressed, &active)?;
.iter()
.filter(|m| !m.role.is_system())
.cloned()
.collect();
let compressed_count = session.compressed_messages().len();
if !messages_snapshot.is_empty() || compressed_count > 0 {
if compressed_count > 0 {
println!(
"{}",
dimmed_text(&format!(
"({compressed_count} earlier messages not shown — compressed for context)"
))
);
println!();
}
for message in &messages_snapshot {
match message.role {
MessageRole::User => {
if let Some(text) = message.content.as_text() {
println!("{}", dimmed_text("You:"));
println!("{text}");
println!();
}
}
MessageRole::Assistant => {
if let Some(text) = message.content.as_text() {
app.print_markdown(text)?;
println!();
}
}
_ => {}
}
}
println!("{}", dimmed_text("─── ↑ previous conversation ↑ ───"));
println!();
}
} }
} }
".install" => { ".install" => {
@@ -953,44 +877,8 @@ pub async fn run_repl_command(
ctx.use_agent(app.as_ref(), agent_name, session_name, abort_signal.clone()) ctx.use_agent(app.as_ref(), agent_name, session_name, abort_signal.clone())
.await?; .await?;
if let Some(session) = &ctx.session { if let Some(session) = &ctx.session {
let messages_snapshot: Vec<Message> = session let (compressed, active) = replay::snapshot(session);
.messages() replay::render(app.as_ref(), &compressed, &active)?;
.iter()
.filter(|m| !m.role.is_system())
.cloned()
.collect();
let compressed_count = session.compressed_messages().len();
if !messages_snapshot.is_empty() || compressed_count > 0 {
if compressed_count > 0 {
println!(
"{}",
dimmed_text(&format!(
"({compressed_count} earlier messages not shown — compressed for context)"
))
);
println!();
}
for message in &messages_snapshot {
match message.role {
MessageRole::User => {
if let Some(text) = message.content.as_text() {
println!("{}", dimmed_text("You:"));
println!("{text}");
println!();
}
}
MessageRole::Assistant => {
if let Some(text) = message.content.as_text() {
app.print_markdown(text)?;
println!();
}
}
_ => {}
}
}
println!("{}", dimmed_text("─── ↑ previous conversation ↑ ───"));
println!();
}
} }
} }
None => { None => {
+58
View File
@@ -0,0 +1,58 @@
use anyhow::Result;
use crate::client::{Message, MessageRole};
use crate::config::{AppConfig, Session};
use crate::utils::dimmed_text;
pub fn snapshot(session: &Session) -> (Vec<Message>, Vec<Message>) {
(
filter_for_display(session.compressed_messages()),
filter_for_display(session.messages()),
)
}
pub fn render(app: &AppConfig, compressed: &[Message], active: &[Message]) -> Result<()> {
if compressed.is_empty() && active.is_empty() {
return Ok(());
}
render_messages(app, compressed)?;
if !compressed.is_empty() && !active.is_empty() {
println!("{}", dimmed_text("─── ↑ pre-compression history ↑ ───"));
println!();
}
render_messages(app, active)?;
println!("{}", dimmed_text("─── ↑ previous conversation ↑ ───"));
println!();
Ok(())
}
fn filter_for_display(messages: &[Message]) -> Vec<Message> {
messages
.iter()
.filter(|m| !m.role.is_system())
.cloned()
.collect()
}
fn render_messages(app: &AppConfig, messages: &[Message]) -> Result<()> {
for message in messages {
match message.role {
MessageRole::User => {
if let Some(text) = message.content.as_text() {
println!("{}", dimmed_text("You:"));
println!("{text}");
println!();
}
}
MessageRole::Assistant => {
if let Some(text) = message.content.as_text() {
app.print_markdown(text)?;
println!();
}
}
_ => {}
}
}
Ok(())
}