memoryd: recall asks Honcho after the local index, outside the state lock

Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
2026-09-29 09:36:43 -07:00
co-authored by ornith-1.5-35b-a3b
parent 6e3e713298
commit 18bafbd2a0
4 changed files with 295 additions and 20 deletions
+16
View File
@@ -24,6 +24,22 @@ pub const SOURCE_WAIT: Duration = Duration::from_secs(5);
/// The line in place of Honcho's items when the query holds a known-prefix secret.
pub const SECRET: &str = "honcho: not asked; the query looks like it holds a secret";
/// What `recall` reads in Honcho: the sources, the owner's peer, and each source's limit
/// (`SOURCE_WAIT` in `memoryd`).
pub struct Reading {
pub readers: Arc<Readers>,
pub owner: String,
pub wait: Duration,
}
impl Reading {
/// `recall`'s answer from the local index's items and Honcho's: `search`, then `answer`.
pub fn recall(&self, local: Local, args: &RecallArgs, log: &Log) -> Recalled {
let searched = search(&self.readers, &self.owner, args, self.wait, log);
answer(local, &args.query, args.k, searched)
}
}
/// What the Honcho part found.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Searched {
+37 -20
View File
@@ -19,6 +19,7 @@ use crate::files::Store;
use crate::honcho::ledger::{self, LedgerError};
use crate::honcho::mirror::Mirror;
use crate::honcho::report;
use crate::honcho::search;
use crate::honcho::state;
use crate::honcho::turns::TurnSync;
use crate::honcho::worker::{self, Wake};
@@ -47,6 +48,8 @@ pub struct Memoryd {
wake: Arc<Wake>,
/// With `[honcho]`: decides memory writes into the ledger, under the ledger's own lock.
mirror: Option<Mirror>,
/// With `[honcho]`: what `recall` reads beside the local index, outside `state`.
reading: Option<search::Reading>,
log: Log,
}
@@ -96,9 +99,12 @@ enum Which {
/// under `memory/` (and, the first time, write when sync began), open the index and catch it up,
/// bind the three sockets, and start the Honcho worker. The error names what failed.
pub fn start(config: Config, log: Log) -> Result<Running, StartError> {
let opened = match config.honcho_config()? {
Some(honcho) => Some(worker::open(&config, &honcho, &log)?),
None => None,
let (opened, owner) = match config.honcho_config()? {
Some(honcho) => (
Some(worker::open(&config, &honcho, &log)?),
honcho.owner.clone(),
),
None => (None, String::new()),
};
let store = Store::new(&config.memory_dir());
store.init(&config.memory.soul_starter)?;
@@ -119,14 +125,19 @@ pub fn start(config: Config, log: Log) -> Result<Running, StartError> {
(admin_listener, Which::Admin),
];
let wake = Arc::new(Wake::default());
let (honcho, mirror) = match opened {
let (honcho, mirror, reading) = match opened {
Some(opened) => {
let sync = Arc::clone(&opened.sync);
let mirror = opened.mirror();
let reading = search::Reading {
readers: Arc::clone(&opened.readers),
owner,
wait: search::SOURCE_WAIT,
};
worker::spawn(opened, &config, Arc::clone(&wake), Arc::clone(&log))?;
(Some(sync), Some(mirror))
(Some(sync), Some(mirror), Some(reading))
}
None => (None, None),
None => (None, None, None),
};
Ok(Running {
memoryd: Arc::new(Memoryd {
@@ -136,6 +147,7 @@ pub fn start(config: Config, log: Log) -> Result<Running, StartError> {
honcho,
wake,
mirror,
reading,
log,
}),
listeners,
@@ -305,13 +317,13 @@ impl Memoryd {
Message::Ok(Empty {})
}
/// A decided call from `brokerd`: `recall` or `memory`, under the one lock. `Failed` carries the
/// sentence for the model.
/// A decided call from `brokerd`: `recall` or `memory`. `memory` runs under the one lock;
/// `recall` takes it for the local index only (`recall`). `Failed` carries the sentence for
/// the model.
fn call(&self, call: MemoryCall) -> ToolResponse {
let state = self.lock();
let result = match call.request.tool.as_str() {
bxcore::memory::RECALL => self.recall(&state, &call),
bxcore::memory::MEMORY => self.memory(&state, &call),
bxcore::memory::RECALL => self.recall(&call),
bxcore::memory::MEMORY => self.memory(&self.lock(), &call),
_ => {
return ToolResponse::Failed {
message: "memoryd runs only recall and memory".to_string(),
@@ -329,19 +341,24 @@ impl Memoryd {
}
}
/// `recall`: search, labelled by what it found.
fn recall(&self, state: &State, call: &MemoryCall) -> Result<Recalled, String> {
/// `recall`: search, labelled by what it found. Without `[honcho]`, the local index under the
/// lock, as before. With it, the local index under the lock, then, with the lock released,
/// Honcho's sources (M5c spec, section 8): a source that hangs holds up no other request.
fn recall(&self, call: &MemoryCall) -> Result<Recalled, String> {
let args: RecallArgs = match serde_json::from_str(&call.request.arguments) {
Ok(args) => args,
Err(e) => return Err(format!("recall's arguments: {e}")),
};
recall::recall(
&state.index,
&self.store,
&args,
call.request.session.as_str(),
Timestamp::now(),
)
let session = call.request.session.as_str();
let Some(reading) = &self.reading else {
let state = self.lock();
return recall::recall(&state.index, &self.store, &args, session, Timestamp::now());
};
let local = {
let state = self.lock();
recall::local(&state.index, &self.store, &args, session, Timestamp::now())?
};
Ok(reading.recall(local, &args, &self.log))
}
/// `memory`: refused, staged for review, or applied and journalled; then what it appended to