Skip to content

fix(openai): omit absent tool description, never serialise a null schema - #8

Merged
AlexMikhalev merged 1 commit into
mainfrom
fix/openai-tool-serialisation-nulls
Aug 30, 2026
Merged

fix(openai): omit absent tool description, never serialise a null schema#8
AlexMikhalev merged 1 commit into
mainfrom
fix/openai-tool-serialisation-nulls

Conversation

@AlexMikhalev

Copy link
Copy Markdown

The OpenAI adapter built each tool with json!, so both optional fields serialised as explicit nulls when unset:

"description": tool.description   // None -> null
"parameters":  tool.schema        // None -> null

Neither is valid. description is optional in the OpenAI function schema, and omitting a key is not the same as sending null — providers that validate the payload reject a null where a string is expected. parameters is worse: it is required to be a schema object, so null is not a legal value at all.

Builds the function object explicitly instead: description is inserted only when present, and parameters falls back to {"type": "object"} — the empty schema, which is what a tool taking no arguments actually means.

strict: false is deliberately unchanged. It is the documented default, and altering it would change structured-output behaviour for every adapter sharing this serialiser. The existing TODO about strict: true needing additionalProperties: false is left for whoever takes that on.

Why it is reachable

terraphim-llm-proxy accepts tools in both the OpenAI shape ({type, function:{...}}) and the Anthropic shape ({name, input_schema}), and the Anthropic form frequently carries no description. It began routing tools through this serialiser in terraphim-llm-proxy#89.

Tests

Five added; the first and third fail against the previous code.

  • absent description omitted rather than nulled
  • present description still serialises
  • absent schema falls back to the empty object schema, never null
  • present schema passes through verbatim
  • strict and the type: function envelope preserved

cargo test --lib: 70 passed. cargo fmt --check: clean.

Pre-existing, untouched: cargo clippy -- -D warnings fails on src/webc/web_stream.rs (collapsible_match) on main as well.

The OpenAI adapter built each tool with `json!`, so both optional fields
serialised as explicit nulls when unset:

    "description": tool.description   // None -> null
    "parameters":  tool.schema        // None -> null

Neither is valid. `description` is optional in the OpenAI function schema, and
omitting a key is not the same as sending `null` — providers that validate the
payload reject a null where a string is expected. `parameters` is worse: it is
*required* to be a schema object, so `null` is not a legal value at all.

Builds the function object explicitly instead: `description` is inserted only
when present, and `parameters` falls back to `{"type": "object"}` — the empty
schema, which is what a tool taking no arguments actually means.

`strict: false` is deliberately unchanged. It is the documented default, and
altering it would change structured-output behaviour for every adapter that
shares this serialiser; the existing TODO about `strict: true` needing
`additionalProperties: false` is left in place for whoever takes that on.

Reachable in practice: terraphim-llm-proxy accepts tools in both the OpenAI
shape (`{type, function:{...}}`) and the Anthropic shape (`{name,
input_schema}`), and the Anthropic form frequently carries no description.

## Tests

Five in `adapter_shared::tests`:
- absent description is omitted rather than nulled
- present description still serialises
- absent schema falls back to the empty object schema, never null
- present schema passes through verbatim
- `strict` and the `type: function` envelope are preserved

The first and third fail against the previous code.

Note: `cargo clippy -- -D warnings` fails on `src/webc/web_stream.rs`
(collapsible_match). That is pre-existing on main and untouched here.
@AlexMikhalev
AlexMikhalev merged commit ae519b6 into main Aug 30, 2026
1 check passed
@AlexMikhalev
AlexMikhalev deleted the fix/openai-tool-serialisation-nulls branch August 30, 2026 22:05
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