simplify compaction: Agent owns config, compact() reloads everything
Agent stores AppConfig and prompt_file, so compact() reloads identity internally — callers no longer pass system_prompt and personality. restore_from_log() loads entries and calls compact(). Remove soft compaction threshold and pre-compaction nudge (journal agent handles this). Remove /compact and /context commands (F10 debug screen replaces both). Inline do_compact, emergency_compact, trim_and_reload into compact(). Rename model_context_window to context_window, drop unused model parameter. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
d419587c1b
commit
af3929cc65
2 changed files with 53 additions and 179 deletions
|
|
@ -38,18 +38,11 @@ use poc_memory::agent::tui::HotkeyAction;
|
|||
use poc_memory::config::{self, AppConfig, SessionConfig};
|
||||
use poc_memory::agent::ui_channel::{ContextInfo, StatusInfo, StreamTarget, UiMessage};
|
||||
|
||||
/// Hard compaction threshold — context is rebuilt immediately.
|
||||
/// Uses config percentage of model context window.
|
||||
/// Compaction threshold — context is rebuilt when prompt tokens exceed this.
|
||||
fn compaction_threshold(app: &AppConfig) -> u32 {
|
||||
(poc_memory::thought::context::context_window() as u32) * app.compaction.hard_threshold_pct / 100
|
||||
}
|
||||
|
||||
/// Soft threshold — nudge the model to journal before compaction.
|
||||
/// Fires once; the hard threshold handles the actual rebuild.
|
||||
fn pre_compaction_threshold(app: &AppConfig) -> u32 {
|
||||
(poc_memory::thought::context::context_window() as u32) * app.compaction.soft_threshold_pct / 100
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let cli = cli::CliArgs::parse();
|
||||
|
|
@ -140,7 +133,6 @@ struct Session {
|
|||
last_user_input: Instant,
|
||||
consecutive_errors: u32,
|
||||
last_turn_had_tools: bool,
|
||||
pre_compaction_nudged: bool,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
|
|
@ -172,7 +164,6 @@ impl Session {
|
|||
last_user_input: Instant::now(),
|
||||
consecutive_errors: 0,
|
||||
last_turn_had_tools: false,
|
||||
pre_compaction_nudged: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -280,41 +271,19 @@ impl Session {
|
|||
async fn check_compaction(&mut self) {
|
||||
let mut agent_guard = self.agent.lock().await;
|
||||
let tokens = agent_guard.last_prompt_tokens();
|
||||
let hard = compaction_threshold(&self.config.app);
|
||||
let soft = pre_compaction_threshold(&self.config.app);
|
||||
let threshold = compaction_threshold(&self.config.app);
|
||||
|
||||
if tokens > hard {
|
||||
if tokens > threshold {
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"[compaction: {}K > {}K threshold]",
|
||||
tokens / 1000,
|
||||
hard / 1000,
|
||||
threshold / 1000,
|
||||
)));
|
||||
match config::reload_for_model(&self.config.app, &self.config.prompt_file) {
|
||||
Ok((system_prompt, personality)) => {
|
||||
agent_guard.compact(system_prompt, personality);
|
||||
let _ = self.ui_tx.send(UiMessage::Info(
|
||||
"[compacted — journal + recent messages]".into(),
|
||||
));
|
||||
self.pre_compaction_nudged = false;
|
||||
self.send_context_info();
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"[compaction failed to reload config: {:#}]",
|
||||
e
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else if tokens > soft && !self.pre_compaction_nudged {
|
||||
self.pre_compaction_nudged = true;
|
||||
self.pending_input = Some(
|
||||
"[dmn] Context window is 70% full. Use the journal \
|
||||
tool now to capture anything important from this \
|
||||
session — what happened, what you learned, how you \
|
||||
feel. After you journal, call yield_to_user. \
|
||||
Compaction will rebuild your context shortly."
|
||||
.to_string(),
|
||||
);
|
||||
agent_guard.compact();
|
||||
let _ = self.ui_tx.send(UiMessage::Info(
|
||||
"[compacted — journal + recent messages]".into(),
|
||||
));
|
||||
self.send_context_info();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -376,10 +345,8 @@ impl Session {
|
|||
("/quit", "Exit poc-agent"),
|
||||
("/new", "Start fresh session (saves current)"),
|
||||
("/save", "Save session to disk"),
|
||||
("/compact", "Rebuild context window now"),
|
||||
("/retry", "Re-run last turn"),
|
||||
("/model", "Show/switch model (/model <name>)"),
|
||||
("/context", "Show context window stats"),
|
||||
("/dmn", "Show DMN state"),
|
||||
("/sleep", "Put DMN to sleep"),
|
||||
("/wake", "Wake DMN to foraging"),
|
||||
|
|
@ -418,6 +385,8 @@ impl Session {
|
|||
),
|
||||
self.config.system_prompt.clone(),
|
||||
self.config.context_parts.clone(),
|
||||
self.config.app.clone(),
|
||||
self.config.prompt_file.clone(),
|
||||
new_log,
|
||||
shared_ctx,
|
||||
);
|
||||
|
|
@ -446,65 +415,6 @@ impl Session {
|
|||
}
|
||||
Command::Handled
|
||||
}
|
||||
"/context" => {
|
||||
if let Ok(agent) = self.agent.try_lock() {
|
||||
let msgs = agent.entries();
|
||||
let total_chars: usize =
|
||||
msgs.iter().map(|e| e.message().content_text().len()).sum();
|
||||
let prompt_tokens = agent.last_prompt_tokens();
|
||||
let threshold = compaction_threshold(&self.config.app);
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
" {} messages, ~{} chars",
|
||||
msgs.len(),
|
||||
total_chars
|
||||
)));
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
" dmn state: {}",
|
||||
self.dmn.label()
|
||||
)));
|
||||
if prompt_tokens > 0 {
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
" {} prompt tokens ({:.0}% of {} threshold)",
|
||||
prompt_tokens,
|
||||
(prompt_tokens as f64 / threshold as f64) * 100.0,
|
||||
threshold,
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
let _ = self.ui_tx.send(UiMessage::Info("(busy)".into()));
|
||||
}
|
||||
Command::Handled
|
||||
}
|
||||
"/compact" => {
|
||||
if self.turn_in_progress {
|
||||
let _ = self
|
||||
.ui_tx
|
||||
.send(UiMessage::Info("(turn in progress, please wait)".into()));
|
||||
return Command::Handled;
|
||||
}
|
||||
let mut agent_guard = self.agent.lock().await;
|
||||
let tokens = agent_guard.last_prompt_tokens();
|
||||
match config::reload_for_model(&self.config.app, &self.config.prompt_file) {
|
||||
Ok((system_prompt, personality)) => {
|
||||
agent_guard.compact(system_prompt, personality);
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"[compacted: {} tokens → journal + recent messages]",
|
||||
tokens
|
||||
)));
|
||||
self.send_context_info();
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"[compaction failed: {:#}]",
|
||||
e
|
||||
)));
|
||||
}
|
||||
}
|
||||
self.dmn = dmn::State::Resting {
|
||||
since: Instant::now(),
|
||||
};
|
||||
Command::Handled
|
||||
}
|
||||
"/dmn" => {
|
||||
let _ = self
|
||||
.ui_tx
|
||||
|
|
@ -772,22 +682,12 @@ impl Session {
|
|||
|
||||
if prompt_changed {
|
||||
self.config.prompt_file = resolved.prompt_file.clone();
|
||||
match config::reload_for_model(&self.config.app, &resolved.prompt_file) {
|
||||
Ok((system_prompt, personality)) => {
|
||||
self.config.system_prompt = system_prompt.clone();
|
||||
self.config.context_parts = personality.clone();
|
||||
agent_guard.compact(system_prompt, personality);
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"Switched to {} ({}) — prompt: {}, recompacted",
|
||||
name, resolved.model_id, resolved.prompt_file,
|
||||
)));
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"Switched model but failed to reload prompts: {:#}", e,
|
||||
)));
|
||||
}
|
||||
}
|
||||
agent_guard.prompt_file = resolved.prompt_file.clone();
|
||||
agent_guard.compact();
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"Switched to {} ({}) — prompt: {}, recompacted",
|
||||
name, resolved.model_id, resolved.prompt_file,
|
||||
)));
|
||||
} else {
|
||||
let _ = self.ui_tx.send(UiMessage::Info(format!(
|
||||
"Switched to {} ({})",
|
||||
|
|
@ -900,6 +800,8 @@ async fn run(cli: cli::CliArgs) -> Result<()> {
|
|||
client,
|
||||
config.system_prompt.clone(),
|
||||
config.context_parts.clone(),
|
||||
config.app.clone(),
|
||||
config.prompt_file.clone(),
|
||||
Some(conversation_log),
|
||||
shared_context,
|
||||
)));
|
||||
|
|
@ -911,10 +813,7 @@ async fn run(cli: cli::CliArgs) -> Result<()> {
|
|||
// Restore conversation from the append-only log
|
||||
{
|
||||
let mut agent_guard = agent.lock().await;
|
||||
if agent_guard.restore_from_log(
|
||||
config.system_prompt.clone(),
|
||||
config.context_parts.clone(),
|
||||
) {
|
||||
if agent_guard.restore_from_log() {
|
||||
replay_session_to_ui(agent_guard.entries(), &ui_tx);
|
||||
let _ = ui_tx.send(UiMessage::Info(
|
||||
"--- restored from conversation log ---".into(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue