fix: coerce parameters to tool schema #3791
Open
+202
−2
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.
Ultravox RealtimeModel: preserve JSON types for tool parameters (schema-based coercion)
Summary
This PR fixes a bug where Ultravox
RealtimeModelemitted tool parameters as strings, breaking MCP and other type-strict tools. We now coerce parameters to the correct JSON types based on each tool’s schema before emittingFunctionCall, including proper handling of union types with null.livekit-plugins-ultravoxProblem
Ultravox sometimes sends tool parameters as strings (e.g.,
"10","true","[\"low_stock\"]","null"). We previously forwarded them as-is viajson.dumps(event.parameters), causing downstream validation errors:["integer","null"]) received"null"instead ofnullThis made Ultravox
RealtimeModelincompatible with MCP and other type-strict integrations.What’s changed
Add schema-based coercion to convert stringified values to the correct JSON types:
1e3,-inf, etc.)"true"/"false","1"/"0","yes"/"no", etc.null, map"null"/"None"→null(also foranyOf/oneOf/allOf)Wire coercion into Ultravox tool invocation path:
json.dumps(event.parameters)json.dumps(coerced_params)wherecoerced_paramshonors the tool schemaFiles changed
livekit-plugins/livekit-plugins-ultravox/livekit/plugins/ultravox/utils.pycoerce_parameters_to_schema(tools_ctx, tool_name, params)utilitylivekit-plugins/livekit-plugins-ultravox/livekit/plugins/ultravox/realtime/realtime_model.pycoerce_parameters_to_schema(...)in_handle_tool_invocation_event(...)Before vs After
alert_type:"[\"low_stock\"]"limit:"10"include_valuation:"true"category_id:"null"alert_type:["low_stock"]limit:10include_valuation:truecategory_id:nullThis aligns Ultravox behavior with OpenAI Realtime for tool calling.
Screenshots
Testing
RealtimeModelwith the sample tool callBackward compatibility
Release notes