Skip to content

Keep workflow tool schemas free of recursive $refs - #1613

Open
mattwyckhouse wants to merge 1 commit into
get-bb:mainfrom
mattwyckhouse:fix/workflows-nonrecursive-tool-schema
Open

Keep workflow tool schemas free of recursive $refs#1613
mattwyckhouse wants to merge 1 commit into
get-bb:mainfrom
mattwyckhouse:fix/workflows-nonrecursive-tool-schema

Conversation

@mattwyckhouse

Copy link
Copy Markdown

Fixes #1612.

Summary

  • bb_workflow_run.args and bb_workflow_result.value used zod 4's z.json(), which compiles to a self-referential $defs entry. Grok 4.6 rejects any tool list containing a recursive $ref, so every turn on cursor-grok-4.6-* died immediately with a generic NonRetriableError: Provider Error before the model ran. Grok 4.5 tolerates it, which is why it surfaced only on 4.6.
  • Both inputs are now declared as unknown, so the wire schema stays flat, and are narrowed to JsonValue at each call site. assertJsonValue moves out of runtime.ts into a small json-value.ts so the tool boundary and the sandbox boundary share one validator — the deep JSON-compatibility checking z.json() did at parse time still happens, just at the call site.
  • bb_workflow_result returns the validation failure as a tool error instead of throwing, matching how bb_workflow_run already reports bad input.

Test plan

  • pnpm exec turbo run test typecheck --filter=bb-plugin-workflows — 220 passed, typecheck clean
  • New harness test registers tool schemas without recursive $refs asserts no registered workflow tool schema contains $ref or $defs, and fails as expected when z.json() is put back
  • Grok 4.6 thread in a live bb with this build loaded: normal turn completes (previously an instant provider error)
  • Grok 4.6 calling bb_workflow_run with a nested object as args ({"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 verbatim
  • bb workflows run --script ... --args ... with the same nested payload: succeeded

Note: 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.

AGENT GENERATED: by Claude Opus 5

Made with Cursor

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

Recursive tool schemas (z.json()) break Grok 4.6: every turn fails with a generic provider error

1 participant