Skip to content

fix: isolate usage between RunState checkpoints - #4479

Merged
seratch merged 3 commits into
openai:mainfrom
chiruu12:fix/isolate-checkpoint-usage
Aug 19, 2026
Merged

fix: isolate usage between RunState checkpoints#4479
seratch merged 3 commits into
openai:mainfrom
chiruu12:fix/isolate-checkpoint-usage

Conversation

@chiruu12

Copy link
Copy Markdown
Contributor

Summary

RunContextWrapper._copy_for_run_state detaches _approvals, _tool_invocations and _restored_unbound_approval_call_ids, but the copy.copy(self) it starts from leaves usage shared. Usage.add accrues in place and extends request_usage_entries, so every checkpoint taken from a result, and the result itself, accumulate into one instance.

Two consequences, both reproducible on main:

A RunResult the caller already holds keeps changing. After result.to_state() and a resume, result.context_wrapper.usage.requests goes from 1 to 2.

Two checkpoints from one result bill each other. Each resumed once from the same one-request run, so both should report 2 requests. The second reports 3.

The copy is deep because add extends request_usage_entries rather than replacing it.

turn_input is aliased by the same copy.copy, but it is reassigned rather than mutated in turn_resolution.py and run_loop.py, so I left it as is rather than widen the change.

Test plan

Two tests in TestRunStateResumption, next to the existing resume-isolation coverage: one asserts a resume does not move the source result's usage, the other that two checkpoints from one result report the same total and do not share request_usage_entries. Reverting only the run_context.py line fails them with assert 2 == 1 and assert 3 == 2.

make format, make lint, make typecheck and make tests all pass (8806 passed, plus the serial pass).

Issue number

None, filing the fix directly since it is a narrow follow-up to #4413.

Checks

  • I've added new tests, if relevant
  • I've run .agents/skills/code-change-verification/scripts/run.sh
  • I've confirmed all verification steps pass
  • If using Codex, I've run /review before submitting this PR

Copilot AI lite review requested due to automatic review settings August 17, 2026 10:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 41cb6a518a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/run_context.py

@seratch seratch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. Please keep the new copied.usage = copy.deepcopy(self.usage) assignment in src/agents/run_context.py; that correctly isolates top-level checkpoints.

The additional runtime change belongs in Agent.as_tool()'s _run_agent_impl() in src/agents/agent.py. After the pending_resume_state if / elif block selects resume_state, move the existing usage assignment out of the status in ("approved", "rejected") branch and apply it to both paths:

if resume_state is not None and resume_state._context is not None:
    resume_state._context.usage = context.usage

Place this immediately after the pending_resume_state if / elif block and before if run_result is None:. This preserves top-level checkpoint isolation while ensuring cached nested Agent.as_tool() resumes continue accumulating usage on the current outer run.

@chiruu12

Copy link
Copy Markdown
Contributor Author

Done. Moved the usage rebind out of the approved/rejected branch so it applies to the cached resume path too, and kept the _copy_for_run_state deepcopy. Added a test that fails without the runtime change. Full stack is green.

@seratch seratch added this to the 0.22.x milestone Aug 19, 2026
@seratch
seratch merged commit fb8fa1b into openai:main Aug 19, 2026
16 checks passed
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.

3 participants