M4: subagent context-file reporting to the job board

Lets subagents report context files back to the job board (surfaced from the read tool) so the parent session's next-turn context includes what a background child has been looking at.
This commit is contained in:
2026-07-10 16:20:11 +02:00
parent 8976b5dc09
commit ac516a7e23
12 changed files with 187 additions and 3 deletions
+1
View File
@@ -411,6 +411,7 @@ mod tests {
now: 1,
spawner: None,
job_board: None,
context_reporter: None,
}
}
+6 -1
View File
@@ -11,7 +11,8 @@ use crate::llm::{FinishReason, LlmEvent, LlmEventStream, ProviderError};
use crate::permission::{PermissionService, Ruleset};
use crate::store::Store;
use crate::tool::{
MetadataSink, PermissionHandle, SubagentSpawner, Tool, ToolCtx, ToolError, ToolRegistry,
ContextReporter, MetadataSink, PermissionHandle, SubagentSpawner, Tool, ToolCtx, ToolError,
ToolRegistry,
};
use crate::types::{Message, MessageId, Part, PartBody, PartId, SessionId, TokenUsage, ToolState};
@@ -65,6 +66,9 @@ pub struct StepContext {
/// This session's background job board (as a parent). Injected into requests when the
/// running agent can delegate; `None` disables the board.
pub job_board: Option<Arc<JobBoard>>,
/// Present in subagent sessions: reports read files to this session's job on the parent
/// board. `None` for root sessions (nothing to report to).
pub context_reporter: Option<Arc<dyn ContextReporter>>,
}
struct FlushTracker {
@@ -506,6 +510,7 @@ impl<'a> Run<'a> {
ask,
metadata: metadata_sink,
spawner: self.ctx.spawner.clone(),
context_reporter: self.ctx.context_reporter.clone(),
};
let result = tokio::select! {
+10
View File
@@ -54,6 +54,14 @@ pub trait SubagentSpawner: Send + Sync {
async fn spawn(&self, req: SpawnRequest) -> Result<SpawnOutcome, SpawnError>;
}
/// Lets a child session report the files it read to its job board entry, so a completed
/// specialist advertises what it already looked at (docs/04-multiagent.md). Present only in
/// subagent sessions; the spawner wires it to the right board + job.
#[async_trait]
pub trait ContextReporter: Send + Sync {
async fn report_file(&self, path: String, lines: u32);
}
#[derive(Debug, thiserror::Error)]
pub enum ToolError {
#[error("permission denied")]
@@ -185,6 +193,8 @@ pub struct ToolCtx {
/// Present when the engine can spawn subagents (the `task` tool's capability). `None`
/// in headless/test contexts with no orchestration wired in.
pub spawner: Option<Arc<dyn SubagentSpawner>>,
/// Present in subagent sessions: lets the read tool report files to the job board.
pub context_reporter: Option<Arc<dyn ContextReporter>>,
}
#[derive(Debug)]