Repository navigation
Conversation
danielkov
force-pushed
the
feat/loop-mutator-lifecycle
branch
from
October 8, 2026 09:09
22179a3 to
733994d
Compare
Narrow the LoopMutator extension to three awaited hooks that intercept values before the loop consumes or commits them: on_session_start, on_model_request, and on_model_response. Remove the read-only lifecycle notifications (turn start/finish/end, model progress/error, tool progress/batch, session end), queued input admission and submit_input_async, explicit close, resumable terminal delivery, transcript rewrite notifications, and the Clone derive on LoopError. Read-only notifications belong in LoopObserver. This also removes the expect-based state machines and behaviour that differed depending on whether a mutator was registered. Hooks fail closed: an error or invalid edit aborts the operation without committing anything from it. LoopError::Cancelled from a hook finishes the turn as cancelled, matching mutate and model-stream cancellation. Hooks run inside the chat span, so gen_ai.input.messages and gen_ai.output.messages capture the final edited messages and hook latency counts toward inference time. MutationPoint::AfterTurnEnded gets a doc fix only: it has always run before the first inference of a new turn, after pending input is appended.
danielkov
force-pushed
the
feat/loop-mutator-lifecycle
branch
from
October 8, 2026 09:10
733994d to
9afba53
Compare
This branch has not been deployed
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.
Summary
Extend
LoopMutatorwith awaited, protocol-neutral lifecycle callbacks for sessions, input, logical turns, model calls, progress, and resolved tool batches. Existing transcript mutators remain compatible through default no-op callbacks.Motivation
Hosts need to intercept values before the loop consumes or commits them. Synchronous observer notifications cannot return effective inputs or responses, and public driver steps do not expose every logical-turn boundary.
Technical details
Editable payloads and consistent commits
Typed payloads separate mutable content and request options from immutable identity and accounting. Turn-start edits are staged and validated; model-request edits are inference-local. Model-response and final-turn edits reach the committed transcript, returned result, terminal notifications, and output capture consistently. Transcript replacements have an explicit observer notification.
Resumable lifecycle delivery
Logical-turn callbacks span model and tool continuations rather than repeating per inference. Driver-owned terminal state retains candidate edits and callback progress across interrupted finalization and explicit closure. Completed callbacks are not repeated; an interrupted callback may be retried. Original execution failures retain precedence over terminal notification failures.
Input admission and session closure
submit_input_asyncprovides awaited admission, while synchronous submission retains queued batches until dispatch. Rejection removes only the rejected batch.closeexplicitly retires active work and delivers session-end callbacks; it is not tied to prompt completion or asynchronous work inDrop.Individual and nested tool interception continues to use the executor boundary. Compaction and application-owned configuration or model-selection operations retain their own extension seams.