Skip to content

fix: isolate RunState checkpoint tool decisions - #4413

Merged
seratch merged 1 commit into
mainfrom
fix/detach-runstate-checkpoint-ledgers
Aug 14, 2026
Merged

seratch merged 1 commit into
mainfrom
fix/detach-runstate-checkpoint-ledgers

Conversation

@seratch

@seratch seratch commented Aug 14, 2026

Copy link
Copy Markdown
Member

This pull request fixes approval and invocation ledger sharing between RunState checkpoints created from the same interrupted result.

RunResult.to_state() and RunResultStreaming.to_state() now detach SDK-owned approval state while preserving caller context and Agent identity. Nested Agent-as-tool approval checkpoints receive scope-qualified, recursively rebound state so approving or rejecting one checkpoint cannot affect another checkpoint or leave stale nested cache entries behind.

The change adds regression coverage for direct checkpoint isolation, streamed results, nested approval ownership, and scope-qualified agent-tool cache entries.

ref: #4409 (comment)

@seratch seratch added this to the 0.21.x milestone Aug 14, 2026
@seratch
seratch merged commit 0b93ce8 into main Aug 14, 2026
14 checks passed
@seratch
seratch deleted the fix/detach-runstate-checkpoint-ledgers branch August 14, 2026 11:50

Copy link
Copy Markdown
Contributor

Thanks for landing the follow-up. I ran the merged commit 0b93ce8faa27d4631df399fe48856b52a8fd9897 through AgentRunProof using the SDK's public agents.testing.ScriptedModel (no provider/API calls).

Good news: the original sibling-isolation scenario now passes all seven recorded invariants in both Runner.run and Runner.run_streamed:

execution_outcome   PASS
state_transitions   PASS
state_fork_isolation PASS
phase_contract      PASS
tool_linkage        PASS
exactly_once        PASS
stream_parity       PASS

That is a real FAIL → PASS relative to openai-agents==0.20.0.

The same verification found one recursive boundary that appears not to be covered by #4413. With a protected approval nested through Agent.as_tool:

nesting edges run run_streamed
1 completes, 0 interruptions, effect once completes, 0 interruptions, effect once
2 remains interrupted, effect not reached remains interrupted, effect not reached
3 remains interrupted, effect not reached remains interrupted, effect not reached

The minimal sequence is:

paused = await Runner.run(outer_agent, "start")
state = paused.to_state()
state.approve(state.get_interruptions()[0])
resumed = await Runner.run(outer_agent, state)

At two or more agent-tool edges, resumed.final_output is None, the same flattened approval remains in resumed.interruptions, and the protected tool has not executed. I reproduced the same result in streamed mode.

So the top-level checkpoint isolation fix is working; the remaining gap is recursive ownership/routing of that approved interruption. I will avoid opening a competing PR. I can provide the focused 2/3-edge regression or validate a follow-up immediately. I am also preparing a content-addressed before/after record so the result is independently checkable; the published 0.20.0 counterexample is in AgentRunProof v0.1.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants