Skip to content

fix(chat): preserve single-pass tool iterables - #3770

Merged
marcuswood-oai merged 7 commits into
openai:mainfrom
Hughhhhcoder:codex/openai-python-single-pass-tools
Sep 23, 2026
Merged

marcuswood-oai merged 7 commits into
openai:mainfrom
Hughhhhcoder:codex/openai-python-single-pass-tools

Conversation

@Hughhhhcoder

@Hughhhhcoder Hughhhhcoder commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Passing a generator to chat.completions.parse() or .stream() can send an empty tools array or lose parsed function arguments. Materialize the iterable once and reuse it for validation, serialization, and response parsing across sync and async helpers.

The public Iterable type stays unchanged. .parse() retains strict-tool validation; async .stream() now accepts non-strict tools without auto-parsing them, matching existing sync behavior. Two parametrized tests cover all four helper paths and non-strict streaming.

Validation: chat suite passed with Pydantic v2 (77 tests) and v1 (76 passed, 1 skipped); all four strict-tool regressions fail against main. Ruff lint, changed-file formatting, Pyright, mypy, and the custom-code budget passed. Security review found no new concerns.

@Hughhhhcoder
Hughhhhcoder requested a review from a team as a code owner August 31, 2026 09:59
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 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-04T12:45:34.340921Z f16aee4 Manual request
🔒 Security Review ✅ Completed 2026-09-04T12:45:36.526861Z f16aee4 Manual request
ℹ️ 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 sync and async stream paths now diverge: sync uses _materialize_input_tools(), while async uses _validate_input_tools(). Since .stream() advertises the same auto-parsing rules as .parse(), a non-strict/non-function tool can get through the sync helper but is rejected by the async helper. Could the sync path materialise through _validate_input_tools() too, so the generator fix preserves validation parity?

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Addressed in commit a0a133b. The synchronous .stream() helper now uses the same _validate_input_tools() path as async streaming, preserving the single-pass materialization while rejecting non-strict tools consistently. Added a regression for the sync mismatch; the focused file has 5 passing tests, with Ruff, formatting, and diff checks passing.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: a0a133b165

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

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

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

When the context manager exits, the response will be closed, however the `stream` instance is still available outside
the context manager.
"""
chat_completion_tools = _validate_input_tools(tools)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve non-strict tools in synchronous streams

When chat.completions.stream() receives a non-strict function tool, this validator now raises before sending the request. Synchronous streaming intentionally allows such tools while leaving parsed_arguments unset, as codified by tests/lib/chat/test_completions_streaming.py::test_allows_non_strict_tools_but_no_parsing; therefore this breaks previously valid SDK calls unrelated to the single-pass iterable fix. Materialize the iterable here without applying the parse-only strictness validation.

AGENTS.md reference: AGENTS.md:L5-L8

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in commit afbb292. I confirmed the existing synchronous-stream contract: non-strict function tools must remain accepted and produce parsed_arguments=None. The sync path now materializes the iterable once without strictness validation, while parse and async stream retain validation. Added a single-pass non-strict regression test; the focused suite (5 tests) and the existing non-strict compatibility test both pass, along with Ruff and format checks.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: afbb2920a1

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

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: afbb2920a1

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Addressed the validation-parity feedback in commit 369db3fb. The synchronous .stream() path now uses _validate_input_tools() just like the asynchronous path, so non-strict tools are rejected consistently while single-pass strict iterables are still materialized once.

Validation: tests/lib/chat/test_single_pass_tools.py — 5 passed; Ruff check/format passed.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: 369db3fbdc

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 369db3fbdc

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

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Synced this branch with the latest upstream main at 3cc8d784ad05f75a265012ee86638adaf93d8bf2 using a regular merge (no force-push); current head is ce8a78e3.

Validation after the sync:

  • uv run --locked pytest tests/lib/chat/test_single_pass_tools.py: 5 passed
  • uv run --locked ruff check on changed files: passed
  • uv run --locked ruff format --check on changed files: passed
  • git diff --check origin/main...HEAD: passed

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Addressed the sync/async validation-parity feedback in commit 369db3fb: the sync .stream() path now also calls _validate_input_tools(), while still materializing one-shot iterables exactly once. I added a regression covering a non-strict single-pass generator and retained sync/async strict-tool coverage.

The current merged head ce8a78e3 passes tests/lib/chat/test_single_pass_tools.py (5 passed), Ruff check/format, and the diff check.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: ce8a78e307

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Addressed the streaming compatibility feedback in f16aee4:

  • .stream() now materializes the tool iterable without applying .parse() strict-tool validation, preserving existing support for non-strict function tools in both sync and async streams;
  • .parse() keeps its existing strict-tool validation;
  • the regression test now verifies that a non-strict single-pass iterable is sent unchanged and yields no fabricated parsed arguments.

Validation:

  • PYTHONPATH=src uv run --locked pytest tests/lib/chat/test_single_pass_tools.py — 5 passed;
  • PYTHONPATH=src uv run --locked pytest tests/lib/chat/test_completions_streaming.py — 18 passed;
  • Pydantic v1 single-pass tests — 5 passed;
  • Ruff check/format passed.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: f16aee4265

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

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: f16aee4265

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@Hughhhhcoder

Copy link
Copy Markdown
Contributor Author

Follow-up to the validation-parity review: f16aee4 applies _materialize_input_tools() to both sync and async .stream() paths, so they now have identical non-strict-tool behavior. Both .parse() paths still use _validate_input_tools() and retain strict auto-parsing validation. The single-pass and streaming regressions cover the shared behavior.

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

Sync and async .stream() now both materialize single-pass tool iterables without imposing .parse() strict-tool validation, while both .parse() paths retain that validation. That restores parity without changing existing stream semantics. The regression coverage addresses my finding.

@marcuswood-oai marcuswood-oai changed the title fix: preserve single-pass chat tool iterables fix(chat): preserve single-pass tool iterables Sep 23, 2026

Copy link
Copy Markdown
Contributor

Thanks for catching this and putting together the fix! We’ve merged main into your branch and tightened the tests. The fix looks good, and our checks are passing—happy to get this in!

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Castiron custom code

✅ No new custom-code files detected.

47 mixed files remain; 1 existing customization changed.

Compared 5e39766dd7ba → a260ecba97db. Generated baselines verified.

File Result Current custom patch
src/openai/resources/chat/completions/completions.py Existing customization changed +603 / −1
46 existing customizations unchanged
  • api.md
  • scripts/castiron/README.md
  • scripts/castiron/custom_code_report.py
  • scripts/castiron/test_custom_code_report.py
  • src/openai/init.py
  • src/openai/_client.py
  • src/openai/resources/audio/transcriptions.py
  • src/openai/resources/audio/translations.py
  • src/openai/resources/beta/agents/sessions/sessions.py
  • src/openai/resources/beta/beta.py
  • src/openai/resources/beta/responses/responses.py
  • src/openai/resources/beta/threads/runs/runs.py
  • src/openai/resources/beta/threads/threads.py
  • src/openai/resources/embeddings.py
  • src/openai/resources/files.py
  • src/openai/resources/live/forks.py
  • src/openai/resources/live/live.py
  • src/openai/resources/live/sideband.py
  • src/openai/resources/realtime/api.md
  • src/openai/resources/realtime/realtime.py
  • src/openai/resources/responses/responses.py
  • src/openai/resources/uploads/uploads.py
  • src/openai/resources/vector_stores/file_batches.py
  • src/openai/resources/vector_stores/files.py
  • src/openai/resources/videos.py
  • src/openai/resources/webhooks/init.py
  • src/openai/resources/webhooks/webhooks.py
  • src/openai/types/beta/agent_session_message.py
  • src/openai/types/chat/init.py
  • src/openai/types/chat/chat_completion_message_tool_call.py
  • src/openai/types/fine_tuning/fine_tuning_job_integration.py
  • src/openai/types/realtime/conversation_item_input_audio_transcription_delta_event.py
  • src/openai/types/realtime/realtime_error_event.py
  • src/openai/types/responses/init.py
  • src/openai/types/responses/response.py
  • src/openai/types/responses/response_function_web_search.py
  • src/openai/types/responses/response_function_web_search_param.py
  • src/openai/types/responses/responses_client_event.py
  • src/openai/types/responses/responses_client_event_param.py
  • src/openai/types/responses/tool.py

6 more in the full report.

A changed generated baseline means this report cannot reliably identify which handwritten lines changed.

Inspect the custom-code diff

Download the exact patch produced by this run (requires repository access):

gh run download 35896788760 --repo openai/openai-python \
  --name castiron-custom-code-35896788760-1 --dir /tmp/castiron-custom-code-35896788760-1
git apply --stat /tmp/castiron-custom-code-35896788760-1/custom-code.patch
cat /tmp/castiron-custom-code-35896788760-1/custom-code.patch

Or reproduce it from an SDK checkout containing the vendored reporter:

git fetch --no-tags origin 5e39766dd7ba2802c97f5305721a621098cf0e38 a260ecba97db9dbafe6579798efb76913c4fc2b0
python3 scripts/castiron/custom_code_report.py report \
  --base 5e39766dd7ba2802c97f5305721a621098cf0e38 \
  --head a260ecba97db9dbafe6579798efb76913c4fc2b0 --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-a260ecba97db
cat /tmp/castiron-custom-code-a260ecba97db/custom-code.patch

This is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR.

Full report and patch

@marcuswood-oai
marcuswood-oai added this pull request to the merge queue Sep 23, 2026
Merged via the queue into openai:main with commit 33ffa1f Sep 23, 2026
18 checks passed
@openai-sdks openai-sdks Bot mentioned this pull request Sep 23, 2026
@sylvesterkaczmarek

Copy link
Copy Markdown
Contributor

Thanks for the final pass and merge. Glad the single-pass iterable fix could land without changing the existing non-strict streaming behavior.

pull Bot pushed a commit to Mattlk13/openai-python that referenced this pull request Sep 23, 2026
Automated Release PR
---


##
[3.19.1](openai/openai-python@v3.19.0...v3.19.1)
(2026-09-23)


### Bug Fixes

* **chat:** preserve single-pass tool iterables
([openai#3770](openai#3770))
([33ffa1f](openai@33ffa1f))
* **client:** merge HTTP headers case-insensitively
([openai#3486](openai#3486))
([5e39766](openai@5e39766))


### Chores

* **api:** clarify Chat Completions seed limits
([openai#3945](openai#3945))
([be9d666](openai@be9d666))


### Documentation

* clarify collaborator-only pull request policy
([openai#3948](openai#3948))
([ead1fa2](openai@ead1fa2))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: openai-sdks[bot] <284451331+openai-sdks[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants