Keep workflow tool schemas free of recursive $refs - #1613
Open
mattwyckhouse wants to merge 1 commit into
Open
Conversation
zod 4's `z.json()` compiles to a self-referential `$defs` entry, and some providers reject an entire tool list that contains a recursive `$ref`. Every Grok 4.6 turn failed immediately with a generic provider connection error because `bb_workflow_run` and `bb_workflow_result` shipped that schema. Declare the freeform JSON inputs as `unknown` so the wire schema stays flat and narrow them to `JsonValue` at each call site, which keeps the existing JSON-compatibility validation. A harness test now fails if any workflow tool schema regains a `$ref` or `$defs`. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fixes #1612.
Summary
bb_workflow_run.argsandbb_workflow_result.valueused zod 4'sz.json(), which compiles to a self-referential$defsentry. Grok 4.6 rejects any tool list containing a recursive$ref, so every turn oncursor-grok-4.6-*died immediately with a genericNonRetriableError: Provider Errorbefore the model ran. Grok 4.5 tolerates it, which is why it surfaced only on 4.6.unknown, so the wire schema stays flat, and are narrowed toJsonValueat each call site.assertJsonValuemoves out ofruntime.tsinto a smalljson-value.tsso the tool boundary and the sandbox boundary share one validator — the deep JSON-compatibility checkingz.json()did at parse time still happens, just at the call site.bb_workflow_resultreturns the validation failure as a tool error instead of throwing, matching howbb_workflow_runalready reports bad input.Test plan
pnpm exec turbo run test typecheck --filter=bb-plugin-workflows— 220 passed, typecheck cleanregisters tool schemas without recursive $refsasserts no registered workflow tool schema contains$refor$defs, and fails as expected whenz.json()is put backbb_workflow_runwith a nested object asargs({"nested":{"token":"TOOL-OK","list":[1,2,{"deep":null}]}}): workflow ran and returned{"token":"TOOL-OK","reply":"TOOL-OK"}, confirming args still reach the script verbatimbb workflows run --script ... --args ...with the same nested payload: succeededNote: the flat schema no longer advertises "any JSON value" to the model, only the description does. In practice the models tested passed real JSON objects unchanged.
Made with Cursor