fix(functions): honor function_arguments_key when building the tool grammar - #11677
fix(functions): honor function_arguments_key when building the tool grammar#11677Anai-Guo wants to merge 3 commits into
Conversation
…rammar
All four call sites of `Functions.ToJSONStructure(name, args string)` pass
`FunctionsConfig.FunctionNameKey` as *both* arguments, so
`FunctionArgumentsKey` never reaches the grammar generator.
`ToJSONStructure` writes the two properties into the same map:
property[nameKey] = FunctionName{Const: function.Name}
property[argsKey] = Argument{...}
When `nameKey == argsKey` the second assignment overwrites the first, so a
model configured with `function_name_key` gets a grammar carrying only the
arguments object -- the `{"const": "<function name>"}` constraint is gone and
the grammar can no longer express which function was called.
With `function_name_key: function`, the generated property set collapses from
{"function": {"const": "get_weather"}, "arguments": {...}}
to
{"function": {"type": "object", "properties": {...}}}
Setting only `function_arguments_key` is equally broken in the other
direction: the grammar keeps emitting `arguments` while `ParseFunctionCall`
(pkg/functions/parse.go) looks up the configured key, so the parsed call comes
back with its arguments empty.
The default configuration is unaffected -- with both keys empty
`ToJSONStructure` falls back to `name`/`arguments` for both parameters, which
is why this went unnoticed.
The existing `ToJSONStructure()` unit test already calls the helper with two
distinct keys, so only the call sites were wrong. Extend that test with a case
that keeps both custom keys distinct and asserts the two properties survive.
Signed-off-by: Anai-Guo <antai12232931@outlook.com>
Route grammar construction through FunctionsConfig so the regression test covers the key wiring used by every endpoint. Assisted-by: Codex:gpt-5
|
I pushed a small follow-up that routes grammar construction through The DCO check rejects my bot-authored follow-up because project policy does not allow me to add a human |
|
Heads-up on the red DCO check: it is not on my commit. The DCO app accepts a remediation commit from the original author, so whoever runs that bot can clear it with: Alternatively, if you would rather I re-author that change under my own sign-off, say the word and I will reapply it as a signed commit. |
|
Review pass. The fix is correct and I traced it end to end. The only blocker is not your fault. The bug is real and the fix is right. All four call sites passed Blocking, and a maintainer problem rather than yours: DCO fails because commit Suggestion, not blocking: the new test exercises No docs change needed: Separately, I approved the stalled workflow runs on this PR so CI can actually exercise it. Note that |
|
Correction to my previous comment: I said I had approved the stalled workflow runs on this PR. That did not actually take effect. The runs are A maintainer still needs to click "Approve and run workflows" on this PR, or the branch needs a fresh push to trigger new runs. The substance of the review above is unchanged: |
Signed-off-by: Tai An <antai12232931@outlook.com>
14299bf to
deafcb2
Compare
|
Small correction to my 09-03 note: two commits were failing DCO, not one. The check is still red on the one remaining commit, |
|
Thanks for this PR! The DCO check is failing because the commits are not signed off. Please amend your commits with |
|
Code review: the fix is correct and important. Currently Only blocker: DCO. All 3 commits need |
Description
FunctionsConfigexposes two independent settings:All four call sites of
Functions.ToJSONStructure(name, args string)passFunctionNameKeyas both arguments, soFunctionArgumentsKeyneverreaches the grammar generator:
core/http/endpoints/openai/chat.go:352core/http/endpoints/openai/realtime_model.go:292core/http/endpoints/openresponses/responses.go:223core/http/endpoints/openresponses/websocket.go:286ToJSONStructurewrites both entries into the same map:When
nameKey == argsKey, the second assignment overwrites the first.Effect
Setting
function_name_keycollapses the generated property set from twoproperties to one, and the surviving one is the arguments object — the
{"const": "<function name>"}constraint is gone, so the grammar can nolonger express which function was called. Running the real
ToJSONStructureover a one-function list:ToJSONStructure("function", "function")(today, withfunction_name_key: function){"function":{"type":"object","properties":{"city":{"type":"string"}}}}ToJSONStructure("function", "parameters")(this PR){"function":{"const":"get_weather"},"parameters":{"type":"object","properties":{"city":{"type":"string"}}}}ToJSONStructure("", "")(default config){"name":{"const":"get_weather"},"arguments":{...}}Setting only
function_arguments_keyis broken in the other direction: thegrammar keeps emitting
arguments, whileParseFunctionCall(
pkg/functions/parse.go:944-949) — the one place that does readFunctionArgumentsKey— looks up the configured key, finds nothing, andreturns the call with empty arguments.
The default configuration is unaffected: with both fields empty,
ToJSONStructurefalls back toname/argumentsfor both parameters. Thatis why this went unnoticed.
Fix
Pass
FunctionArgumentsKeyas the second argument at the four call sites.FunctionArgumentsKeyis astringfield on the same struct asFunctionNameKey, so this is a one-token change per call site with nobehavior change for the default configuration.
Notes
ToJSONStructure()unit test already calls the helper with twodistinct keys (
"function","arguments"), i.e. the helper's contract wasright and only the call sites were wrong. This PR extends that test with a
case that keeps both custom keys distinct and asserts the two properties
survive; it fails against the collapsed structure.
pkg/functionscannot be compiled standalone here (pkg/grpc/protoisgenerated at build time), so the table above was produced by running the
unmodified
ToJSONStructure/function_structure.gosources in an isolatedmodule with a stubbed
xlog.gofmt -lis clean on all five files.{}on/v1/responses), but I could not confirm that: the config in that reportdoes not set either key, so this is offered as a separate, independently
reproducible defect rather than a fix for that issue.
Deliberately not in scope
The two streaming tool-call emitters
(
core/http/endpoints/openai/chat_stream_workers.go:45-50andcore/http/endpoints/openresponses/responses.go:1793-1797) hardcode"name"and
"arguments"when readingParseJSONIterativeoutput, so they also ignoreboth config keys. That is a separate defect needing a signature change and test
updates; I left it out to keep this PR reviewable and can follow up if wanted.
🤖 Generated with Claude Code