fix(chat): preserve single-pass tool iterables - #3770
marcuswood-oai merged 7 commits into
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
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?
|
Addressed in commit |
|
@codex review |
|
Security review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 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) |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
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.
|
@codex review |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Security review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Addressed the validation-parity feedback in commit Validation: |
|
@codex review |
|
Security review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Synced this branch with the latest upstream Validation after the sync:
|
|
Addressed the sync/async validation-parity feedback in commit The current merged head |
|
@codex review |
|
Security review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Addressed the streaming compatibility feedback in f16aee4:
Validation:
|
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Security review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Follow-up to the validation-parity review: f16aee4 applies |
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
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.
|
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! |
Castiron custom code✅ No new custom-code files detected. 47 mixed files remain; 1 existing customization changed. Compared
46 existing customizations unchanged
6 more in the full report. A changed generated baseline means this report cannot reliably identify which handwritten lines changed. Inspect the custom-code diffDownload 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.patchOr 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.patchThis is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR. |
|
Thanks for the final pass and merge. Glad the single-pass iterable fix could land without changing the existing non-strict streaming behavior. |
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>
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
Iterabletype 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.