Mid-turn steering orchestration with token-level streaming — enables users to inject guidance while the agent is working.
- Python 3.11+
- UV - Fast Python package manager
# macOS/Linux/WSL
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"Extends the streaming orchestrator with mid-turn message injection. Users can send steering messages while the agent is executing — the messages are added to the conversation context at the next iteration boundary, allowing the LLM to adjust its approach without cancelling the current turn.
This is the orchestrator Brian Krabach described: "between its steps... if it's got any new messages... consider that" for steering.
Module Type: Orchestrator
Mount Point: orchestrators
Entry Point: amplifier_module_loop_steering:mount
- Everything from
loop-streaming: token-level streaming, parallel tool execution, two-tier cancellation, hook-gated operations - Mid-turn steering:
inject_steering(message)queues a user message that gets drained at the next iteration boundary - Persistent context injection: Steering messages are added via
context.add_message()(not ephemeral — visible for all subsequent LLM calls in the turn) - System-reminder framing: Messages are wrapped in
<system-reminder source="user-steering">so the LLM treats them as guidance, not new tasks - Bounded queue: Max 10 pending steering messages (raises
asyncio.QueueFullat capacity) - Two drain points: Top of each iteration + after tool execution completes (halves worst-case latency)
- Observable events: Emits
steering:appliedwhen a message is injected into context
[[orchestrators]]
module = "loop-steering"
name = "steering"
config = {
buffer_size = 10, # Tokens to buffer before flush
max_iterations = -1, # Maximum iterations (-1 = unlimited, default)
timeout = 300 # Timeout in seconds
}# In amplifier configuration
[session]
orchestrator = "loop-steering"session:
orchestrator:
module: loop-steering
source: "git+https://github.com/manojp99/amplifier-module-loop-steering@master"The orchestrator exposes one public method for external callers (e.g., the amplifierd daemon):
orchestrator = coordinator.get("orchestrator")
orchestrator.inject_steering("focus on the test files instead")Messages are drained at the next iteration boundary and added to context as:
<system-reminder source="user-steering">
The user injected the following guidance mid-turn. Integrate it into your
ongoing work; do not treat it as a new task or respond to it as a question.
focus on the test files instead
</system-reminder>
Steering messages land at iteration boundaries — between LLM calls and after tool execution. Worst-case latency = remaining time in the current phase:
| Phase | Typical duration | Steering waits until... |
|---|---|---|
| LLM streaming | 10-60s | Stream completes |
Tool execution (asyncio.gather) |
Seconds to minutes | All tools finish |
| Between iterations | Instant | Next loop iteration |
This is an acceptable tradeoff — the alternative (cancelling mid-stream) loses all in-progress work.
| Event | When | Data |
|---|---|---|
steering:applied |
Message injected into context | {orchestrator, content, iteration} |
All loop-streaming events |
Unchanged | Same as loop-streaming |
# Install dev dependencies
uv sync --group dev
# Run tests (15 tests)
uv run pytest tests/ -vTests cover: queue injection, queue capacity, mid-turn application, queue clear on new execute, multiple messages, persistence in context, event naming, and basic regression.
Perfect for:
- Interactive CLI applications with mid-turn user steering
- Web UIs where users can redirect agent work in real-time
- Any frontend that needs to inject guidance without cancelling the current turn
amplifier-core>=1.0.0