Handle universal ToolDiscoveryResult type #312
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c27f502bf5
ℹ️ 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 (@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 (@codex) address that feedback".
| let provider_executed = if matches!( | ||
| input.execution.as_ref(), | ||
| Some(openai::ToolSearchExecutionType::Server) | ||
| ) { | ||
| Some(true) | ||
| } else { | ||
| None |
There was a problem hiding this comment.
Preserve client tool_search items on re-export
When a Responses request contains a client-executed tool_search_call, this branch records it as a normal non-provider-executed tool call. The Responses exporter treats those as function_call items, so importing and then re-emitting the same history changes tool_search_call/tool_search_output into ordinary function-call items and loses the typed execution/tools wire shape that OpenAI expects for tool-search history. Preserve enough typed state here, or teach the Responses exporter to emit tool_search_* for tool_name == "tool_search".
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 964b4b0d87
ℹ️ 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 (@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 (@codex) address that feedback".
| })); | ||
| } | ||
|
|
||
| let anthropic_tool = Tool::try_from(tool)?; |
There was a problem hiding this comment.
Normalize Responses discovery tools before Anthropic serialization
When a Responses request uses the normal dynamic-discovery tool config (tools entries like {"type":"tool_search"} or {"type":"namespace"}), parse_openai_responses_tools_array stores those as BuiltinToolProvider::Responses. This new Anthropic serialization path only special-cases Anthropic builtins before calling Tool::try_from, which rejects Responses builtins, so Responses→Anthropic fails instead of emitting the equivalent tool_search_tool_regex and deferred tools. Normalize or filter Responses discovery tools before this conversion.
Useful? React with 👍 / 👎.
| ToolContentPart::ToolResult(result) => Some(result), | ||
| ToolContentPart::ToolDiscoveryResult(_) => None, |
There was a problem hiding this comment.
Avoid emitting empty Bedrock messages for discovery results
For a Responses history containing a tool_search_output, the universal Tool message contains only ToolDiscoveryResult; this filter drops every part, and universal_to_bedrock_messages still pushes a Bedrock user message with content: []. That produces an invalid/meaningless Converse request instead of either dropping discovery-only messages at the message level or returning an explicit unsupported-mapping error.
Useful? React with 👍 / 👎.
| for item in &result.tools { | ||
| item.tool_name.hash(hasher); |
There was a problem hiding this comment.
Include discovered tool definitions in the dedup key
If two imported tool_search_output messages have the same call id and tool names but different returned tool definitions (for example a schema/strictness change), deduplication treats them as identical because only tool_name is hashed. Since ToolDiscoveryResultItem.tool carries the actual definition that is later re-exported to Responses/Anthropic, the second result can be dropped and leave stale tool metadata in the conversation.
Useful? React with 👍 / 👎.
|
Codex (@codex) review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 919f99456c
ℹ️ 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 (@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 (@codex) address that feedback".
| if request.messages.is_none() { | ||
| return Err(ValidationError::DeserializationFailed( | ||
| "missing field `messages`".to_string(), | ||
| )); | ||
| } |
There was a problem hiding this comment.
Enforce required max_tokens in Anthropic validation
This required-field check stops after model and messages, but AnthropicParams made max_tokens optional even though Anthropic Messages requests require it (and try_parse_anthropic still calls required_max_tokens). As a result, validate_anthropic_request now accepts {model, messages} payloads that the old generated CreateMessageParams validation rejected and that Anthropic will not accept.
Useful? React with 👍 / 👎.
| "store", | ||
| "stream_options", | ||
| "top_logprobs", |
There was a problem hiding this comment.
Reject all OpenAI-only fields in Anthropic validation
This validation-only OpenAI field list is shorter than the one used by providers/anthropic/detect.rs; it omits gateway/chat fields such as reasoning_enabled, suffix_messages, and chat_template_kwargs. Because AnthropicParams now flattens unknown fields into extras, an OpenAI-compatible request with model, messages, max_tokens, and one of those extensions will pass validate_anthropic_request, reintroducing the cross-provider false positive this guard is meant to prevent.
Useful? React with 👍 / 👎.
919f994 to
65d3afc
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 65d3afc0f4
ℹ️ 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 (@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 (@codex) address that feedback".
| if name == "tool_search" { | ||
| tool_discovery::input_call_from_tool_arguments(call_id, arguments, id) |
There was a problem hiding this comment.
Avoid keying discovery calls on the function name
When a normal function/tool is named tool_search (for example a Chat Completions function call with a tool of that name), this name-only branch converts it to a Responses tool_search_call instead of a function_call. input_call_from_tool_arguments then expects nested arguments/status/execution fields, so a regular argument map like {"query":"..."} is dropped and the target sees a discovery call rather than the original function call. Use the new ToolDiscoveryCall representation or explicit provider metadata to select this path instead of the function name alone.
Useful? React with 👍 / 👎.
| if capabilities.requires_thought_signature_for_function_call_history { | ||
| add_dummy_thought_signatures_for_transferred_function_call_history(&mut messages); | ||
| } | ||
| messages.retain(|message| !is_discovery_only_message(message)); |
There was a problem hiding this comment.
Re-check Google contents after dropping discovery messages
For a Responses follow-up that contains only dynamic-discovery history, such as previous_response_id plus a tool_search_output, messages is non-empty when the earlier Google validation runs, but this retain removes every remaining message and the adapter then serializes contents: []. Google requests require at least one content message, so this should re-check after filtering and return an unsupported/validation error instead of producing an invalid request.
Useful? React with 👍 / 👎.
ToolDiscoveryResult type
65d3afc to
38c4a5f
Compare
|
Codex (@codex) review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2f648052f8
ℹ️ 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 (@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 (@codex) address that feedback".
| pub(super) fn message_from_output_output( | ||
| item: openai::OutputItem, | ||
| ) -> Result<Message, ConvertError> { | ||
| let tool_call_id = item.call_id.or_else(|| item.id.clone()).ok_or_else(|| { |
There was a problem hiding this comment.
Preserve pairing for null tool-search call IDs
When a Responses response contains server-executed tool_search_call/tool_search_output items with call_id: null, this fallback assigns the output's own id as tool_call_id, while part_from_output_call does the same for the call item. Because those item IDs differ, the universal ToolDiscoveryCall and ToolDiscoveryResult no longer match, so exporting to Anthropic emits a server_tool_use and tool_search_tool_result with different IDs. Track the preceding tool-search call or otherwise preserve a shared synthetic ID for this null-call_id response shape.
Useful? React with 👍 / 👎.
| file_id: None, | ||
| }); | ||
| } | ||
| ToolContentPart::ToolDiscoveryResult(discovery_result) => { |
There was a problem hiding this comment.
Reject unpaired tool-search results for Anthropic
For a valid Responses follow-up that uses an item_reference plus a tool_search_output, there is no adjacent ToolDiscoveryCall in req.messages; this branch still serializes the discovery result as a standalone Anthropic user message containing tool_search_tool_result. The later merge helper only moves it into assistant content when the matching call is present immediately before it, so reference-based follow-ups produce an invalid Anthropic transcript instead of returning an unsupported-mapping error.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ce9398a43
ℹ️ 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 (@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 (@codex) address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6bd1f6b53
ℹ️ 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 (@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 (@codex) address that feedback".
Alex Z (CLowbrow)
left a comment
There was a problem hiding this comment.
I think you can merge this once codex stops complaining
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b495926fa
ℹ️ 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 (@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 (@codex) address that feedback".
| }) if tool_type == "web_search_20250305" | ||
| || tool_type == "google_search" | ||
| || is_anthropic_tool_search_builtin_type(&tool_type) => {} |
There was a problem hiding this comment.
Skip Responses discovery tools for Chat export
When a Responses request uses dynamic discovery, ResponsesAdapter::request_to_universal stores top-level namespace/tool_search entries as BuiltinToolProvider::Responses; transforming that request to Chat Completions then calls tools_to_openai_chat_value, where to_openai_chat_value returns UnsupportedToolType for those builtins and this catch only skips web/search and Anthropic tool-search types. The new responsesToolSearchInputParam case is expected to drop discovery-only history for Chat, but it will fail before message conversion unless the Responses discovery builtins are also skipped or otherwise marked as an intentional unsupported loss.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dbf4a5fc92
ℹ️ 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 (@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 (@codex) address that feedback".
| result.push(openai::InputItem { | ||
| role: None, | ||
| content: None, | ||
| content: Some(openai::InputItemContent::InputContentArray(vec![])), |
There was a problem hiding this comment.
Keep reasoning items content-free
When replaying any Responses history that contains a reasoning item (for example a GPT/o-series follow-up), this now serializes the item as {"type":"reasoning","content":[],"summary":...}. The prior conversion and captured Responses payloads omit content for reasoning items; adding an empty message-content array changes the union shape and can make follow-up requests invalid or break round-trip parity. Leave content as None and carry the summary/encrypted fields only.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e6b75854e7
ℹ️ 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 (@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 (@codex) address that feedback".
| fn has_anthropic_source_markers(request: &AnthropicParams) -> bool { | ||
| request.system.is_some() | ||
| || request.thinking.is_some() | ||
| || request.output_config.is_some() | ||
| || request.cache_control.is_some() | ||
| || request.top_k.is_some() |
There was a problem hiding this comment.
Keep cache_control as an Anthropic source marker
When a Claude Code-style Messages payload uses only top-level cache_control as its Anthropic-specific marker and includes a system-role message with a non-Anthropic model, try_parse_anthropic_source now rejects it because AnthropicParams captures cache_control in extras while this marker check no longer looks there. That regresses the source-detection path for those payloads, so they can fall through to another adapter instead of preserving Anthropic message semantics.
Useful? React with 👍 / 👎.
| pub fn validate_anthropic_request(json: &str) -> Result<AnthropicParams, ValidationError> { | ||
| let request: AnthropicParams = validate_json(json)?; |
There was a problem hiding this comment.
Validate known Anthropic extras with typed fields
Because request validation now deserializes into the partial AnthropicParams, known Anthropic fields that are not declared there, such as top-level cache_control, container, inference_geo, or the enum-shaped service_tier, are accepted in extras with any JSON shape. For example {..., "cache_control": "bad"} now passes validate_anthropic_request even though the generated CreateMessageParams typed this field and would reject it, weakening the validation API for real Anthropic request syntax.
Useful? React with 👍 / 👎.
This reverts commit e6b7585.
There was a problem hiding this comment.
💡 Codex Review
lingua/crates/lingua/src/providers/anthropic/detect.rs
Lines 42 to 43 in 70d13b5
When an OpenAI Chat Completions request uses the legacy functions or function_call fields together with max_tokens, AnthropicParams captures those keys in extras and this guard does not reject them. Such a payload can therefore be detected as Anthropic and passed through by transform_request(..., Anthropic) with OpenAI-only fields instead of being converted or rejected; add the legacy function fields to this OpenAI-only list as well.
ℹ️ 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 (@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 (@codex) address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ddf2fcf89
ℹ️ 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 (@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 (@codex) address that feedback".
| if let ToolContentPart::ToolResult(tool_result) = part { | ||
| result.push(tool_result_to_chat_completion_message(tool_result)?); | ||
| } |
There was a problem hiding this comment.
Filter discovery-only assistant calls for Chat export
Fresh evidence in this version is that this branch drops only the ToolDiscoveryResult half of a dynamic-discovery transcript; the paired Message::Assistant containing only ToolDiscoveryCall still reaches the other arm and extract_content_tool_calls_and_reasoning ignores it, producing an assistant Chat message with no content and no tool_calls. For Responses/Anthropic histories with tool-search calls, Chat export should drop both discovery-only halves or return an unsupported-mapping error instead of emitting an invalid empty assistant message.
Useful? React with 👍 / 👎.
| if !input_message_is_pure_tool_search_result(message) { | ||
| return None; |
There was a problem hiding this comment.
Split mixed tool-search results before Anthropic merge
When a parallel tool-output turn has both a normal ToolResult and a ToolDiscoveryResult in the same Message::Tool, this purity guard returns None, so the later merge/validation is skipped and the tool_search_tool_result remains inside a user message next to regular tool_result blocks. The converter only makes valid Anthropic tool-search history by merging discovery results into the preceding assistant server_tool_use, so mixed tool messages need to be split/merged or rejected instead of emitted in that user-message shape.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6f8116059
ℹ️ 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 (@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 (@codex) address that feedback".
| !matches!( | ||
| msg, | ||
| Message::Tool { content } | ||
| if content | ||
| .iter() | ||
| .all(|part| matches!(part, ToolContentPart::ToolDiscoveryResult(_))) | ||
| ) |
There was a problem hiding this comment.
Drop discovery-only assistant messages from Chat responses
Fresh evidence after the prior request-path fix is that OpenAIAdapter::response_from_universal still drops only discovery result tool messages. When a Responses/Anthropic response contains a discovery-only assistant ToolDiscoveryCall, the filtered resp.messages still sends it through ChatCompletionResponseMessageExt::try_from, which ignores that part and emits a Chat choice with neither content nor tool_calls; this violates the expected ChatCompletions loss of dynamic-discovery history and can produce invalid empty choices. Filter discovery-only assistant messages here too.
Useful? React with 👍 / 👎.
| pub(super) fn message_from_input_output(input: openai::InputItem) -> Result<Message, ConvertError> { | ||
| let tool_call_id = input.call_id.or_else(|| input.id.clone()).ok_or_else(|| { |
There was a problem hiding this comment.
Preserve null call_id pairing for Responses input replay
Fresh evidence is that the null-call_id pairing fix was added only for OutputItem conversion; this InputItem replay path still falls back independently to each item's id. If a follow-up Responses request includes prior tool_search_call/tool_search_output input items with call_id: null (the same shape the response converter now handles), the call gets the call item's id and the result gets the output item's id, so downstream Anthropic export treats them as unpaired or emits mismatched IDs. Track the preceding input call id here as well instead of using the output item id.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6b29a0c9a9
ℹ️ 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 (@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 (@codex) address that feedback".
| logprobs: Option<Value>, | ||
| top_logprobs: Option<Value>, | ||
| logit_bias: Option<Value>, | ||
| response_format: Option<Value>, |
There was a problem hiding this comment.
Treat null OpenAI-only markers as present
If an OpenAI-compatible payload includes one of these guard fields as JSON null, for example {..., "response_format": null} with model, messages, and max_tokens, serde deserializes this Option<Value> as None, so first_present() does not reject it. Because the generated Anthropic request type ignores unknown fields, such payloads can still pass Anthropic detection/validation; use presence-aware fields or a raw typed map so null OpenAI markers are rejected too.
Useful? React with 👍 / 👎.
| if blocks.is_empty() { | ||
| continue; |
There was a problem hiding this comment.
Drop discovery-only assistant calls for Bedrock
When converting a Responses/Anthropic history with a tool_search_call/tool_search_output pair to Bedrock, this empty-block skip only covers the Tool result half. The preceding assistant message containing only ToolDiscoveryCall falls through to BedrockMessage::try_from, where that part is ignored and the request emits an assistant message with content: [], which Converse rejects. Filter or reject discovery-only assistant messages in the same path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2dd99e171e
ℹ️ 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 (@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 (@codex) address that feedback".
| if !normalized | ||
| .iter() | ||
| .any(|existing: &UniversalTool| existing.name == expanded_tool.name) |
There was a problem hiding this comment.
Preserve namespace collisions when flattening deferred tools
When a Responses request has two namespace tools that both contain a function with the same local name, calls remain distinguishable by the namespace field, but this name-only dedup drops the second expanded tool. The Anthropic request then advertises only one deferred definition for both namespaces, so discovery output or later calls for the dropped namespace are mapped to the wrong schema instead of returning an unsupported non-lossy mapping error.
Useful? React with 👍 / 👎.
| let view: ToolDiscoveryQueryView = serde_json::from_value(arguments_to_value(arguments)) | ||
| .map_err(|e| ConvertError::JsonSerializationFailed { | ||
| field: "tool_discovery.arguments".to_string(), | ||
| error: e.to_string(), | ||
| })?; |
There was a problem hiding this comment.
Handle string tool-search arguments before reading query
If a Responses tool_search_call uses the string arm that the generated InputItem.arguments type accepts, for example a JSON string like "{\"query\":\"foo\"}", this deserializes the string itself as ToolDiscoveryQueryView and returns an error before the original arguments can be preserved. That makes otherwise deserializable tool-search history fail on import/replay; parse JSON strings first or treat them as opaque arguments with query: None.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 228d870dc0
ℹ️ 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 (@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 (@codex) address that feedback".
| if is_discovery_only_assistant_message(&message) { | ||
| continue; |
There was a problem hiding this comment.
Reject all-discovery histories before emitting Bedrock
When the source history contains only dynamic-discovery items, this filter drops the ToolDiscoveryCall assistant message and the Message::Tool branch below drops the paired ToolDiscoveryResult because it produces no Bedrock blocks. BedrockAdapter::request_from_universal then serializes the returned vector as messages: [], producing an invalid Converse request instead of a clear unsupported/validation error; add a post-filter empty check like the Google path uses.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9e55f2e9e
ℹ️ 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 (@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 (@codex) address that feedback".
07e3fcf to
ae000c4
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f0ed01ddeb
ℹ️ 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 (@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 (@codex) address that feedback".
| if existing.responses_namespace.is_some() | ||
| && expanded_tool.responses_namespace.is_some() |
There was a problem hiding this comment.
Reject namespace/function name collisions
When a Responses tool list has both a top-level function and a namespace tool with the same local function name, Responses can still distinguish calls via the namespace field, but this check only rejects collisions where both definitions came from namespaces. A namespace-vs-function collision falls through and drops whichever definition is encountered second, so Anthropic receives a single name-only tool with the wrong schema for one of the call sites instead of an explicit unsupported-mapping error.
Useful? React with 👍 / 👎.
| .map(|item| generated::RequestToolReferenceBlock { | ||
| cache_control: None, | ||
| tool_name: item.tool_name, |
There was a problem hiding this comment.
Reject unknown tool-search result payloads
If result_from_input_content/result_from_response_content hits an unrecognized tool_search_tool_result.content, unknown_result_items stores the original payload in provider_options, but this export path ignores that field and emits only a tool_reference named from item.tool_name (often unknown). In that scenario an unsupported Anthropic result payload is silently rewritten as a successful empty discovery reference, so the converter should either re-emit the preserved content or return an unsupported-mapping error.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f23f6a56a4
ℹ️ 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 (@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 (@codex) address that feedback".
| for part in content { | ||
| let ToolContentPart::ToolResult(tool_result) = part; | ||
| result.push(tool_result_to_chat_completion_message(tool_result)?); | ||
| if let ToolContentPart::ToolResult(tool_result) = part { |
There was a problem hiding this comment.
Reject all-discovery Chat requests after filtering
Fresh evidence in this version is that the Chat export now skips discovery-only assistant calls and only emits normal ToolResult parts here; if a Responses follow-up contains only dynamic-discovery history, such as previous_response_id plus a tool_search_output or a tool_search_call/tool_search_output pair, this returns an empty message vector and request_from_universal serializes messages: []. Chat Completions requests require at least one message, so this should return an unsupported/validation error instead of emitting an invalid request.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: af16050c15
ℹ️ 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 (@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 (@codex) address that feedback".
| if capabilities.requires_thought_signature_for_function_call_history { | ||
| add_dummy_thought_signatures_for_transferred_function_call_history(&mut messages); | ||
| } | ||
| messages.retain(|message| !is_discovery_only_message(message)); |
There was a problem hiding this comment.
Move discovery filtering before flattening Google messages
When a Responses history has normal content on both sides of discovery-only items (for example user → tool_search_call/output → user, as in the new fixture), this retain runs after flatten_consecutive_messages, so dropping the discovery messages creates two adjacent user messages that are never flattened. The adapter comment above says Google doesn't allow consecutive same-role messages, so these requests can still serialize invalid contents; filter discovery-only messages before flattening, or flatten again after this step.
Useful? React with 👍 / 👎.

Summary
Adds cross-provider support for Responses
tool_search/ deferred tool discovery, including Anthropic tool-searchtranslation and universal message/tool representations for discovery calls and results.
Also tightens Anthropic validation to continue rejecting OpenAI-shaped payloads now that unknown fields are captured
in
extras.Changes
ToolDiscoveryCall/ToolDiscoveryResultcontent parts.UniversalTool.tool_search_callandtool_search_outputto/from universal messages.openai/tool_discovery.rsandanthropic/tool_discovery.rsto keepconverters/adapters readable.
responsesToolSearchInputParam.max_tokensin Anthropic validation and reject OpenAI/gateway-only fields likereasoning_enabled,suffix_messages, andchat_template_kwargs.Testing