Skip to content

fix(core): count replayed program items as parents with client-managed input - #4840

Open
fuchengwarrenzhu wants to merge 1 commit into
openai:mainfrom
fuchengwarrenzhu:fix/program-parents-from-client-managed-input
Open

fix(core): count replayed program items as parents with client-managed input#4840
fuchengwarrenzhu wants to merge 1 commit into
openai:mainfrom
fuchengwarrenzhu:fix/program-parents-from-client-managed-input

Conversation

@fuchengwarrenzhu

@fuchengwarrenzhu fuchengwarrenzhu commented Sep 3, 2026

Copy link
Copy Markdown

Summary

A program item that arrives in a run's input was never counted as a parent for a later program_output unless the server manages the conversation. With client-managed history, a program that pauses across runs (for example a human-in-the-loop approval of a program-owned call, resumed with the app's own transcript as input) fails with ModelBehaviorError: Model produced program_output item that does not match a parent program item as soon as the model finishes it.

process_model_response now receives the run's input items unconditionally and the parent scan reads program items from them in both modes. The server-managed only branches, which also accept program_output and program caller ids as parents because the program itself may not be in the input there, are unchanged. This matches what RunState resume already does with durable input items. The parameter is renamed from server_managed_input_items to input_items since it no longer means that.

Test plan

  • test_process_model_response_accepts_program_output_for_program_in_input: the scan accepts a program_output whose parent is only in the input.
  • test_runner_completes_a_program_replayed_as_client_managed_input: a Runner.run whose input carries a program, its program-owned call and output, finishes the program and answers. Fails on main with the error above.
  • make format, make lint, make mypy, make tests pass locally, and .agents/skills/code-change-verification/scripts/run.sh reports all commands passed.

Issue number

Closes #4839

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T18:57:18.340996Z a56b8e8 New commits
🔒 Security Review ⚠️ Failed 2026-09-04T18:53:06.464996Z a56b8e8 New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The parent relation should come from durable input regardless of who manages conversation history. Counting replayed program items from input_items while leaving the server-managed-only shortcuts inside _collect_program_parent_state avoids widening parent acceptance. The Runner resume regression pins the actual HITL/replay path.

…d input

A `program` item arriving in a run's input was only counted as a parent for
a later `program_output` when the server manages the conversation. With
client-managed history, a program that pauses across runs (a human-in-the-loop
approval of a program-owned call, resumed with the app's own transcript as
input) failed with "Model produced program_output item that does not match a
parent program item" as soon as the model finished it.

Pass the run's input items to `process_model_response` unconditionally and
read `program` items from them in both modes, as `RunState` resume already
does with durable input. The server-managed only branches, which also accept
`program_output` and program caller ids as parents because the `program`
itself may not be in the input there, are unchanged.

Closes openai#4839
@fuchengwarrenzhu
fuchengwarrenzhu force-pushed the fix/program-parents-from-client-managed-input branch from dfd2448 to a56b8e8 Compare September 4, 2026 18:52

@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: a56b8e8613

ℹ️ 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".

if server_manages_conversation
else None
),
input_items=ItemHelpers.input_to_new_input_list(original_input),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the filtered model input for parent validation

When RunConfig.call_model_input_filter adds replayed program history—or removes it—the model receives filtered.input, but this line validates against the unfiltered original_input. Consequently, a supported client-managed callback that injects the parent program still causes a matching program_output to fail with ModelBehaviorError; conversely, an output can be accepted after the callback removed its parent. Carry the actual filtered input into response processing for both streaming and non-streaming calls.

AGENTS.md reference: AGENTS.md:L147-L148

Useful? React with 👍 / 👎.

@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.

The current head still validates program parents against the unfiltered run input, while the model receives call_model_input_filter's result. A filter that supplies a replayed program can therefore produce a valid completion that the SDK rejects as parentless. Please base parent validation on the input actually sent to the model and cover this through both Runner paths.

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.

Count replayed program items as parents with client-managed input

3 participants