[PR #7114] [CLOSED] fix(mcp): preserve non-array element types in reduced compact array items #7651

Closed
opened 2026-11-03 13:39:23 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/7114
Author: @carcraze
Created: 10/25/2026
Status: ❌ Closed

Base: main ← Head: fix/compact-reduced-array-items


📝 Commits (2)

  • b15a924 fix(mcp): preserve non-array element types in reduced compact array items
  • 24f0c98 fix(mcp): fall back for prefixItems and open union branches in reduced arrays

📊 Changes

3 files changed (+148 additions, -19 deletions)

View changed files

📝 src/contracts/compactInputSchema.test.ts (+53 -7)
📝 src/contracts/compactInputSchema.ts (+86 -11)
📝 tests/boundary/mcp/compactInputSchemaMcp.test.ts (+9 -1)

📄 Description

Summary

Fixes #7103.

In rea-agents@6.8.0, compact became the default REA_MCP_INPUT_SCHEMA_PROFILE. When a tool input schema falls back to reduceToShallowProperties, every array-typed root property received items: jsonValueSchema() ({ type: ["null", "boolean", "object", "array", "number", "string"], items: {} }). When MCP-to-Gemini converters expand the multi-type array into any_of branches, the outer items node retains a sibling items: {} without $type == Type.ARRAY while the inner { type: "ARRAY" } branch has no items field, causing Google to reject the entire tool catalog with HTTP 400 across 44 reduced array properties in 25 tools.

reduceToShallowProperties now preserves detected non-array element types (string, integer, object, or unions of non-array types) via reducedArrayItems, falling back to jsonValueSchema() only when the item schema itself is unconstrained or admits nested arrays. inlineWithinBudget also keeps negated empty schemas (not: {}) intact instead of expanding them into jsonValueSchema().

Problem and expected behavior

Trigger: connect rea-agents@6.8.0 (default compact profile) to a Gemini-backed MCP client (opencode 1.19.2). Every turn fails with 44 pairs of parameters.properties[...].items.items: field predicate failed: $type == Type.ARRAY and parameters.properties[...].items.any_of[2].items: missing field.

Expected: reduced array properties in the compact profile preserve their element types when known and non-array, so the default 6.8.0 catalog loads cleanly in Gemini-backed clients.

Change and scope

  • src/contracts/compactInputSchema.ts: add reducedArrayItems (resolving items, $ref, and anyOf/oneOf array branches via detectedTypes) so reduced array properties emit their element type(s) unless unconstrained or nested-array; keep not: {} as {} during inline serialization.
  • src/contracts/compactInputSchema.test.ts: verify reduced $ref array properties preserve items: { type: "object" } while unconstrained array items still receive the full JSON-value fallback.
  • tests/boundary/mcp/compactInputSchemaMcp.test.ts: assert that no advertised compact tool schema carries a multi-type array containing "array" alongside a sibling items.

Follow the contribution scope. Not applicable (ordinary MCP schema projection fix within existing boundaries).

Contract and boundary impact

  • Semantic owner and earliest changed stage: src/contracts/compactInputSchema.ts (reduceToShallowProperties and inlineWithinBudget).
  • Contribution scope fit and linked maintainer decision: not applicable.
  • CLI and MCP/tool-catalog contract: advertised compact input schemas only; canonical runtime validation is unchanged.
  • Provider, bridge, target-format, or platform compatibility: restores default compact-profile compatibility with Gemini-backed MCP clients.
  • Evidence, artifact, provenance, or reconstruction contract: none.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Expected effects:

  • Documentation or usability only; no target interaction.

Evidence and regression coverage

  • Tests added or updated: src/contracts/compactInputSchema.test.ts and tests/boundary/mcp/compactInputSchemaMcp.test.ts.
  • Base reproduction or other evidence: stdio tools/list scan of rea-agents@6.8.0 in default compact mode shows 46 occurrences of { type: ["null", "boolean", "object", "array", "number", "string"], items: {} }; with this patch, all 229 tools report 0 occurrences in both compact and full profiles.
  • User-visible CLI/MCP output (if applicable): patched 6.8.0 profile=compact: tools=229 multiTypeWithItems=0 emptyConstOrEnum=0.
  • Remaining proof gaps: none.

Validation performed

  • npx vitest run src/contracts/compactInputSchema.test.ts src/contracts/toolInputReferences.test.ts — 69 passed
  • npx vitest run tests/boundary/mcp/compactInputSchemaMcp.test.ts — 13 passed
  • npm run check:fast (tsc --noEmit, oxlint, verify:module-boundaries), npm run format:check, npm run jscpd — all passed with 0 errors

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: none.

Author readiness

Human owner: @carcraze

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/7114 **Author:** [@carcraze](https://github.com/carcraze) **Created:** 10/25/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/compact-reduced-array-items` --- ### 📝 Commits (2) - [`b15a924`](https://github.com/morluto/rea/commit/b15a924c3155bd78c048169cfe6740dc40522e5c) fix(mcp): preserve non-array element types in reduced compact array items - [`24f0c98`](https://github.com/morluto/rea/commit/24f0c98a50b2520a8dc939f11ec4d771ceb1e0e7) fix(mcp): fall back for prefixItems and open union branches in reduced arrays ### 📊 Changes **3 files changed** (+148 additions, -19 deletions) <details> <summary>View changed files</summary> 📝 `src/contracts/compactInputSchema.test.ts` (+53 -7) 📝 `src/contracts/compactInputSchema.ts` (+86 -11) 📝 `tests/boundary/mcp/compactInputSchemaMcp.test.ts` (+9 -1) </details> ### 📄 Description ## Summary Fixes #7103. In `rea-agents@6.8.0`, `compact` became the default `REA_MCP_INPUT_SCHEMA_PROFILE`. When a tool input schema falls back to `reduceToShallowProperties`, every array-typed root property received `items: jsonValueSchema()` (`{ type: ["null", "boolean", "object", "array", "number", "string"], items: {} }`). When MCP-to-Gemini converters expand the multi-type array into `any_of` branches, the outer `items` node retains a sibling `items: {}` without `$type == Type.ARRAY` while the inner `{ type: "ARRAY" }` branch has no `items` field, causing Google to reject the entire tool catalog with HTTP 400 across 44 reduced array properties in 25 tools. `reduceToShallowProperties` now preserves detected non-array element types (`string`, `integer`, `object`, or unions of non-array types) via `reducedArrayItems`, falling back to `jsonValueSchema()` only when the item schema itself is unconstrained or admits nested arrays. `inlineWithinBudget` also keeps negated empty schemas (`not: {}`) intact instead of expanding them into `jsonValueSchema()`. ## Problem and expected behavior Trigger: connect `rea-agents@6.8.0` (default `compact` profile) to a Gemini-backed MCP client (`opencode 1.19.2`). Every turn fails with 44 pairs of `parameters.properties[...].items.items: field predicate failed: $type == Type.ARRAY` and `parameters.properties[...].items.any_of[2].items: missing field`. Expected: reduced array properties in the `compact` profile preserve their element types when known and non-array, so the default `6.8.0` catalog loads cleanly in Gemini-backed clients. ## Change and scope - `src/contracts/compactInputSchema.ts`: add `reducedArrayItems` (resolving `items`, `$ref`, and `anyOf`/`oneOf` array branches via `detectedTypes`) so reduced array properties emit their element type(s) unless unconstrained or nested-array; keep `not: {}` as `{}` during inline serialization. - `src/contracts/compactInputSchema.test.ts`: verify reduced `$ref` array properties preserve `items: { type: "object" }` while unconstrained array items still receive the full JSON-value fallback. - `tests/boundary/mcp/compactInputSchemaMcp.test.ts`: assert that no advertised compact tool schema carries a multi-type array containing `"array"` alongside a sibling `items`. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). Not applicable (ordinary MCP schema projection fix within existing boundaries). ## Contract and boundary impact - Semantic owner and earliest changed stage: `src/contracts/compactInputSchema.ts` (`reduceToShallowProperties` and `inlineWithinBudget`). - Contribution scope fit and linked maintainer decision: not applicable. - CLI and MCP/tool-catalog contract: advertised compact input schemas only; canonical runtime validation is unchanged. - Provider, bridge, target-format, or platform compatibility: restores default compact-profile compatibility with Gemini-backed MCP clients. - Evidence, artifact, provenance, or reconstruction contract: none. - Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. Expected effects: - [x] Documentation or usability only; no target interaction. ## Evidence and regression coverage - Tests added or updated: `src/contracts/compactInputSchema.test.ts` and `tests/boundary/mcp/compactInputSchemaMcp.test.ts`. - Base reproduction or other evidence: stdio `tools/list` scan of `rea-agents@6.8.0` in default `compact` mode shows 46 occurrences of `{ type: ["null", "boolean", "object", "array", "number", "string"], items: {} }`; with this patch, all 229 tools report `0` occurrences in both `compact` and `full` profiles. - User-visible CLI/MCP output (if applicable): `patched 6.8.0 profile=compact: tools=229 multiTypeWithItems=0 emptyConstOrEnum=0`. - Remaining proof gaps: none. ## Validation performed - `npx vitest run src/contracts/compactInputSchema.test.ts src/contracts/toolInputReferences.test.ts` — 69 passed - `npx vitest run tests/boundary/mcp/compactInputSchemaMcp.test.ts` — 13 passed - `npm run check:fast` (`tsc --noEmit`, `oxlint`, `verify:module-boundaries`), `npm run format:check`, `npm run jscpd` — all passed with 0 errors ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: not applicable. - Package or release metadata impact: none. - Security, privacy, process, or containment review: none. ## Author readiness Human owner: @carcraze - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-03 13:39:23 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7651
No description provided.