feat: add approval override argument parity for RunState resumes - #2695
feat: add approval override argument parity for RunState resumes#2695seratch wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1e8b70a05e
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a8503fdc79
ℹ️ 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".
a8503fd to
b662362
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b66236272e
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 672358a3c0
ℹ️ 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".
672358a to
2cabc3a
Compare
Co-authored-by: Kazuhiro Sera <seratch@openai.com>
2cabc3a to
7bb9415
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7bb9415c5b
ℹ️ 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".
| nested_state.approve( | ||
| nested_item, | ||
| always_approve=always_approve, | ||
| override_arguments=override_arguments, | ||
| save_override_arguments=save_override_arguments, |
There was a problem hiding this comment.
Validate nested overrides before starting the outer tool
When the approval belongs to a nested Agent.as_tool() run, the override and its persistence requirements are recorded only on nested_state, so the outer runner's preflight cannot see them. Validation or history rewriting therefore occurs after the outer function tool starts; with Agent.as_tool()'s default failure_error_function, an unsupported execution-only override backed by local history—or a failed durable rewrite—is converted into a model-visible tool error, allowing the parent run to continue without executing the approved corrected call. Surface nested persistence requirements to the outer preflight, or otherwise validate them before invoking the parent tool.
AGENTS.md reference: AGENTS.md:L88-L88
Useful? React with 👍 / 👎.
| if session is None or is_session_history_rewrite_aware_session(session): | ||
| return |
There was a problem hiding this comment.
Require the original session for durable overrides
When an interrupted run was persisted to a local session but the caller resumes its RunState without passing that session, this branch treats session is None as supported. The pending mutation is consequently skipped, the corrected tool invocation executes, and its bookkeeping is cleared while the original session still contains the model-proposed arguments; later replay or compaction from that session can therefore revert to the unapproved call. Distinguish session-backed states from sessionless states and reject a durable override before execution when its canonical session is unavailable.
AGENTS.md reference: AGENTS.md:L156-L156
Useful? React with 👍 / 👎.
| else: | ||
| state._approval_argument_override_modes = {} | ||
| state._session_history_mutations = [] |
There was a problem hiding this comment.
Reject downgraded override snapshots
If a current durable-override snapshot is relabeled with any schema version below 1.16, this branch clears only the override bookkeeping while retaining the overridden arguments in the interruption, generated, session, and processed-response payloads. Resuming that state executes the corrected arguments with no pending history mutation, leaving a supplied local session's original function call unchanged and allowing later replay to revert it. Reject legacy schema labels that contain these fields, or detect the argument divergence instead of silently discarding the mutation metadata.
AGENTS.md reference: AGENTS.md:L158-L158
Useful? React with 👍 / 👎.
| self._approval_argument_override_modes[call_id] = ( | ||
| "durable" if should_save_override_arguments else "execution_only" | ||
| ) |
There was a problem hiding this comment.
Clear override state when a rejection supersedes approval
A caller can approve with override_arguments and then change the same per-call decision to rejection before resuming, because reject_tool() explicitly replaces the earlier approval. The override mode and durable mutation recorded here remain active, however, so resume rewrites history even though the call is rejected; because the invocation never executes, _clear_executed_approval_argument_overrides() leaves the mode behind, and a later RunState.from_json() rejects the resulting snapshot because the mode no longer belongs to an approved pending call. Unwind the override mutation and mode when rejection supersedes the approval.
AGENTS.md reference: AGENTS.md:L147-L147
Useful? React with 👍 / 👎.
| previous_items = await self._get_all_underlying_session_items(underlying_session) | ||
| rewritten_items = apply_session_history_mutations(previous_items, mutations) |
There was a problem hiding this comment.
Normalize mutations for ID-stripping session backends
When OpenAIResponsesCompactionSession wraps a valid client-managed backend that strips or reassigns provider id fields on add_items(), the stored function call lacks the id retained in the mutation's expected payload. This fallback performs an exact comparison through apply_session_history_mutations(), so it raises a target-mismatch error and durable approval overrides cannot resume even though the wrapper advertises supports_expected_history_mutations = True. Normalize mutation payloads using the underlying session's storage policy, or require an explicit rewrite-aware underlying backend instead of advertising unsupported fallback behavior.
AGENTS.md reference: AGENTS.md:L156-L156
Useful? React with 👍 / 👎.
This pull request adds approval-time argument overrides for pending function calls resumed from
RunState.Applications can inspect an interrupted run, replace the model-proposed arguments during approval, and resume execution with the corrected values:
By default, the override is durable: the SDK rewrites the canonical function call in a compatible local session before executing the tool. This prevents later replay, compaction, or model input from reverting to the original arguments.
For server-managed conversations, where the SDK does not own canonical history, callers can explicitly request an execution-only override:
Execution-only mode changes the pending tool invocation without claiming to rewrite remote history. Raw model responses also retain the model-requested arguments as audit provenance, while pending approvals and processed execution use the approved arguments. This provenance model aligns with openai/openai-agents-js#1098 while retaining Python's nested-agent support.
The behavior is consistent across synchronous, streamed, serialized, and nested-agent resumes:
Durable overrides require a locally managed, history-rewrite-aware session. SQLite and Responses compaction sessions support the required mutation contract. Unsupported ownership combinations, missing mutation targets, and unconfirmed rewrites fail before tool execution.
The change also introduces strict
RunStateschema 1.16 persistence for override modes and pending history mutations. Restoration validates call identity and mode-specific provenance, while earlier schemas remain readable without granting override behavior. Cleanup is tracked per call so partial failure or cancellation preserves unstarted sibling approvals without allowing unsafe retries to repeat tool side effects.