Skip to main content

Module tool_bridge

Module tool_bridge 

Source
Expand description

The async worker side of the ECS tool stage - the sync-ECS ↔ async-I/O bridge for tool execution.

When the pipeline decides an agent’s response has tool calls to run, the tool-dispatch system builds a ToolJob (the agent plus a boxed async closure that executes that agent’s batch of calls against its own tool registry / workdir / policy) and sends it to the tool lane. The lane runs the batch and reports its ToolOutcome back on the results channel, waking the tick loop; the tool-collect system applies the results on a later tick.

Concurrency: the lane is a semaphore, not a pool of workers. ToolLane::serve reads jobs off the channel and spawns one task per batch; each task holds a permit for as long as it is executing, so max_concurrent_tools batches run at a time.

It used to be a fixed pool of worker tasks, and that deadlocked. Several things a batch can await have no time bound at all: a tool-approval prompt, an ask_user, a wait_for_agent poll that only ends when some other run finishes. A worker sitting in one of those was a unit of capacity spent on waiting rather than working, and a parent waiting on a child it had spawned was holding capacity that child needed to finish. Eight of those and no agent’s tools ran again, for as long as the daemon lived (issue #191).

A permit, unlike a worker, can be handed back in the middle of a batch. That is what off_lane does, and it is what makes the deadlock impossible: waiting costs the lane nothing, and the batch takes a permit again when it has something to do.

Order: which of two batches submitted together gets in first is not fixed - they race for the permit as separate tasks. Nothing depends on it, since an agent only ever has one batch in flight, and once both are actually waiting the semaphore hands out permits first-come-first-served, so nothing is starved either.

Structs§

ToolJob
A batch of tool calls to execute for one agent.
ToolLane
The tool lane: the capacity that bounds how many batches execute at once, and the plumbing a batch needs to report its outcome.
ToolLaneStats
Live occupancy of the tool lane.
ToolOutcome
The result of a ToolJob, applied on a later tick by the tool-collect system.

Functions§

off_lane
Await something with no time bound without holding the tool lane.

Type Aliases§

BoxedToolExec
A boxed, per-agent tool-execution closure. Built by the dispatch system so it captures that agent’s own tool registry, workdir, and policy; run once by the tool lane.
ToolExecFuture
The future produced by a boxed tool-execution closure: resolves to (tool_call_id, result) pairs - the same shape the engine’s tool executors already return.