Skip to content

fix: simplify donut chart schema for OpenAI compatibility#8182

Open
xr843 wants to merge 2 commits intoblock:mainfrom
xr843:fix/autovisualiser-donut-schema
Open

fix: simplify donut chart schema for OpenAI compatibility#8182
xr843 wants to merge 2 commits intoblock:mainfrom
xr843:fix/autovisualiser-donut-schema

Conversation

@xr843
Copy link
Copy Markdown

@xr843 xr843 commented Mar 29, 2026

Summary

Fixes #8173

The autovisualiser__render_donut tool schema was rejected by OpenAI-compatible endpoints because it used #[serde(untagged)] enums, which generate anyOf/oneOf constructs in JSON Schema that OpenAI's function calling validation does not support.

This PR replaces the two problematic untagged enums with simpler, flat types:

  • DonutDataItem: Changed from an untagged enum (Number(f64) | LabeledValue { label, value }) to a plain struct with required label and value fields. This produces a single object schema instead of anyOf.
  • DonutChartData: Removed the untagged enum (Single(SingleDonutChart) | Multiple(Vec<SingleDonutChart>)). RenderDonutParams.data now takes Vec<SingleDonutChart> directly — a single chart is represented as a one-element array.
  • Removed the labels field from SingleDonutChart since labels are now always embedded in each DonutDataItem.
  • Updated tool description examples to reflect the new schema.
  • Updated tests accordingly.

The HTML template (donut_template.html) already handles both object-style values and arrays, so no template changes are needed.

Test plan

  • Existing test_render_donut and donut_rejects_empty_values tests pass
  • Verify the generated JSON Schema no longer contains anyOf/oneOf for the donut tool
  • Test with OpenAI-compatible endpoint: goose run --provider openai --model gpt-4o-mini --with-builtin autovisualiser --text "Reply with exactly OK" should not return schema validation error

🤖 Generated with Claude Code

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb46c429d4

ℹ️ 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".

Comment on lines +992 to +995
let count = data
.get("data")
.and_then(|d| d.as_array())
.map(|a| a.len())
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Count donut charts from returned data array

validate_data_param returns the value of params["data"] (for this tool, an array), but this code looks for a nested "data" field again, so count is always 1. As a result, calls with multiple charts still return the fallback text "donut/pie chart: 1 chart(s)", which is incorrect for clients that rely on result.content rather than the structured payload.

Useful? React with 👍 / 👎.

Replace untagged enums in DonutDataItem and DonutChartData with plain
structs and Vec to produce a JSON Schema that OpenAI-compatible
endpoints accept for function calling.

- DonutDataItem: changed from untagged enum (Number|LabeledValue) to a
  struct with required label+value fields
- DonutChartData: removed untagged enum (Single|Multiple), RenderDonutParams
  now takes Vec<SingleDonutChart> directly
- Removed the now-unnecessary labels field from SingleDonutChart since
  labels are always part of each DonutDataItem
- Updated tool description examples to reflect the new schema
- Updated and fixed tests to match the simplified schema

Fixes block#8173

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Tim Ren <[email protected]>
@DOsinga
Copy link
Copy Markdown
Collaborator

DOsinga commented Mar 30, 2026

Thanks for the PR — the core idea of simplifying the donut schema to avoid anyOf/oneOf is sound and would fix the OpenAI compatibility issue.

A few things to address before we can move forward:

  1. Bug in the text fallback (Codex caught this): validate_data_param already extracts params["data"], so data is the array of charts. The new code does data.get("data") which looks for a nested "data" key that does not exist, so count always falls back to 1. You need data.as_array().map(|a| a.len()).unwrap_or(1) instead. Please address the Codex review comment — see CONTRIBUTING.md § AI Code Reviews.

  2. Duplicate test: labeled_values_as_single_chart is identical in structure to labeled_values_single_chart — please remove the duplicate.

  3. Multiple open PRs: You have three PRs open at once (fix: propagate token usage from ACP provider responses #8181, fix: simplify donut chart schema for OpenAI compatibility #8182, fix: handle unknown tool calls gracefully instead of failing #8183) with no previously merged contributions. Per CONTRIBUTING.md § Pull Requests, please focus on landing one PR at a time. We think this one (fix: simplify donut chart schema for OpenAI compatibility #8182) is the most promising — please close the others or wait until this one lands before continuing with them.

@DOsinga DOsinga added the needs_human label to set when a robot looks at a PR and can't handle it label Mar 30, 2026
- Fix donut text_fallback: `data` is already the array extracted by
  `validate_data_param`, so use `data.as_array()` directly instead of
  `data.get("data")` which always fell back to 1.
- Remove `labeled_values_as_single_chart` test that duplicates
  `labeled_values_single_chart`.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@xr843
Copy link
Copy Markdown
Author

xr843 commented Mar 30, 2026

Thanks for the detailed review @DOsinga! All three items addressed:

  1. Fixed text_fallback count bugdata is already the extracted array from validate_data_param, so changed to data.as_array().map(|a| a.len()).unwrap_or(1) instead of the incorrect data.get("data") which always fell back to 1.

  2. Removed duplicate testlabeled_values_as_single_chart was structurally identical to labeled_values_single_chart, now removed.

  3. Closed other PRs — closed fix: propagate token usage from ACP provider responses #8181 to focus on this one as suggested. fix: handle unknown tool calls gracefully instead of failing #8183 was already closed by you.

Apologies for the multi-PR approach — lesson learned, will follow the one-PR-at-a-time guideline going forward!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs_human label to set when a robot looks at a PR and can't handle it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

autovisualiser__render_donut schema rejected by OpenAI-compatible tool calling

2 participants