Skip to content

fix(examples): support recursive structured output schemas - #844

Open
charle-z wants to merge 5 commits into
openai:mainfrom
charle-z:fix/492-recursive-structured-output
Open

fix(examples): support recursive structured output schemas#844
charle-z wants to merge 5 commits into
openai:mainfrom
charle-z:fix/492-recursive-structured-output

Conversation

@charle-z

@charle-z charle-z commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Make the Structured Outputs schema helper support recursive Go types without changing the example's object-shaped root schema.

Fixes #492.

Problem

The example configures invopop/jsonschema with DoNotReference: true. That forces referenced types to be inlined. A self-referential type therefore has no cycle breaker and schema reflection recurses until the Go runtime exhausts the goroutine stack.

Simply re-enabling references avoids the recursion, but jsonschema normally represents the root as a $ref into $defs, while the Structured Outputs example needs an object-shaped root.

Fix

Keep references enabled and expand only the reflector's local root $ref:

  • AllowAdditionalProperties: false remains unchanged;
  • the referenced root definition is copied into the root schema;
  • $defs is retained, so nested and recursive definitions can continue to use $ref;
  • schema metadata ($schema, $id, $anchor) is preserved;
  • the existing json.RawMessage conversion remains in place so large integer constraints keep their exact JSON representation.

This deliberately does not use ExpandedStruct: true: revalidation against invopop/jsonschema v0.14.0 showed that for the recursive fixture it expands the root while omitting $defs, leaving the emitted nested $ref dangling.

The duplicated Structured Outputs snippet in README.md uses the same logic.

Regression coverage

The recursive fixture verifies that:

  • the root remains type: "object";
  • $defs is present;
  • the recursive children item is a self-reference into $defs.

The existing object-shape and exact 64-bit integer enum tests remain intact.

Validation

Current head: 32823ea5723614ad1053f3caaa4cc1bc6686dfe3.

Local / isolated validation:

  • focused recursive regression test: pass;
  • complete examples test module: pass;
  • root and examples go vet ./...: pass;
  • root and examples builds: pass;
  • external consumer test: pass;
  • git diff --check: pass;
  • synthetic merge with current upstream/main at 37c0f0ab07fbe5f5b2775c12ca3500acd0caad8c: clean; examples tests and root build pass on the merged tree.

Fork CI on the exact head is green for the executable gates:

  • lint + check-go-mod: pass;
  • Go 1.25.x: root module, examples module, and external consumer tests pass;
  • Go 1.26.x: root module, examples module, and external consumer tests pass.

The upstream workflows for this external-contributor head remain action_required; that is an approval gate, not a technical test failure.

@charle-z
charle-z marked this pull request as ready for review August 23, 2026 00:19
@charle-z
charle-z requested a review from a team as a code owner August 23, 2026 00:19

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 66ffbc5d63

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: 66ffbc5d63

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@charle-z

Copy link
Copy Markdown
Contributor Author

@codex review

Please re-review the current head 32823ea5723614ad1053f3caaa4cc1bc6686dfe3; the recursive-schema implementation changed materially after adversarial validation.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 32823ea572

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: 32823ea572

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked the current head. Keeping refs enabled fixes the recursion problem, and expanding only the root while carrying $defs forward preserves the self-reference instead of flattening the schema. The metadata copy also avoids dropping schema/id/anchor. Looks good from this side.

Copy link
Copy Markdown
Contributor Author

@jbeckwith-oai when you have a chance, could you take a maintainer look at this one? The current head (32823ea5723614ad1053f3caaa4cc1bc6686dfe3) is mergeable, the fork CI is green on the executable gates, and the latest human review found the recursive $ref / $defs approach sound. The upstream Actions are still gated on external-contributor approval rather than a test failure. Thanks!

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.

Stack Overflow When Parsing Recursive Structs with Structured Outputs

2 participants