feat(responses): accept non-standard tool and input item types for Codex compatibility#5456
feat(responses): accept non-standard tool and input item types for Codex compatibility#5456franciscojavierarceo wants to merge 2 commits intoogx-ai:mainfrom
Conversation
…dex compatibility External clients like OpenAI Codex send tool types (local_shell, tool_search, image_generation, custom) and input item types (local_shell_call, custom_tool_call, tool_search_call) that are not part of the standard OpenAI Responses API. Previously these caused 422 validation errors because the Pydantic unions used strict discriminators. This adds catch-all models (OpenAIResponseInputToolCustom for tools, OpenAIResponseInputUnknown for input items) and switches the unions from discriminated to left-to-right mode so that known types are matched first and unknown types are gracefully accepted. Client-side tool types are skipped during chat conversion since the model doesn't need to see them. Also adds the verbosity field to OpenAIResponseText which Codex sends in its text configuration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
✱ Stainless preview buildsThis PR will update the Edit this comment to update it. It will appear in the SDK's changelogs.
|
| 💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputToolCustom` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`. |
| 💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputUnknown` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`. |
| 💡 Go/SchemaUnionDiscriminatorMissing: This union schema has more than one object variant, but no [`discriminator`](https://www.stainless.com/docs/reference/openapi-support#discriminator) property, so deserializing the union may be inefficient or ambiguous. |
✅ llama-stack-client-openapi studio · code · diff
Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️New diagnostics (2 note)
💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputToolCustom` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`. 💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputUnknown` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`.
✅ llama-stack-client-python studio · code · diff
Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️→build ✅(prev:build ⏭️) →lint ✅(prev:lint ⏭️) →test ✅pip install https://pkg.stainless.com/s/llama-stack-client-python/ff5da08122fac6aa448a391db595940fc2bec848/llama_stack_client-0.7.0a2-py3-none-any.whlNew diagnostics (2 note)
💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputToolCustom` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`. 💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputUnknown` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`.
✅ llama-stack-client-node studio · code · diff
Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️→build ✅(prev:build ⏭️) →lint ✅(prev:lint ⏭️) →test ✅npm install https://pkg.stainless.com/s/llama-stack-client-node/556a4fb5c22acd7fffd45db06e7892a33941bff4/dist.tar.gzNew diagnostics (2 note)
💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputToolCustom` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`. 💡 Model/Recommended: `#/components/schemas/OpenAIResponseInputUnknown` could potentially be defined as a [model](https://www.stainless.com/docs/guides/configure#models) within `#/resources/responses`.
This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-04-06 23:33:02 UTC
|
This pull request has merge conflicts that must be resolved before it can be merged. @franciscojavierarceo please rebase it. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork |
mattf
left a comment
There was a problem hiding this comment.
@franciscojavierarceo tool types of local_shell, tool_search, image_generation, custom are standard, see https://developers.openai.com/api/reference/resources/responses/methods/create.
we should definitely recognize them, even if stack shouldn't do anything to implement them, e.g. stack treats them like the function case. if an llm requests local shell or tool search, we need to make sure the client gets a chance to implement them. if they're something we should implement, e.g. web_search w/o a tool_runtime, we should return 501.
Summary
OpenAIResponseInputToolCustomcatch-all model for non-standard tool types (local_shell,tool_search,image_generation,custom) sent by external clients like OpenAI CodexOpenAIResponseInputUnknowncatch-all model for non-standard input item types (local_shell_call,custom_tool_call,tool_search_call, etc.)OpenAIResponseInputToolandOpenAIResponseToolunions from strictdiscriminator="type"tounion_mode="left_to_right"so known types match first and unknown types are gracefully acceptedverbosityfield toOpenAIResponseText(Codex sendstext: {verbosity: "low"})Context
When Codex CLI sends requests through Llama Stack as a proxy, it includes tool types and input items that are specific to the OpenAI Responses API but not part of the standard spec that Llama Stack implements. For example, Codex sends
{"type": "local_shell"}tools and{"type": "local_shell_call", ...}input items representing shell command executions. Without this change, these cause 422 validation errors.The fix uses a catch-all pattern: specific types are tried first in the union, and the catch-all model (with
extra="allow") matches anything that didn't match above. Client-side items are silently skipped during chat conversion since the model already processed them on previous turns.Test plan
test_codex_compat.pycovering:ToolContext.available_tools()with custom toolsconvert_response_input_to_chat_messages()skipping unknown itemsOpenAIResponseText.verbosityfield🤖 Generated with Claude Code