mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
feat(compaction): surface checkpoint warning
This commit is contained in:
@@ -12,6 +12,7 @@ use crate::error::Result as CodexResult;
|
||||
use crate::protocol::AgentMessageEvent;
|
||||
use crate::protocol::ErrorEvent;
|
||||
use crate::protocol::EventMsg;
|
||||
use code_protocol::protocol::CompactionCheckpointWarningEvent;
|
||||
use crate::protocol::InputItem;
|
||||
use crate::protocol::TaskCompleteEvent;
|
||||
use crate::truncate::truncate_middle;
|
||||
@@ -28,6 +29,7 @@ use base64::Engine;
|
||||
use futures::prelude::*;
|
||||
|
||||
pub const SUMMARIZATION_PROMPT: &str = include_str!("../../templates/compact/prompt.md");
|
||||
pub const COMPACTION_CHECKPOINT_MESSAGE: &str = "History checkpoint: earlier conversation compacted.";
|
||||
const COMPACT_USER_MESSAGE_MAX_TOKENS: usize = 20_000;
|
||||
const COMPACT_TEXT_CONTENT_MAX_BYTES: usize = 8 * 1024;
|
||||
const COMPACT_TOOL_ARGS_MAX_BYTES: usize = 4 * 1024;
|
||||
@@ -199,6 +201,8 @@ pub(super) async fn perform_compaction(
|
||||
state.history.record_items(new_history.iter());
|
||||
}
|
||||
|
||||
send_compaction_checkpoint_warning(&sess, &sub_id).await;
|
||||
|
||||
let rollout_item = RolloutItem::Compacted(CompactedItem {
|
||||
message: summary_text.clone(),
|
||||
});
|
||||
@@ -305,6 +309,8 @@ async fn run_compact_task_inner_inline(
|
||||
state.history.record_items(new_history.iter());
|
||||
}
|
||||
|
||||
send_compaction_checkpoint_warning(&sess, &sub_id).await;
|
||||
|
||||
let rollout_item = RolloutItem::Compacted(CompactedItem {
|
||||
message: summary_text.clone(),
|
||||
});
|
||||
@@ -449,6 +455,17 @@ fn sanitize_items_for_compact(items: Vec<ResponseItem>) -> Vec<ResponseItem> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn compaction_checkpoint_warning_event() -> EventMsg {
|
||||
EventMsg::CompactionCheckpointWarning(CompactionCheckpointWarningEvent {
|
||||
message: COMPACTION_CHECKPOINT_MESSAGE.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn send_compaction_checkpoint_warning(sess: &Arc<Session>, sub_id: &str) {
|
||||
let event = sess.make_event(sub_id, compaction_checkpoint_warning_event());
|
||||
sess.send_event(event).await;
|
||||
}
|
||||
|
||||
pub(crate) fn collect_user_messages(items: &[ResponseItem]) -> Vec<String> {
|
||||
items
|
||||
.iter()
|
||||
@@ -729,4 +746,14 @@ mod tests {
|
||||
"bridge should include the provided summary text"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compaction_checkpoint_warning_event_has_copy() {
|
||||
match compaction_checkpoint_warning_event() {
|
||||
EventMsg::CompactionCheckpointWarning(payload) => {
|
||||
assert!(payload.message.contains("checkpoint"));
|
||||
}
|
||||
other => panic!("unexpected variant: {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,6 +723,9 @@ pub enum EventMsg {
|
||||
/// Browser snapshot metadata emitted alongside environment context.
|
||||
BrowserSnapshot(BrowserSnapshotEvent),
|
||||
|
||||
/// Warning that the platform compacted conversation history to stay within limits.
|
||||
CompactionCheckpointWarning(code_protocol::protocol::CompactionCheckpointWarningEvent),
|
||||
|
||||
/// Ack the client's configure message.
|
||||
SessionConfigured(SessionConfiguredEvent),
|
||||
|
||||
|
||||
@@ -618,6 +618,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
|
||||
EventMsg::UserMessage(_) => {}
|
||||
EventMsg::EnteredReviewMode(_) => {}
|
||||
EventMsg::ExitedReviewMode(_) => {}
|
||||
EventMsg::CompactionCheckpointWarning(_) => {}
|
||||
}
|
||||
CodexStatus::Running
|
||||
}
|
||||
|
||||
@@ -290,6 +290,7 @@ async fn run_code_tool_session_inner(
|
||||
| EventMsg::EnvironmentContextFull(_)
|
||||
| EventMsg::EnvironmentContextDelta(_)
|
||||
| EventMsg::AgentStatusUpdate(_)
|
||||
| EventMsg::CompactionCheckpointWarning(_)
|
||||
| EventMsg::TurnAborted(_)
|
||||
| EventMsg::ConversationPath(_)
|
||||
| EventMsg::UserMessage(_)
|
||||
|
||||
@@ -538,6 +538,9 @@ pub enum EventMsg {
|
||||
/// Browser snapshot metadata emitted alongside environment context.
|
||||
BrowserSnapshot(BrowserSnapshotEvent),
|
||||
|
||||
/// Warning that the platform compacted conversation history to stay within limits.
|
||||
CompactionCheckpointWarning(CompactionCheckpointWarningEvent),
|
||||
|
||||
/// Ack the client's configure message.
|
||||
SessionConfigured(SessionConfiguredEvent),
|
||||
|
||||
@@ -626,6 +629,11 @@ pub struct TaskStartedEvent {
|
||||
pub model_context_window: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS)]
|
||||
pub struct CompactionCheckpointWarningEvent {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize, TS)]
|
||||
pub struct TokenUsage {
|
||||
pub input_tokens: u64,
|
||||
@@ -1507,4 +1515,23 @@ mod tests {
|
||||
assert_eq!(deserialized, event);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compaction_checkpoint_warning_round_trips() -> Result<()> {
|
||||
let event = EventMsg::CompactionCheckpointWarning(CompactionCheckpointWarningEvent {
|
||||
message: "History checkpoint: earlier conversation compacted.".to_string(),
|
||||
});
|
||||
|
||||
let serialized = serde_json::to_string(&event)?;
|
||||
let restored: EventMsg = serde_json::from_str(&serialized)?;
|
||||
|
||||
match restored {
|
||||
EventMsg::CompactionCheckpointWarning(payload) => {
|
||||
assert!(payload.message.contains("checkpoint"));
|
||||
}
|
||||
other => panic!("unexpected variant: {other:?}"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ use code_core::protocol::PatchApplyEndEvent;
|
||||
use code_core::protocol::TaskCompleteEvent;
|
||||
use code_core::protocol::TokenUsage;
|
||||
use code_core::protocol::TurnDiffEvent;
|
||||
use code_core::codex::compact::COMPACTION_CHECKPOINT_MESSAGE;
|
||||
use crate::bottom_pane::{
|
||||
AutoActiveViewModel,
|
||||
AutoCoordinatorButton,
|
||||
@@ -10385,6 +10386,9 @@ impl ChatWidget<'_> {
|
||||
EventMsg::BrowserSnapshot(ev) => {
|
||||
self.handle_browser_snapshot_event(&ev);
|
||||
}
|
||||
EventMsg::CompactionCheckpointWarning(event) => {
|
||||
self.history_push_plain_paragraphs(PlainMessageKind::Notice, [event.message]);
|
||||
}
|
||||
EventMsg::SessionConfigured(event) => {
|
||||
// Remove stale "Connecting MCP servers…" status from the startup notice
|
||||
// now that MCP initialization has completed in core.
|
||||
@@ -14995,6 +14999,10 @@ Have we met every part of this goal and is there no further work to do?"#
|
||||
self.auto_history.replace_all(conversation.clone());
|
||||
self.auto_compaction_overlay =
|
||||
self.derive_compaction_overlay(&previous_items, &previous_indices, &conversation);
|
||||
self.history_push_plain_paragraphs(
|
||||
PlainMessageKind::Notice,
|
||||
[COMPACTION_CHECKPOINT_MESSAGE],
|
||||
);
|
||||
self.auto_rebuild_live_ring();
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
---
|
||||
source: tui/tests/vt100_chatwidget_snapshot.rs
|
||||
assertion_line: 2006
|
||||
expression: frame
|
||||
---
|
||||
+----------------------------------------------------------------------------+
|
||||
| Code |
|
||||
+----------------------------------------------------------------------------+
|
||||
|
||||
|
||||
|
||||
• I can help with various tasks including:
|
||||
|
||||
- Writing code
|
||||
- Reading files
|
||||
- Running commands
|
||||
|
||||
|
||||
★ History checkpoint: earlier conversation compacted.
|
||||
|
||||
+----------------------------------------------------------------------------+
|
||||
| What can I code for you today? |
|
||||
+----------------------------------------------------------------------------+
|
||||
Read Only (Shift+Tab change) Ctrl+H help • API key
|
||||
@@ -32,6 +32,8 @@ use code_tui::test_helpers::{
|
||||
AutoContinueModeFixture,
|
||||
ChatWidgetHarness,
|
||||
};
|
||||
use code_core::codex::compact::COMPACTION_CHECKPOINT_MESSAGE;
|
||||
use code_protocol::protocol::CompactionCheckpointWarningEvent;
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
|
||||
use regex_lite::{Captures, Regex};
|
||||
use serde_json::json;
|
||||
@@ -1986,6 +1988,24 @@ fn settings_help_overlay_from_section() {
|
||||
insta::assert_snapshot!("settings_help_overlay_section_closed", section_closed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compaction_checkpoint_warning_notice() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
let mut harness = ChatWidgetHarness::new();
|
||||
|
||||
harness.handle_event(Event {
|
||||
id: "compaction-warning".into(),
|
||||
event_seq: 0,
|
||||
msg: EventMsg::CompactionCheckpointWarning(CompactionCheckpointWarningEvent {
|
||||
message: COMPACTION_CHECKPOINT_MESSAGE.to_string(),
|
||||
}),
|
||||
order: None,
|
||||
});
|
||||
|
||||
let frame = normalize_output(render_chat_widget_to_vt100(&mut harness, 80, 20));
|
||||
insta::assert_snapshot!("compaction_checkpoint_warning_notice", frame);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agent_status_missing_batch_displays_error() {
|
||||
let mut harness = ChatWidgetHarness::new();
|
||||
|
||||
Reference in New Issue
Block a user