Skip to content

fix: OpenCode array item schemas#180

Merged
ian-pascoe merged 3 commits into
mainfrom
codex/fix-opencode-array-item-schemas
Jun 30, 2026
Merged

fix: OpenCode array item schemas#180
ian-pascoe merged 3 commits into
mainfrom
codex/fix-opencode-array-item-schemas

Conversation

@ian-pascoe

@ian-pascoe ian-pascoe commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes @caplets/opencode: array items schema discarded, Gemini rejects tool declarations #178 by preserving JSON Schema items definitions when @caplets/opencode registers direct native tool schemas.
  • Falls back to string array items when a downstream array schema has no usable items object, avoiding empty Gemini array item declarations.
  • Adds a regression assertion for array<string> direct native input schemas and a patch changeset for @caplets/opencode.

Validation

  • pnpm --filter @caplets/opencode test -- test/opencode.test.ts
  • pnpm --filter @caplets/opencode typecheck
  • pnpm --filter @caplets/opencode build
  • pnpm format:check
  • pnpm changeset status --since=origin/main
  • pnpm verify
  • pre-push pnpm verify

Fixes #178

Summary by CodeRabbit

  • Bug Fixes
    • Preserved array item types when generating argument schemas from native tools.
    • Improved schema handling so boolean and array arguments keep the correct required/optional behavior.
    • Better support for arrays with nested item definitions in generated tool inputs.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ian-pascoe, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 34 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b5c3721c-ff6a-44f9-9ee9-b0b7eb62f46a

📥 Commits

Reviewing files that changed from the base of the PR and between a5d1f3a and 413c346.

📒 Files selected for processing (2)
  • packages/opencode/src/schema.ts
  • packages/opencode/test/opencode.test.ts
📝 Walkthrough

Walkthrough

Fixes jsonSchemaPropertyToOpenCode in packages/opencode/src/schema.ts to accept an options.optional flag and recurse into schema.items for array-typed JSON Schema properties instead of always using array(unknown). Tests and mocks are updated to cover optional boolean and typed array schemas.

Changes

Array items schema preservation

Layer / File(s) Summary
Schema conversion refactor
packages/opencode/src/schema.ts
Adds OpenCodeSchema type alias; refactors jsonSchemaPropertyToOpenCode to accept { optional } and conditionally apply .optional(); array handling now recurses into schema.items with { optional: false } and falls back to string().
Updated mocks and test expectations
packages/opencode/test/opencode.test.ts
Mocked boolean() and array() builders updated to support optional state; status__ping input schema expanded with a tags array-of-string property; expected directTool.args updated to assert both verbose and tags as optional.
Changeset
.changeset/sharp-array-schemas.md
Patch release entry for @caplets/opencode recording the fix.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hoppity-hop, through schemas I leap,
Array items were lost in a slumber so deep.
Now items.type is found and preserved,
Gemini gets exactly what it deserved!
No more missing fields, no more rejected calls —
The rabbit fixed schemas, and order befalls. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: preserving OpenCode array item schemas.
Linked Issues check ✅ Passed The array conversion now preserves schema.items and falls back to string items when missing, matching issue #178.
Out of Scope Changes check ✅ Passed The changeset and test updates support the same array-schema fix and don't introduce unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-opencode-array-item-schemas

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ian-pascoe ian-pascoe changed the title [codex] fix OpenCode array item schemas fix: OpenCode array item schemas Jun 29, 2026
@ian-pascoe ian-pascoe marked this pull request as ready for review June 29, 2026 21:24
@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes @caplets/opencode to correctly preserve JSON Schema items definitions when building OpenCode tool argument schemas from direct native tool schemas, and falls back to string items for unsupported item shapes (e.g. anyOf), preventing empty Gemini array item declarations.

  • Array item preservation: jsonSchemaPropertyToOpenCode now resolves schema.items through isSupportedOpenCodeJsonSchema + recursive conversion instead of always emitting tool.schema.unknown() as the item type.
  • Consistent optional handling: An explicit options.optional flag replaces unconditional .optional() calls, making all branches (enum, string, number, boolean, object, array) respect the same optionality contract when called recursively for nested items.
  • Regression test: The direct-native-tool test is expanded to cover enum, boolean, array<string>, array<enum>, and anyOf-fallback cases, and the tool mock is updated to capture item schemas so assertions are meaningful.

Confidence Score: 5/5

The change is narrowly scoped to the JSON-Schema-to-OpenCode conversion path and adds no new external dependencies or side effects.

The fix is correct: resolving array item schemas recursively through the same converter ensures fidelity with the upstream JSON Schema, and the isSupportedOpenCodeJsonSchema guard safely rejects unsupported item shapes before recursion. The options.optional refactor is mechanically sound — every branch now honours the flag consistently. Tests cover the five meaningful item-schema shapes, and the mock is updated to make those assertions observable.

No files require special attention.

Important Files Changed

Filename Overview
packages/opencode/src/schema.ts Refactored jsonSchemaPropertyToOpenCode to accept an explicit optional flag, fixed array item schema preservation by resolving schema.items through the same converter, and added isSupportedOpenCodeJsonSchema guard with a string fallback for unrecognized item types.
packages/opencode/test/opencode.test.ts Expanded the direct native input schema test to cover enum, boolean, string-array, enum-array, and anyOf-fallback array cases; updated the mock to capture item schemas on array() and expose optional() on enum/boolean.
.changeset/sharp-array-schemas.md New patch changeset entry for @caplets/opencode documenting the array item type preservation fix.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[capletsOpenCodeJsonSchemaArgs\nschema properties] -->|optional: true| B[jsonSchemaPropertyToOpenCode\nvalue, options]

    B --> C{value is\nvalid object?}
    C -->|No| Z[tool.schema.unknown]
    C -->|Yes| D{schema.enum\nall strings?}

    D -->|Yes| E[tool.schema.enum\n± .optional]
    D -->|No| F{schema.type?}

    F -->|string| G[tool.schema.string\n± .optional]
    F -->|number/integer| H[tool.schema.number.int.positive\n± .optional]
    F -->|boolean| I[tool.schema.boolean\n± .optional]
    F -->|object| J[tool.schema.record\n± .optional]
    F -->|array| K[isSupportedOpenCodeJsonSchema\nschema.items]
    F -->|other| Z

    K -->|true| L[jsonSchemaPropertyToOpenCode\nschema.items, optional: false]
    K -->|false| M[tool.schema.string\nfallback]

    L --> N[tool.schema.array\nresolvedItemSchema .min 1 ± .optional]
    M --> N
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[capletsOpenCodeJsonSchemaArgs\nschema properties] -->|optional: true| B[jsonSchemaPropertyToOpenCode\nvalue, options]

    B --> C{value is\nvalid object?}
    C -->|No| Z[tool.schema.unknown]
    C -->|Yes| D{schema.enum\nall strings?}

    D -->|Yes| E[tool.schema.enum\n± .optional]
    D -->|No| F{schema.type?}

    F -->|string| G[tool.schema.string\n± .optional]
    F -->|number/integer| H[tool.schema.number.int.positive\n± .optional]
    F -->|boolean| I[tool.schema.boolean\n± .optional]
    F -->|object| J[tool.schema.record\n± .optional]
    F -->|array| K[isSupportedOpenCodeJsonSchema\nschema.items]
    F -->|other| Z

    K -->|true| L[jsonSchemaPropertyToOpenCode\nschema.items, optional: false]
    K -->|false| M[tool.schema.string\nfallback]

    L --> N[tool.schema.array\nresolvedItemSchema .min 1 ± .optional]
    M --> N
Loading

Reviews (3): Last reviewed commit: "fix opencode enum schema optionality" | Re-trigger Greptile

Comment thread packages/opencode/src/schema.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/src/schema.ts`:
- Around line 94-100: The array-item fallback in jsonSchemaPropertyToOpenCode
still allows unsupported non-empty items schemas to recurse into
tool.schema.unknown(), which should be treated as unusable. Update the
itemSchema logic so that after calling
jsonSchemaPropertyToOpenCode(schema.items, { optional: false }), you detect an
unknown() result and fall back to tool.schema.string() instead. Keep the
existing handling in schema.ts for missing, empty, or non-object items, and
apply the same fallback behavior for any unsupported items schema that resolves
to unknown.
- Around line 70-72: The enum handling in schema conversion is missing optional
wrapping, so enum properties are still treated as required. Update the enum
branch in schema.ts where tool.schema.enum(...) is returned so it follows the
same optionality behavior as the other top-level property branches, and make
sure the change is applied in the schema conversion path that handles enum
arrays. Add a regression test covering enum inputs to verify the resulting
schema remains optional.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: df6b175e-c3e0-4233-9f5c-e2a3aefd4154

📥 Commits

Reviewing files that changed from the base of the PR and between 071775c and a5d1f3a.

📒 Files selected for processing (3)
  • .changeset/sharp-array-schemas.md
  • packages/opencode/src/schema.ts
  • packages/opencode/test/opencode.test.ts

Comment thread packages/opencode/src/schema.ts
Comment thread packages/opencode/src/schema.ts Outdated
@ian-pascoe ian-pascoe merged commit 2e2e258 into main Jun 30, 2026
6 checks passed
@ian-pascoe ian-pascoe deleted the codex/fix-opencode-array-item-schemas branch June 30, 2026 01:17
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.

@caplets/opencode: array items schema discarded, Gemini rejects tool declarations

1 participant