fix(api): accept official Responses text.format structured types - #681
Closed
cursor[bot] wants to merge 16 commits into
Closed
fix(api): accept official Responses text.format structured types#681cursor[bot] wants to merge 16 commits into
cursor[bot] wants to merge 16 commits into
Conversation
…closed otherwise Chat history: message-level audio and legacy function_call are null/empty omit no-ops; non-empty fail closed with named errors (including tools passthrough). Tip substrate from #577 assistant refusal/annotations honesty. Local full unit: 940 passed.
…ed otherwise OpenAI fine-tune style message weight is not applied on this gateway. Accept null/0/1 as honest no-ops; reject other types and values with invalid_message_weight. Tip substrate from #578. Local full unit: 943 passed.
…ion role Reject unsupported message keys with named unknown_message_fields (not silent strip or tools-passthrough smuggle). Reject legacy function role with invalid_message_role migration to tool. Tip substrate from #579. Local full unit: 947 passed.
OpenAI partial-assistant prefix flag is not applied on this gateway. null/false are honest no-ops; true and non-booleans fail closed with invalid_message_prefix. Tip substrate from #580. Local full unit: 950 passed.
…therwise Named invalid_max_tool_calls on /v1/chat/completions instead of opaque unknown_fields. Aligns with Responses max_tool_calls honesty; gateway has no multi-step tool loop.
…losed otherwise Legacy /v1/completions treated max_tool_calls as unknown_fields. Accept the key for named invalid_max_tool_calls (null/empty/whitespace omit-equivalent), matching chat/Responses honesty so SDKs get a clear migration path.
SDK clients often send include_usage/include_obfuscation as JSON null. Drop null flag values before validation so null (and null+false mixes) match omit / all-false no-ops on chat, Completions, and Responses. True flags remain fail-closed with invalid_stream_options.
…or Responses parallel true SDK optional defaults often send function.strict and json_schema.strict as null — treat as omit rather than type errors. Align Responses parallel_tool_calls=true with chat by requiring a non-empty tools array.
SDK optional defaults often send description and parameters as JSON null. Treat null as omit rather than type errors; non-null non-string/object values remain fail-closed with invalid_tools.
OpenAI-style tool descriptions are at most 1024 characters. Over-long descriptions fail closed with named invalid_tools so SDKs never believe a truncated description was accepted.
SDK optional participant name blanks ("" / whitespace) are omit-equivalent
like JSON null. Non-string, over-long, and invalid charset names remain
fail-closed with invalid_message_name.
…ll as omit SDK optional defaults often send top_logprobs as "" and tool_calls function.arguments as JSON null. Empty/whitespace top_logprobs matches null/0 omit on chat and Completions; null arguments normalizes to empty JSON-text string. Non-zero top_logprobs and non-string arguments stay fail-closed.
SDK optional defaults often send instructions as empty or blank. Match JSON null omit-equivalent behavior so blank instructions do not fail closed as invalid_instructions; non-string and oversized remain rejected.
SDK null/empty/whitespace instructions are now omit-real: the key is removed so /v1/responses does not forward a blank system prompt. HTTP tests lock the mock echo, and the OpenAPI/docs contract tells callers to send a non-empty string when they want instructions. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
OpenAI SDKs send text: {format: {type: "text"}} as the default output
control. Rejecting that official default as invalid_text contradicted
response_format type=text on the same surface. Forward the default;
keep fail-closed for other non-empty text objects.
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
The type=text default opened a dual-plane hole: official text plus response_format both reached the provider. Accept json_object and flat json_schema on text.format, pop null/blank optionals, and fail-closed on verbosity and dual-plane so buyers get one honest output control. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
seonghobae
marked this pull request as ready for review
August 16, 2026 17:05
seonghobae
enabled auto-merge (squash)
August 16, 2026 17:05
Author
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
Contributor
|
Superseded by tip substrate ≥ #691 (cumulative OpenAI/gateway honesty band + auto-merge tip). Closing to free product-gate runners (Full unit + Semgrep). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Unique tip on #666 (
2f420a9). Official SDKs send structured output on the Responsestext.formatplane. #666 accepted only{format: {type: text}}, which opened a dual-plane hole: that default plusresponse_formatboth reached the provider.This tip makes the official plane real:
_validate_responses_textacceptstext/json_object/ flatjson_schema(type/name/schema/ optionaldescription/strict).descriptionand JSON-nullstrictare popped before proxy (omit-real). Mockecho.textlocks that.text.verbosity(except JSON null / blank) and sending bothtextandresponse_formatreturninvalid_text.text.format— fix(api): accept official Responses text.format omit-real #657 is the same slice on the older fix(api): pop null json_schema description/strict omit-real before proxy #646 substrate.Review this commit only
8b6cb23— do not merge this honesty stack ontomain. Parent unique tip is #666 / #649.Test plan
python3 tests/test_responses_text_format_http_honesty.pypython3 tests/test_responses_conversation_controls_http_honesty.pypython3 tests/test_responses_response_format_http_honesty.pypython3 tests/test_sdk_null_legacy_controls_noop_http_honesty.pypython3 tests/test_function_call_reasoning_empty_noop_http_honesty.pypython3 tests/test_empty_string_reasoning_text_include_noop_http_honesty.pypython3 tests/test_api_contract.pypython3 tests/test_product_planning_contract.pypython3 tests/test_paper_contracts.pypython3 tests/test_conventions.pypython3 tests/test_self_check.pypython3 tests/test_openai_passthrough.pyBuyer next action
Point SDKs at
/v1/responses. Send one officialtext.formatobject (text/json_object/ flatjson_schema). If you seeinvalid_text, you senttext.verbosity, an unknown key, or bothtextandresponse_format— drop the extra plane and retry. Do not send chat-nestedresponse_format.json_schemaon this surface.