unify conversation persistence to append-only jsonl
Log ConversationEntry (with Memory/Message typing) instead of raw Message. restore_from_log reads typed entries directly, preserving Memory vs Message distinction across restarts. Remove current.json snapshot and save_session — the append-only log is the single source of truth. Remove dead read_all and message_count methods. Add push_entry for logging typed entries. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
1f7b585d41
commit
a21cf31ad2
3 changed files with 47 additions and 125 deletions
|
|
@ -24,7 +24,6 @@
|
|||
use anyhow::Result;
|
||||
use crossterm::event::{Event, EventStream, KeyEventKind};
|
||||
use futures::StreamExt;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
|
|
@ -124,8 +123,6 @@ struct Session {
|
|||
process_tracker: tools::ProcessTracker,
|
||||
ui_tx: ui_channel::UiSender,
|
||||
turn_tx: mpsc::Sender<(Result<TurnResult>, StreamTarget)>,
|
||||
session_file: PathBuf,
|
||||
|
||||
// DMN state
|
||||
dmn: dmn::State,
|
||||
dmn_turns: u32,
|
||||
|
|
@ -153,7 +150,6 @@ impl Session {
|
|||
process_tracker: tools::ProcessTracker,
|
||||
ui_tx: ui_channel::UiSender,
|
||||
turn_tx: mpsc::Sender<(Result<TurnResult>, StreamTarget)>,
|
||||
session_file: PathBuf,
|
||||
) -> Self {
|
||||
let max_dmn_turns = config.app.dmn.max_turns;
|
||||
|
||||
|
|
@ -163,7 +159,6 @@ impl Session {
|
|||
process_tracker,
|
||||
ui_tx,
|
||||
turn_tx,
|
||||
session_file,
|
||||
dmn: if dmn::is_off() {
|
||||
dmn::State::Off
|
||||
} else {
|
||||
|
|
@ -321,8 +316,6 @@ impl Session {
|
|||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
let _ = save_session(&agent_guard, &self.session_file);
|
||||
}
|
||||
|
||||
/// Send any consolidated pending input as a single turn.
|
||||
|
|
@ -398,14 +391,9 @@ impl Session {
|
|||
match input {
|
||||
"/quit" | "/exit" => Command::Quit,
|
||||
"/save" => {
|
||||
if let Ok(agent) = self.agent.try_lock() {
|
||||
let _ = save_session(&agent, &self.session_file);
|
||||
let _ = self.ui_tx.send(UiMessage::Info("Session saved.".into()));
|
||||
} else {
|
||||
let _ = self
|
||||
.ui_tx
|
||||
.send(UiMessage::Info("(busy — will save after turn)".into()));
|
||||
}
|
||||
let _ = self.ui_tx.send(UiMessage::Info(
|
||||
"Conversation is saved automatically (append-only log).".into()
|
||||
));
|
||||
Command::Handled
|
||||
}
|
||||
"/new" | "/clear" => {
|
||||
|
|
@ -415,10 +403,6 @@ impl Session {
|
|||
.send(UiMessage::Info("(turn in progress, please wait)".into()));
|
||||
return Command::Handled;
|
||||
}
|
||||
{
|
||||
let agent_guard = self.agent.lock().await;
|
||||
let _ = save_session(&agent_guard, &self.session_file);
|
||||
}
|
||||
{
|
||||
let new_log = log::ConversationLog::new(
|
||||
self.config.session_dir.join("conversation.jsonl"),
|
||||
|
|
@ -516,7 +500,6 @@ impl Session {
|
|||
)));
|
||||
}
|
||||
}
|
||||
let _ = save_session(&agent_guard, &self.session_file);
|
||||
self.dmn = dmn::State::Resting {
|
||||
since: Instant::now(),
|
||||
};
|
||||
|
|
@ -861,8 +844,6 @@ impl Session {
|
|||
if let Some(handle) = self.turn_handle.take() {
|
||||
handle.abort();
|
||||
}
|
||||
let agent = self.agent.lock().await;
|
||||
let _ = save_session(&agent, &self.session_file);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -927,29 +908,17 @@ async fn run(cli: cli::CliArgs) -> Result<()> {
|
|||
// so Ctrl+K can kill processes even when the agent is busy.
|
||||
let process_tracker = agent.lock().await.process_tracker.clone();
|
||||
|
||||
// Try to restore from conversation log (primary) or session file (fallback)
|
||||
let session_file = config.session_dir.join("current.json");
|
||||
// Restore conversation from the append-only log
|
||||
{
|
||||
let mut agent_guard = agent.lock().await;
|
||||
let restored = agent_guard.restore_from_log(
|
||||
if agent_guard.restore_from_log(
|
||||
config.system_prompt.clone(),
|
||||
config.context_parts.clone(),
|
||||
);
|
||||
if restored {
|
||||
) {
|
||||
replay_session_to_ui(agent_guard.entries(), &ui_tx);
|
||||
let _ = ui_tx.send(UiMessage::Info(
|
||||
"--- restored from conversation log ---".into(),
|
||||
));
|
||||
} else if session_file.exists() {
|
||||
if let Ok(data) = std::fs::read_to_string(&session_file) {
|
||||
if let Ok(messages) = serde_json::from_str(&data) {
|
||||
agent_guard.restore(messages);
|
||||
replay_session_to_ui(agent_guard.entries(), &ui_tx);
|
||||
let _ = ui_tx.send(UiMessage::Info(
|
||||
"--- restored from session file ---".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -978,7 +947,6 @@ async fn run(cli: cli::CliArgs) -> Result<()> {
|
|||
process_tracker,
|
||||
ui_tx.clone(),
|
||||
turn_tx,
|
||||
session_file,
|
||||
);
|
||||
session.update_status();
|
||||
session.send_context_info();
|
||||
|
|
@ -1103,12 +1071,6 @@ fn drain_ui_messages(rx: &mut ui_channel::UiReceiver, app: &mut tui::App) {
|
|||
}
|
||||
}
|
||||
|
||||
fn save_session(agent: &Agent, path: &PathBuf) -> Result<()> {
|
||||
let data = serde_json::to_string_pretty(agent.entries())?;
|
||||
std::fs::write(path, data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_tool_tests(ui_tx: &ui_channel::UiSender, tracker: &tools::ProcessTracker) {
|
||||
use serde_json::json;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue