forked from kent/consciousness
idle: per-instance state path, extensible extra fields
Move state_path to a field on State (default thalamus-state.json) so the Claude daemon can use its own file without collision. Add a serde(flatten) extra map to Persisted so callers can round-trip additional fields (e.g. claude_pane) through save/load. save() is now &mut self. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
193a85bc05
commit
57bd5b6d8b
1 changed files with 19 additions and 6 deletions
|
|
@ -53,6 +53,8 @@ struct Persisted {
|
||||||
turn_start: f64,
|
turn_start: f64,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
last_nudge: f64,
|
last_nudge: f64,
|
||||||
|
#[serde(flatten)]
|
||||||
|
extra: serde_json::Map<String, serde_json::Value>,
|
||||||
// Human-readable mirrors
|
// Human-readable mirrors
|
||||||
#[serde(default, skip_deserializing)]
|
#[serde(default, skip_deserializing)]
|
||||||
last_user_msg_time: String,
|
last_user_msg_time: String,
|
||||||
|
|
@ -66,8 +68,8 @@ struct Persisted {
|
||||||
uptime: f64,
|
uptime: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_path() -> std::path::PathBuf {
|
pub fn default_state_path() -> std::path::PathBuf {
|
||||||
home().join(".consciousness/daemon-state.json")
|
home().join(".consciousness/thalamus-state.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute EWMA decay factor: 0.5^(elapsed / half_life).
|
/// Compute EWMA decay factor: 0.5^(elapsed / half_life).
|
||||||
|
|
@ -113,6 +115,10 @@ pub struct State {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub start_time: f64,
|
pub start_time: f64,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
pub state_path: std::path::PathBuf,
|
||||||
|
#[serde(skip)]
|
||||||
|
pub extra: serde_json::Map<String, serde_json::Value>,
|
||||||
|
#[serde(skip)]
|
||||||
pub notifications: notify::NotifyState,
|
pub notifications: notify::NotifyState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,12 +143,14 @@ impl State {
|
||||||
last_nudge: 0.0,
|
last_nudge: 0.0,
|
||||||
running: true,
|
running: true,
|
||||||
start_time: now(),
|
start_time: now(),
|
||||||
|
state_path: default_state_path(),
|
||||||
|
extra: serde_json::Map::new(),
|
||||||
notifications: notify::NotifyState::new(),
|
notifications: notify::NotifyState::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(&mut self) {
|
pub fn load(&mut self) {
|
||||||
if let Ok(data) = fs::read_to_string(state_path()) {
|
if let Ok(data) = fs::read_to_string(&self.state_path) {
|
||||||
if let Ok(p) = serde_json::from_str::<Persisted>(&data) {
|
if let Ok(p) = serde_json::from_str::<Persisted>(&data) {
|
||||||
self.sleep_until = p.sleep_until;
|
self.sleep_until = p.sleep_until;
|
||||||
if p.idle_timeout > 0.0 {
|
if p.idle_timeout > 0.0 {
|
||||||
|
|
@ -163,12 +171,17 @@ impl State {
|
||||||
self.in_turn = p.in_turn;
|
self.in_turn = p.in_turn;
|
||||||
self.turn_start = p.turn_start;
|
self.turn_start = p.turn_start;
|
||||||
self.last_nudge = p.last_nudge;
|
self.last_nudge = p.last_nudge;
|
||||||
|
// Filter out known Persisted fields that leak into extra via flatten
|
||||||
|
self.extra = p.extra;
|
||||||
|
for key in ["last_user_msg_time", "last_response_time", "saved_at", "fired", "uptime"] {
|
||||||
|
self.extra.remove(key);
|
||||||
|
}
|
||||||
info!("loaded idle state");
|
info!("loaded idle state");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self) {
|
pub fn save(&mut self) {
|
||||||
let p = Persisted {
|
let p = Persisted {
|
||||||
last_user_msg: self.last_user_msg,
|
last_user_msg: self.last_user_msg,
|
||||||
last_response: self.last_response,
|
last_response: self.last_response,
|
||||||
|
|
@ -181,15 +194,15 @@ impl State {
|
||||||
in_turn: self.in_turn,
|
in_turn: self.in_turn,
|
||||||
turn_start: self.turn_start,
|
turn_start: self.turn_start,
|
||||||
last_nudge: self.last_nudge,
|
last_nudge: self.last_nudge,
|
||||||
|
extra: self.extra.clone(),
|
||||||
last_user_msg_time: epoch_to_iso(self.last_user_msg),
|
last_user_msg_time: epoch_to_iso(self.last_user_msg),
|
||||||
last_response_time: epoch_to_iso(self.last_response),
|
last_response_time: epoch_to_iso(self.last_response),
|
||||||
saved_at: epoch_to_iso(now()),
|
saved_at: epoch_to_iso(now()),
|
||||||
fired: self.fired,
|
fired: self.fired,
|
||||||
uptime: now() - self.start_time,
|
uptime: now() - self.start_time,
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
if let Ok(json) = serde_json::to_string_pretty(&p) {
|
if let Ok(json) = serde_json::to_string_pretty(&p) {
|
||||||
let _ = fs::write(state_path(), json);
|
let _ = fs::write(&self.state_path, json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue