Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/biorouter/src/agents/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5447,11 +5447,17 @@ impl Agent {
/// assistant messages). MOIM injection already re-normalized on the way
/// through; this closes the same hole for sessions with no MOIM provider.
/// `BIOROUTER_NORMALIZE_EACH_TURN=false` restores the old behaviour.
/// `cancel` is the turn's own token. It reaches this far down because the
/// workspace map's directory walk is the one piece of per-turn context
/// assembly that touches the filesystem, and a `Stop` has to be able to end
/// the wait for it — see `agents::workspace_summary` and finding M1 of the
/// 2026-09-10 test drive.
async fn assemble_turn_context(
&self,
session_id: &str,
conversation: &Conversation,
working_dir: &std::path::Path,
cancel: Option<&CancellationToken>,
) -> Conversation {
let _phase = super::phase_timing::Phase::start("agent.assemble_turn_context");

Expand All @@ -5462,6 +5468,7 @@ impl Agent {
&self.extension_manager,
working_dir,
&self.normalizer,
cancel,
)
.await;
drop(moim_phase);
Expand Down Expand Up @@ -9578,6 +9585,7 @@ impl Agent {
&session_config.id,
&conversation,
&working_dir,
cancel_token.as_ref(),
)
.await
}
Expand Down
10 changes: 8 additions & 2 deletions crates/biorouter/src/agents/extension_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3152,10 +3152,14 @@ impl ExtensionManager {
.map(|ext| ext.get_client())
}

/// `cancel` is the turn's cancellation token, threaded down to the
/// workspace map so a `Stop` is honoured while its directory walk is still
/// outstanding. See `agents::workspace_summary`.
pub async fn collect_moim(
&self,
session_id: &str,
working_dir: &std::path::Path,
cancel: Option<&tokio_util::sync::CancellationToken>,
) -> Option<String> {
// Use minute-level granularity to prevent conversation changes every second
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:00").to_string();
Expand All @@ -3168,7 +3172,9 @@ impl ExtensionManager {
// BR-1: give the model a bounded, gitignore-aware map of the workspace so
// it doesn't rediscover project structure from scratch every session. The
// map is cached and token-capped inside `workspace_summary`.
if let Some(map) = crate::agents::workspace_summary::workspace_summary(working_dir) {
if let Some(map) =
crate::agents::workspace_summary::workspace_summary(working_dir, cancel).await
{
content.push('\n');
content.push_str(&map);
content.push('\n');
Expand Down Expand Up @@ -4280,7 +4286,7 @@ mod tests {
let em = ExtensionManager::new_without_provider(temp_dir.path().to_path_buf());
let working_dir = std::path::Path::new("/tmp");

if let Some(moim) = em.collect_moim("test-session-id", working_dir).await {
if let Some(moim) = em.collect_moim("test-session-id", working_dir, None).await {
// Timestamp should end with :00 (seconds fixed to 00)
assert!(
moim.contains(":00\n"),
Expand Down
8 changes: 7 additions & 1 deletion crates/biorouter/src/agents/moim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::conversation::message::Message;
use crate::conversation::{Conversation, SharedNormalizer};
use rmcp::model::Role;
use std::path::Path;
use tokio_util::sync::CancellationToken;

// Test-only utility. Do not use in production code. No `test` directive due to call outside crate.
thread_local! {
Expand Down Expand Up @@ -71,13 +72,14 @@ pub async fn inject_moim(
extension_manager: &ExtensionManager,
working_dir: &Path,
normalizer: &SharedNormalizer,
cancel: Option<&CancellationToken>,
) -> (Conversation, bool) {
if SKIP.with(|f| f.get()) {
return (conversation, false);
}

if let Some(moim) = extension_manager
.collect_moim(session_id, working_dir)
.collect_moim(session_id, working_dir, cancel)
.await
{
let moim = cap_moim_block(moim, max_moim_tokens());
Expand Down Expand Up @@ -142,6 +144,7 @@ mod tests {
&em,
&working_dir,
&SharedNormalizer::new(),
None,
)
.await;
let msgs = result.messages();
Expand Down Expand Up @@ -180,6 +183,7 @@ mod tests {
&em,
&working_dir,
&SharedNormalizer::new(),
None,
)
.await;

Expand Down Expand Up @@ -252,6 +256,7 @@ mod tests {
&em,
&working_dir,
&SharedNormalizer::new(),
None,
)
.await;
let msgs = result.messages();
Expand Down Expand Up @@ -379,6 +384,7 @@ mod tests {
&em,
&working_dir,
&SharedNormalizer::new(),
None,
)
.await;

Expand Down
Loading
Loading