Skip to content

fix(translation): validate known request fields - #317

Open
nachiketb-nvidia wants to merge 1 commit into
mainfrom
nachiketb/switch-1205-decoder-validation
Open

fix(translation): validate known request fields#317
nachiketb-nvidia wants to merge 1 commit into
mainfrom
nachiketb/switch-1205-decoder-validation

Conversation

@nachiketb-nvidia

@nachiketb-nvidia nachiketb-nvidia commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

What

Validate known request fields before decoding OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages payloads into the neutral IR.

The decoder now distinguishes malformed JSON types (InvalidType) from unsupported values (InvalidValue) and reports the exact JSON path. Unknown fields and unknown content-block types remain preserved for forward compatibility.

This also corrects the Responses encoder's image and file shapes so payloads emitted by Switchyard satisfy the same validation contract.

Closes SWITCH-1205.

Why

Several decoder paths previously used permissive accessors such as as_str, as_array, or as_object. A malformed known field could therefore be dropped, defaulted, or normalized into a different valid request instead of being rejected at the translation boundary.

Error contract

Condition Translation error Message shape
A known field has the wrong JSON type or container shape InvalidType expected <type> at <JSONPath>
A known enum or numeric field has the correct JSON type but an unsupported value InvalidValue invalid value at <JSONPath>: <reason>
A field is omitted where the decoder already permits omission No error Existing default or optional behavior is preserved
An unknown provider extension or unknown content-block type is present No new error Existing preservation policy remains authoritative

Source of truth and checks

OpenAI Chat Completions

Source: Create chat completion

Request surface What and how we check Error thrown in translation
model, stream, temperature, top_p Validate string, boolean, and numeric scalar types when present; preserve documented nullable optional fields InvalidType, e.g. expected boolean at $.stream
max_completion_tokens, legacy max_tokens Require a non-negative integer when non-null InvalidType for non-numeric JSON; InvalidValue, e.g. invalid value at $.max_completion_tokens: expected a non-negative integer
response_format Require an object when non-null InvalidType at $.response_format
reasoning_effort Require a string in the supported API value set InvalidType for non-string JSON; InvalidValue naming the unsupported value and allowed values
messages and each message Require an array of objects InvalidType, e.g. expected object at $.messages[0]
Message role Require a string in system, developer, user, assistant, tool, or legacy function InvalidType or InvalidValue at $.messages[n].role
Message content Require a string or content-block array; allow null only for the documented assistant/legacy function cases InvalidType, e.g. expected string or array at $.messages[0].content
Known text/refusal/image/file blocks Validate each block object and its known nested string/object/detail fields InvalidType or InvalidValue at the full block path, such as $.messages[0].content[0].image_url.detail
Assistant tool_calls Require an array of call objects; validate IDs, call type, function object, name, and string arguments InvalidType or InvalidValue, e.g. expected string at $.messages[0].tool_calls[0].function.arguments
tools and function definitions Require an array of objects; validate function name/description, object parameters, and boolean strict InvalidType at the exact definition field
tool_choice Require none, auto, required, or an object; validate named function selection InvalidType or InvalidValue at $.tool_choice or its nested field

OpenAI Responses

Source: Create a response

Request surface What and how we check Error thrown in translation
model, stream, temperature, top_p Validate string, boolean, and numeric scalar types when present; preserve documented nullable optional fields InvalidType at the exact top-level path
max_output_tokens Require a non-negative integer when non-null InvalidType or InvalidValue, e.g. invalid value at $.max_output_tokens: expected a non-negative integer
instructions Require a string when non-null InvalidType, e.g. expected string at $.instructions
text.format Require nested objects and a string type when present InvalidType at $.text, $.text.format, or $.text.format.type
reasoning.effort Require a reasoning object and a supported effort string InvalidType or InvalidValue at $.reasoning.effort
input Require a string or array; explicitly reject boolean, number, object, and null containers InvalidType, e.g. expected string or array at $.input
Message input items Require objects; validate message role and string-or-array content InvalidType or InvalidValue at $.input[n], .role, or .content
Function call items Validate string call_id, name, and arguments InvalidType, e.g. expected string at $.input[0].arguments
Function call output items Validate string call_id and string-or-content-array output InvalidType, e.g. expected string or array at $.input[0].output
Reasoning items Validate nullable text plus array-shaped content and summary blocks InvalidType at the exact reasoning item path
Known text/refusal/image/file blocks Validate block objects; require string image/file references and supported image detail values InvalidType or InvalidValue, e.g. expected string at $.input[0].content[0].image_url
tools Require an array of objects; validate known function definitions, IDs, and object-shaped compatibility schemas InvalidType at $.tools or the exact nested field
tool_choice Require none, auto, required, or an object; validate named function selection InvalidType or InvalidValue at $.tool_choice or its nested field

Anthropic Messages

Sources: Create a Message and Effort

Request surface What and how we check Error thrown in translation
model, stream, temperature, top_p, top_k Validate string, boolean, numeric, and non-negative integer types; Anthropic fields are not silently treated as nullable InvalidType or InvalidValue at the exact top-level path
max_tokens Require a non-negative integer; accept 0 as documented InvalidType, e.g. expected non-negative integer at $.max_tokens, or InvalidValue for negative/fractional values
system Require a string or array of text-block objects; omission remains the way to send no system prompt InvalidType, e.g. expected string or array of text blocks at $.system
messages and each message Require an array of objects InvalidType, e.g. expected object at $.messages[0]
Message role Require user or assistant; reject a message-level system role because Anthropic uses top-level system InvalidType or InvalidValue at $.messages[n].role
Message content Require a string or array of content-block objects InvalidType at the exact content or block path
Text and thinking blocks Validate known text, thinking, and signature fields as strings InvalidType at the exact block field
tool_use and tool_result blocks Validate IDs/names as strings, tool input as an object, result error flag as boolean, and nested result content recursively InvalidType, e.g. expected object at $.messages[0].content[0].input
Image and document blocks Require known source values to be objects InvalidType at the block's .source path
tools Require an array of tool objects; validate type/name/description strings and object input_schema InvalidType, e.g. expected object at $.tools[0].input_schema
tool_choice Require an object; validate auto, any, tool, or none, optional tool name, and boolean parallel-use flag InvalidType or InvalidValue at $.tool_choice or its nested field
thinking Require an object; validate enabled, disabled, or adaptive and a non-negative integer budget InvalidType or InvalidValue at $.thinking or its nested field
output_config Require an object; validate supported effort strings and object-shaped structured output format when non-null InvalidType or InvalidValue at $.output_config or its nested field

Scope boundaries

  • This validates known fields before normalization; it does not add required-field presence checks.
  • It does not reject unknown top-level fields or unknown block types.
  • It does not enforce model-specific ranges or cross-field constraints.
  • It does not change response decoding.

What to review

  • Whether each known field is validated at the narrowest useful JSON path.
  • Whether InvalidType versus InvalidValue is applied consistently.
  • Whether optional/null handling matches each provider rather than being generalized across formats.
  • Whether unknown provider extensions remain unaffected.

Validation

  • cargo test -p switchyard-translation
  • cargo clippy -p switchyard-translation --all-targets -- -D warnings
  • Commit hooks: cargo fmt, cargo clippy, and commitlint

Summary by CodeRabbit

  • Bug Fixes
    • Improved validation for Anthropic, OpenAI Chat, and OpenAI Responses requests.
    • Malformed field types, unsupported values, and unknown message roles now produce clear structured errors.
    • Improved handling of image, file, tool, streaming, sampling, and token-limit inputs.
    • Preserved supported formats for function-call arguments and Anthropic tool inputs.
  • Tests
    • Expanded coverage for invalid requests, error paths, content formats, and round-trip translations.

Signed-off-by: nachiketb <nachiketb@nvidia.com>
@nachiketb-nvidia
nachiketb-nvidia requested a review from a team as a code owner August 5, 2026 23:23
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

Request validation and decoding

Layer / File(s) Summary
Shared JSON validation helpers
crates/switchyard-translation/src/util.rs
Added typed validators for JSON types, non-negative integers, and allowed string enums.
OpenAI Chat request validation
crates/switchyard-translation/src/codecs/openai_chat/buffered.rs, crates/switchyard-translation/src/codecs/openai_chat/mod.rs
Added validation for requests, messages, content, tools, function definitions, and tool choices.
OpenAI Responses validation and media encoding
crates/switchyard-translation/src/codecs/responses/buffered.rs
Added nested request validation, stricter role handling, and image/file source encoding for URL, base64, ID, filename, and raw-source variants.
Anthropic request validation
crates/switchyard-translation/src/codecs/anthropic/buffered.rs
Added validation for request fields, messages, content, tools, tool choices, thinking, output configuration, and roles.
Fixtures and validation tests
crates/switchyard-translation/tests/lossless_roundtrip.rs, crates/switchyard-translation/tests/request_translation.rs
Updated request fixtures and added typed error coverage across all three codecs.

Estimated code review effort: 4 (Complex) | ~60 minutes

Poem

I’m a rabbit guarding JSON tight,
With typed errors clean and bright.
Tools and roles now hop in line,
Strings and numbers check out fine.
The codecs burrow, tests rejoice—
Validation sings with one clear voice.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: validation of known request fields in the translation layer.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

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

🧹 Nitpick comments (1)
crates/switchyard-translation/src/codecs/openai_chat/buffered.rs (1)

582-585: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the shared validator.

validate_function_definition is now crate-visible and is consumed by crates/switchyard-translation/src/codecs/responses/buffered.rs through the re-export in crates/switchyard-translation/src/codecs/openai_chat/mod.rs. Add a short /// comment that states the shape it validates and that both OpenAI Chat and OpenAI Responses tool definitions use it.

♻️ Proposed doc comment
+/// Validates the shared OpenAI function-definition shape (`name`,
+/// `description`, `parameters`, `strict`). OpenAI Chat and OpenAI Responses
+/// tool definitions both use this contract.
 pub(crate) fn validate_function_definition(
     function: &Map<String, Value>,
     path: &str,
 ) -> Result<()> {

As per coding guidelines: "Add concise /// documentation for public Rust items and comments for module intent, non-obvious private helpers, and important validation, routing, configuration, async, lifecycle, concurrency, and test behavior."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/switchyard-translation/src/codecs/openai_chat/buffered.rs` around
lines 582 - 585, Add a concise Rust doc comment directly above
validate_function_definition describing the function-definition shape it
validates and noting that both OpenAI Chat and OpenAI Responses tool definitions
use this shared validator.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/switchyard-translation/src/codecs/openai_chat/buffered.rs`:
- Around line 582-585: Add a concise Rust doc comment directly above
validate_function_definition describing the function-definition shape it
validates and noting that both OpenAI Chat and OpenAI Responses tool definitions
use this shared validator.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b3ad9625-26cc-4a76-b76a-0511ed9648b7

📥 Commits

Reviewing files that changed from the base of the PR and between 70aeb1f and 7cef54b.

📒 Files selected for processing (7)
  • crates/switchyard-translation/src/codecs/anthropic/buffered.rs
  • crates/switchyard-translation/src/codecs/openai_chat/buffered.rs
  • crates/switchyard-translation/src/codecs/openai_chat/mod.rs
  • crates/switchyard-translation/src/codecs/responses/buffered.rs
  • crates/switchyard-translation/src/util.rs
  • crates/switchyard-translation/tests/lossless_roundtrip.rs
  • crates/switchyard-translation/tests/request_translation.rs

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.

1 participant