Unconscious agents: 60s idle timer, no cooldown
Gate unconscious agents on 60s of no conscious activity using sleep_until() instead of polling. Remove COOLDOWN constant — once idle, agents run back-to-back to keep the GPU busy. Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
This commit is contained in:
parent
eae8d92918
commit
707f836ca0
2 changed files with 31 additions and 13 deletions
|
|
@ -526,6 +526,8 @@ impl Mind {
|
||||||
.expect("Mind::run() called twice");
|
.expect("Mind::run() called twice");
|
||||||
let mut sub_handle: Option<tokio::task::JoinHandle<()>> = None;
|
let mut sub_handle: Option<tokio::task::JoinHandle<()>> = None;
|
||||||
let mut unc_handle: Option<tokio::task::JoinHandle<()>> = None;
|
let mut unc_handle: Option<tokio::task::JoinHandle<()>> = None;
|
||||||
|
let mut unc_idle_deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(60);
|
||||||
|
let mut unc_idle = false;
|
||||||
loop {
|
loop {
|
||||||
let (timeout, has_input) = {
|
let (timeout, has_input) = {
|
||||||
let me = self.shared.lock().unwrap();
|
let me = self.shared.lock().unwrap();
|
||||||
|
|
@ -553,7 +555,13 @@ impl Mind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = tokio::time::sleep_until(unc_idle_deadline), if !unc_idle && !self.config.no_agents => {
|
||||||
|
unc_idle = true;
|
||||||
|
}
|
||||||
|
|
||||||
Some((result, target)) = turn_rx.recv() => {
|
Some((result, target)) = turn_rx.recv() => {
|
||||||
|
unc_idle_deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(60);
|
||||||
|
unc_idle = false;
|
||||||
let model_switch = {
|
let model_switch = {
|
||||||
let mut s = self.shared.lock().unwrap();
|
let mut s = self.shared.lock().unwrap();
|
||||||
s.turn_handle = None;
|
s.turn_handle = None;
|
||||||
|
|
@ -584,7 +592,7 @@ impl Mind {
|
||||||
s.trigger(&agent).await;
|
s.trigger(&agent).await;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if unc_handle.as_ref().map_or(true, |h| h.is_finished()) {
|
if unc_idle && unc_handle.as_ref().map_or(true, |h| h.is_finished()) {
|
||||||
let unc = self.unconscious.clone();
|
let unc = self.unconscious.clone();
|
||||||
unc_handle = Some(tokio::spawn(async move {
|
unc_handle = Some(tokio::spawn(async move {
|
||||||
unc.lock().await.trigger().await;
|
unc.lock().await.trigger().await;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
//
|
//
|
||||||
// Standalone agents that operate on the memory graph without needing
|
// Standalone agents that operate on the memory graph without needing
|
||||||
// conversation context. Each agent runs in a loop: finish one run,
|
// conversation context. Each agent runs in a loop: finish one run,
|
||||||
// wait a cooldown, start the next. Agents can be toggled on/off,
|
// start the next. Agents can be toggled on/off, persisted to
|
||||||
// persisted to ~/.consciousness/agent-enabled.json.
|
// ~/.consciousness/agent-enabled.json.
|
||||||
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Instant;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
|
||||||
|
|
@ -13,9 +13,6 @@ use crate::agent::oneshot::{AutoAgent, AutoStep};
|
||||||
use crate::agent::tools;
|
use crate::agent::tools;
|
||||||
use crate::subconscious::defs;
|
use crate::subconscious::defs;
|
||||||
|
|
||||||
/// Cooldown between consecutive runs of the same agent.
|
|
||||||
const COOLDOWN: Duration = Duration::from_secs(120);
|
|
||||||
|
|
||||||
fn config_path() -> std::path::PathBuf {
|
fn config_path() -> std::path::PathBuf {
|
||||||
dirs::home_dir().unwrap_or_default()
|
dirs::home_dir().unwrap_or_default()
|
||||||
.join(".consciousness/agent-enabled.json")
|
.join(".consciousness/agent-enabled.json")
|
||||||
|
|
@ -50,11 +47,7 @@ impl UnconsciousAgent {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_run(&self) -> bool {
|
fn should_run(&self) -> bool {
|
||||||
if !self.enabled || self.is_running() { return false; }
|
self.enabled && !self.is_running()
|
||||||
match self.last_run {
|
|
||||||
Some(t) => t.elapsed() >= COOLDOWN,
|
|
||||||
None => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +160,7 @@ impl Unconscious {
|
||||||
pub async fn trigger(&mut self) {
|
pub async fn trigger(&mut self) {
|
||||||
// Periodic graph health refresh (also on first call)
|
// Periodic graph health refresh (also on first call)
|
||||||
if self.last_health_check
|
if self.last_health_check
|
||||||
.map(|t| t.elapsed() > Duration::from_secs(600))
|
.map(|t| t.elapsed() > std::time::Duration::from_secs(600))
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
self.refresh_health();
|
self.refresh_health();
|
||||||
|
|
@ -299,8 +292,25 @@ impl Unconscious {
|
||||||
|
|
||||||
self.agents[idx].handle = Some(tokio::spawn(async move {
|
self.agents[idx].handle = Some(tokio::spawn(async move {
|
||||||
let result = auto.run_shared(&agent).await;
|
let result = auto.run_shared(&agent).await;
|
||||||
|
save_agent_log(&auto.name, &agent).await;
|
||||||
auto.steps = orig_steps;
|
auto.steps = orig_steps;
|
||||||
(auto, result)
|
(auto, result)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn save_agent_log(name: &str, agent: &std::sync::Arc<crate::agent::Agent>) {
|
||||||
|
let dir = dirs::home_dir().unwrap_or_default()
|
||||||
|
.join(format!(".consciousness/logs/{}", name));
|
||||||
|
if std::fs::create_dir_all(&dir).is_err() { return; }
|
||||||
|
let ts = chrono::Utc::now().format("%Y%m%d-%H%M%S");
|
||||||
|
let path = dir.join(format!("{}.json", ts));
|
||||||
|
let nodes: Vec<crate::agent::context::AstNode> = {
|
||||||
|
let ctx = agent.context.lock().await;
|
||||||
|
ctx.conversation().to_vec()
|
||||||
|
};
|
||||||
|
if let Ok(json) = serde_json::to_string_pretty(&nodes) {
|
||||||
|
let _ = std::fs::write(&path, json);
|
||||||
|
dbglog!("[unconscious] saved log to {}", path.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue