plugin: granular streaming hooks (P3, retargeted) — on-turn-start/end + on-message-update - #43
Merged
Merged
Conversation
Builds on P0's turn-boundary detection. Wires the new
AgentEvent::TurnStart / TurnEnd events into three new plugin hooks:
on-turn-start {:index N}
on-message-update {:index N :partial "text-so-far"}
on-turn-end {:index N :message "full turn text"}
These give plugins per-turn observability that wasn't possible from
the previous `on-response` hook alone (which only fires once at the
end of the whole agent run). Typical uses:
* Per-turn cost / latency tracking.
* Token-level filtering or annotation.
* Cancel-on-condition based on streaming output.
* Streaming a live transcript to an external sink.
Implementation:
* `src/ui/streaming.rs` — new TokenBatcher type that collects tokens
since the last flush and yields the accumulated text once the count
threshold (DEFAULT_BATCH_TOKENS = 16) is crossed. Count-based
rather than time-based so the tests are deterministic without
mocking Instant. Module is cfg-gated to the plugin feature.
* `src/ui/mod.rs`:
- New per-turn streaming state (token_batcher, current_turn_text,
current_turn_index), cfg-gated.
- AgentEvent::Token arm now pushes to the batcher; on flush,
dispatches `on-message-update` with the accumulated text.
- AgentEvent::TurnStart arm resets per-turn state and dispatches
`on-turn-start`.
- AgentEvent::TurnEnd arm flushes any trailing partial batch (as
a final `on-message-update`), then dispatches `on-turn-end`
with the full turn text.
* `src/main.rs` — adds the three hook names to auto-discovery.
`harness/replace-message` (mutating the persisted assistant text from
on-message-end) is deferred. It needs session-write position tracking
and interacts with usage accounting; will land in a follow-up phase.
Tests: 6 new unit tests on `TokenBatcher` — threshold yielding,
post-flush fresh batch, partial-batch draining, reset, zero-threshold
clamping, lossless content over a run. Total: 516 pass with plugin
(was 510); 460/12 baseline without plugin unchanged.
plugins/turn_timing.janet — example using on-turn-start / on-turn-end
to notify the user how long each turn took.
Refs dirge-87x.
allen-munsch
pushed a commit
to allen-munsch/dirge
that referenced
this pull request
Jun 3, 2026
…te) (dirge-code#43) Builds on P0's turn-boundary detection. Wires the new AgentEvent::TurnStart / TurnEnd events into three new plugin hooks: on-turn-start {:index N} on-message-update {:index N :partial "text-so-far"} on-turn-end {:index N :message "full turn text"} These give plugins per-turn observability that wasn't possible from the previous `on-response` hook alone (which only fires once at the end of the whole agent run). Typical uses: * Per-turn cost / latency tracking. * Token-level filtering or annotation. * Cancel-on-condition based on streaming output. * Streaming a live transcript to an external sink. Implementation: * `src/ui/streaming.rs` — new TokenBatcher type that collects tokens since the last flush and yields the accumulated text once the count threshold (DEFAULT_BATCH_TOKENS = 16) is crossed. Count-based rather than time-based so the tests are deterministic without mocking Instant. Module is cfg-gated to the plugin feature. * `src/ui/mod.rs`: - New per-turn streaming state (token_batcher, current_turn_text, current_turn_index), cfg-gated. - AgentEvent::Token arm now pushes to the batcher; on flush, dispatches `on-message-update` with the accumulated text. - AgentEvent::TurnStart arm resets per-turn state and dispatches `on-turn-start`. - AgentEvent::TurnEnd arm flushes any trailing partial batch (as a final `on-message-update`), then dispatches `on-turn-end` with the full turn text. * `src/main.rs` — adds the three hook names to auto-discovery. `harness/replace-message` (mutating the persisted assistant text from on-message-end) is deferred. It needs session-write position tracking and interacts with usage accounting; will land in a follow-up phase. Tests: 6 new unit tests on `TokenBatcher` — threshold yielding, post-flush fresh batch, partial-batch draining, reset, zero-threshold clamping, lossless content over a run. Total: 516 pass with plugin (was 510); 460/12 baseline without plugin unchanged. plugins/turn_timing.janet — example using on-turn-start / on-turn-end to notify the user how long each turn took. Refs dirge-87x. Co-authored-by: Yogthos <yogthos@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-opening PR #38 after its base branch was deleted by the P0 merge. Content unchanged — just retargeted to current main.