mind: zero UI dependencies — init() + run() split
Mind::init() restores conversation from log and starts scoring. No UiMessages sent. The UI event loop reads Mind's state after init and displays startup info (model, restored conversation) by reading the agent directly. mind/mod.rs has zero UiMessage imports or sends. Complete separation between cognitive state machine and user interface. Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
3ee1aa69b0
commit
9d597b5eff
2 changed files with 25 additions and 40 deletions
|
|
@ -26,7 +26,7 @@ use crate::agent::{Agent, TurnResult};
|
|||
use crate::agent::api::ApiClient;
|
||||
use crate::config::{self, AppConfig, SessionConfig};
|
||||
use crate::user::{self as tui};
|
||||
use crate::user::ui_channel::{self, StatusInfo, StreamTarget, UiMessage};
|
||||
use crate::user::ui_channel::{self, StreamTarget};
|
||||
use crate::subconscious::learn;
|
||||
|
||||
/// Compaction threshold — context is rebuilt when prompt tokens exceed this.
|
||||
|
|
@ -192,6 +192,17 @@ impl Mind {
|
|||
Self { agent, shared, config, ui_tx, turn_tx, turn_handle: None, turn_watch }
|
||||
}
|
||||
|
||||
/// Initialize — restore conversation from log, start background agents.
|
||||
pub async fn init(&mut self) {
|
||||
let mut ag = self.agent.lock().await;
|
||||
ag.restore_from_log();
|
||||
drop(ag);
|
||||
|
||||
if !self.config.no_agents {
|
||||
self.start_memory_scoring();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn turn_watch(&self) -> tokio::sync::watch::Receiver<bool> {
|
||||
self.turn_watch.subscribe()
|
||||
}
|
||||
|
|
@ -381,23 +392,11 @@ pub async fn run(cli: crate::user::CliArgs) -> Result<()> {
|
|||
let shared_context = ui_channel::shared_context_state();
|
||||
let shared_active_tools = ui_channel::shared_active_tools();
|
||||
|
||||
// Startup info
|
||||
let _ = ui_tx.send(UiMessage::Info("consciousness v0.3 (tui)".into()));
|
||||
let _ = ui_tx.send(UiMessage::Info(format!(
|
||||
" model: {} (available: {})", config.model, config.app.model_names().join(", "),
|
||||
)));
|
||||
let client = ApiClient::new(&config.api_base, &config.api_key, &config.model);
|
||||
let _ = ui_tx.send(UiMessage::Info(format!(" api: {} ({})", config.api_base, client.backend_label())));
|
||||
let _ = ui_tx.send(UiMessage::Info(format!(
|
||||
" context: {}K chars ({} config, {} memory files)",
|
||||
config.context_parts.iter().map(|(_, c)| c.len()).sum::<usize>() / 1024,
|
||||
config.config_file_count, config.memory_file_count,
|
||||
)));
|
||||
|
||||
let conversation_log_path = config.session_dir.join("conversation.jsonl");
|
||||
let conversation_log = log::ConversationLog::new(conversation_log_path.clone())
|
||||
.expect("failed to create conversation log");
|
||||
let _ = ui_tx.send(UiMessage::Info(format!(" log: {}", conversation_log.path().display())));
|
||||
|
||||
let agent = Arc::new(Mutex::new(Agent::new(
|
||||
client,
|
||||
|
|
@ -410,37 +409,12 @@ pub async fn run(cli: crate::user::CliArgs) -> Result<()> {
|
|||
shared_active_tools.clone(),
|
||||
)));
|
||||
|
||||
// Restore conversation from log
|
||||
{
|
||||
let mut agent_guard = agent.lock().await;
|
||||
if agent_guard.restore_from_log() {
|
||||
ui_channel::replay_session_to_ui(agent_guard.entries(), &ui_tx);
|
||||
let _ = ui_tx.send(UiMessage::Info("--- restored from conversation log ---".into()));
|
||||
}
|
||||
}
|
||||
|
||||
// Send initial budget to status bar
|
||||
{
|
||||
let agent_guard = agent.lock().await;
|
||||
let _ = ui_tx.send(UiMessage::StatusUpdate(StatusInfo {
|
||||
dmn_state: "resting".to_string(),
|
||||
dmn_turns: 0, dmn_max_turns: 0,
|
||||
prompt_tokens: 0, completion_tokens: 0,
|
||||
model: agent_guard.model().to_string(),
|
||||
turn_tools: 0,
|
||||
context_budget: agent_guard.budget().status_string(),
|
||||
}));
|
||||
}
|
||||
|
||||
let (turn_tx, turn_rx) = mpsc::channel::<(Result<TurnResult>, StreamTarget)>(1);
|
||||
|
||||
let no_agents = config.no_agents;
|
||||
let shared_mind = shared_mind_state(config.app.dmn.max_turns);
|
||||
crate::user::event_loop::send_context_info(&config, &ui_tx);
|
||||
let mut mind = Mind::new(agent, shared_mind.clone(), config, ui_tx.clone(), turn_tx);
|
||||
if !no_agents {
|
||||
mind.start_memory_scoring();
|
||||
}
|
||||
mind.init().await;
|
||||
|
||||
// Start observation socket
|
||||
let socket_path = mind.config.session_dir.join("agent.sock");
|
||||
|
|
|
|||
|
|
@ -181,7 +181,6 @@ pub async fn run(
|
|||
mut app: tui::App,
|
||||
agent: Arc<Mutex<Agent>>,
|
||||
shared_mind: crate::mind::SharedMindState,
|
||||
|
||||
turn_watch: tokio::sync::watch::Receiver<bool>,
|
||||
mind_tx: tokio::sync::mpsc::UnboundedSender<MindCommand>,
|
||||
ui_tx: ui_channel::UiSender,
|
||||
|
|
@ -202,6 +201,18 @@ pub async fn run(
|
|||
|
||||
terminal.hide_cursor()?;
|
||||
|
||||
// Startup info
|
||||
let _ = ui_tx.send(UiMessage::Info("consciousness v0.3 (tui)".into()));
|
||||
{
|
||||
let ag = agent.lock().await;
|
||||
let _ = ui_tx.send(UiMessage::Info(format!(" model: {}", ag.model())));
|
||||
// Replay restored conversation to UI
|
||||
if !ag.entries().is_empty() {
|
||||
ui_channel::replay_session_to_ui(ag.entries(), &ui_tx);
|
||||
let _ = ui_tx.send(UiMessage::Info("--- restored from conversation log ---".into()));
|
||||
}
|
||||
}
|
||||
|
||||
// Initial render
|
||||
app.drain_messages(&mut ui_rx);
|
||||
terminal.draw(|f| app.draw(f))?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue