Problem
CodeAct requires each model turn to call execute_python() or return_result(). When a model instead returns plain text, both text-only recovery routes remove the provider-authored LLMOutput and replace it with synthetic events.
For Responses reasoning models, the removed event can contain the exact assistant text plus opaque/encrypted reasoning output items needed for stateless multi-turn continuation. Removing it loses reasoning continuity. Attaching those items to the synthetic tool call would retain bytes but would incorrectly attribute the model reasoning to a function call the model never produced.
Affected continuations:
text_only_stop_behavior=return_result when synthetic return validation fails and the model is asked to retry
text_only_stop_behavior=synthetic_comment, which always continues to another model turn
A successful synthetic return_result does not require another provider call, but its trace should still preserve what the provider actually returned.
Desired design
Make CodeAct correction append-only:
- Preserve the original provider-authored output event and exact replayable output batch.
- Record provider/client/model-family provenance with opaque continuation state.
- Add correction and synthetic execution events after the provider event instead of deleting or rewriting it.
- Keep framework-synthetic events distinguishable from provider-authored events.
- On the next request, replay the exact provider reasoning + assistant output, followed by a normal model-visible correction.
- Do not replay retained state to an incompatible provider or model family.
Acceptance criteria
- Neither text-only recovery route removes the provider-authored output.
- A validation-failure retry replays the original Responses items in their original order before correction.
- Synthetic-comment continuation preserves the same ordering.
- Synthetic events are not represented as provider-authored output.
- Persistence/session resume preserves the continuation state and provenance.
- Tests cover Actor → event storage → CodeAct recovery → formatter → second Responses request.
- Existing Completion-client text-only behavior remains unchanged.
Related: #261
🤖🤖🤖
Problem
CodeAct requires each model turn to call
execute_python()orreturn_result(). When a model instead returns plain text, both text-only recovery routes remove the provider-authoredLLMOutputand replace it with synthetic events.For Responses reasoning models, the removed event can contain the exact assistant text plus opaque/encrypted reasoning output items needed for stateless multi-turn continuation. Removing it loses reasoning continuity. Attaching those items to the synthetic tool call would retain bytes but would incorrectly attribute the model reasoning to a function call the model never produced.
Affected continuations:
text_only_stop_behavior=return_resultwhen synthetic return validation fails and the model is asked to retrytext_only_stop_behavior=synthetic_comment, which always continues to another model turnA successful synthetic
return_resultdoes not require another provider call, but its trace should still preserve what the provider actually returned.Desired design
Make CodeAct correction append-only:
Acceptance criteria
Related: #261
🤖🤖🤖