Skip to content

fix(items): strip created_by when replaying RunItems as input - #4568

Open
hsusul wants to merge 1 commit into
openai:mainfrom
hsusul:fix/runitem-strip-created-by
Open

fix(items): strip created_by when replaying RunItems as input#4568
hsusul wants to merge 1 commit into
openai:mainfrom
hsusul:fix/runitem-strip-created-by

Conversation

@hsusul

@hsusul hsusul commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

This pull request fixes a gap left by #4308: ModelResponse.to_input_items() already strips output-only created_by before Responses replay, but public RunItem continuation still leaked it.

RunItem.to_input_item() dumped function-call and tool-output payloads with created_by intact. That same conversion feeds run_item_to_input_item(), session persistence, and RunResult.to_input_list(), so a later Responses request can include a field that is not part of the input schema.

The base converter now routes through _output_item_to_input_item(), and the dict path on ToolCallOutputItem pops created_by from the copied payload without mutating raw_item.

Test plan

  • Added tests for ToolCallItem.to_input_item, ToolCallOutputItem.to_input_item, and run_item_to_input_item on function calls/outputs that carry created_by
  • uv run pytest tests/test_items_helpers.py tests/test_run_internal_items.py
  • make format, make lint, make typecheck
  • Full make tests — one pre-existing local failure on this host, unrelated to this change: tests/sandbox/test_run_cwd.py::test_python_skill_uses_absolute_root_from_nested_workdir (WorkspaceReadNotFoundError for tasks/task-a/nested/output.txt). The same failure occurs on unpatched upstream/main.

Issue number

N/A — small fix, no existing issue.

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

ModelResponse.to_input_items already dropped output-only created_by, but RunItem.to_input_item still forwarded it on function calls and tool outputs used for sessions and to_input_list.

@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: 0c24229502

ℹ️ 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/items.py
if isinstance(outcome, dict):
if outcome.get("type") == "exit":
entry["outcome"] = outcome
payload.pop("created_by", None)

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 Strip nested shell ownership metadata too

When a ToolCallOutputItem is constructed from an unsanitized dictionary-form shell_call_output, this removes only the top-level created_by; each entry under output can also contain created_by, so to_input_item() still returns a payload the Responses API rejects. The shared _output_item_to_input_item() path already rebuilds these chunks without that field, so apply the same nested sanitization here while retaining the shell-specific field removal.

AGENTS.md reference: AGENTS.md:L93-L93

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.

Thanks for addressing the RunItem replay path. The overall direction is right, but one dict-backed path still retains output-only metadata.

I reproduced this on the current head with a ToolCallOutputItem whose raw_item is a shell_call_output mapping. to_input_item() removes the top-level created_by, but output[*].created_by remains in the replayed payload because this branch returns its shallow-copied payload directly and bypasses the nested cleanup in _output_item_to_input_item().

Please keep the existing dict-specific cleanup for status, shell_output, and provider_data, then route the cleaned payload through the shared output-item sanitizer. Please also add a regression test covering a dict-backed ToolCallOutputItem and asserting that:

  • both the top-level and nested created_by fields are removed;
  • the existing shell-output cleanup is preserved; and
  • the original raw_item, including its nested chunk mapping, is not mutated.

Once that case is covered, this should be ready.

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