gatewayd: a turn's speaker, the username of the one person who wrote its burst

Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
2026-09-28 10:51:17 -07:00
co-authored by ornith-1.5-35b-a3b
parent 4866353ac9
commit fae12c3fe2
12 changed files with 503 additions and 15 deletions
+18 -9
View File
@@ -151,6 +151,7 @@ fn one_turn(
socket: &Path,
batch: &Batch,
resume: bool,
speaker: Option<&str>,
on_event: &mut dyn FnMut(&TurnEvent),
) -> Outcome {
// 1. Connect to the socket (else LoopDown("cannot connect to <path>: <e>")).
@@ -167,8 +168,8 @@ fn one_turn(
session: batch.session.clone(),
content: batch.text.clone(),
resume,
// Set in M5c-1 task 03. Until then no turn has a speaker, and none is synced.
speaker: None,
// On the turn only, never in its text: `memoryd` reads it from the log, the model never.
speaker: speaker.map(str::to_string),
};
if let Err(e) = write_frame(
&mut stream,
@@ -207,14 +208,20 @@ fn one_turn(
}
}
/// A turn for a batch. A reply in a thread `loopd` does not know creates the session, as
/// `bxctl chat --session` does.
pub fn run_turn(socket: &Path, batch: &Batch, on_event: &mut dyn FnMut(&TurnEvent)) -> Outcome {
/// A turn for a batch, spoken by `speaker` (a Mattermost username) when one person wrote all of
/// it. A reply in a thread `loopd` does not know creates the session, as `bxctl chat --session`
/// does.
pub fn run_turn(
socket: &Path,
batch: &Batch,
speaker: Option<&str>,
on_event: &mut dyn FnMut(&TurnEvent),
) -> Outcome {
// `one_turn` with batch.resume. When that is Refused with NoSuchSession and batch.resume was
// true, one more `one_turn` with resume false. Otherwise the first outcome.
match one_turn(socket, batch, batch.resume, on_event) {
match one_turn(socket, batch, batch.resume, speaker, on_event) {
Outcome::Refused(err) if err.code == ErrorCode::NoSuchSession && batch.resume => {
one_turn(socket, batch, false, on_event)
one_turn(socket, batch, false, speaker, on_event)
}
outcome => outcome,
}
@@ -230,11 +237,13 @@ fn post(poster: &dyn Poster, thread: &Thread, text: String, log: &dyn Fn(&str))
}
}
/// Run a batch's turn and post what comes of it in its thread. A post that fails is logged.
/// Run a batch's turn, spoken by `speaker`, and post what comes of it in its thread. A post that
/// fails is logged.
pub fn deliver(
poster: &dyn Poster,
socket: &Path,
batch: &Batch,
speaker: Option<&str>,
log: &dyn Fn(&str),
notice: &Notice,
) {
@@ -244,7 +253,7 @@ pub fn deliver(
// LoopDown(why) -> log "gatewayd: <session>: <why>" and post LOOP_DOWN. A post that fails is
// logged, exactly "gatewayd: cannot post in <channel> (thread <root>): <error>", and the rest
// goes on.
let outcome = run_turn(socket, batch, &mut |event| {
let outcome = run_turn(socket, batch, speaker, &mut |event| {
if let TurnEvent::ApprovalPending { approval, .. } = event
&& !notice.arrives(*approval)
{