Skip to content

fix: Recursively strip examples from Google provider schemas#2644

Closed
Sushmithamallesh wants to merge 4 commits intonextfrom
fix/google-provider-strip-examples
Closed

fix: Recursively strip examples from Google provider schemas#2644
Sushmithamallesh wants to merge 4 commits intonextfrom
fix/google-provider-strip-examples

Conversation

@Sushmithamallesh
Copy link
Collaborator

Summary

  • The Gemini API rejects function declarations containing examples fields in parameter schemas
  • Python (composio_google): Only stripped examples at the top level of properties, missing nested schemas (e.g. arrays of objects with their own examples fields)
  • TypeScript (@composio/google): Didn't strip examples at all

Both providers now use a recursive helper to strip examples from the entire schema tree before creating function declarations.

Test plan

  • Verify session.tools() with GoogleProvider no longer throws protobuf errors (Python)
  • Verify session.tools() with GoogleProvider no longer causes 400 errors from Gemini API (TypeScript)
  • Test with both simple toolkit tools and complex tool-router session tools

🤖 Generated with Claude Code

@vercel
Copy link

vercel bot commented Feb 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Feb 19, 2026 0:42am

Request Review

@github-actions
Copy link
Contributor

github-actions bot commented Feb 17, 2026

⚠️ Security Audit Warning

The pnpm audit --prod check found security vulnerabilities in production dependencies.

Please review and fix the vulnerabilities. You can try running:

pnpm audit --fix --prod
Audit output
┌─────────────────────┬────────────────────────────────────────────────────────┐
│ high                │ minimatch has a ReDoS via repeated wildcards with      │
│                     │ non-matching literal in pattern                        │
├─────────────────────┼────────────────────────────────────────────────────────┤
│ Package             │ minimatch                                              │
├─────────────────────┼────────────────────────────────────────────────────────┤
│ Vulnerable versions │ <10.2.1                                                │
├─────────────────────┼────────────────────────────────────────────────────────┤
│ Patched versions    │ >=10.2.1                                               │
├─────────────────────┼────────────────────────────────────────────────────────┤
│ Paths               │ ts__examples__google>@google/genai>google-auth-        │
│                     │ library>gaxios>rimraf>glob>minimatch                   │
│                     │                                                        │
│                     │ ts__packages__cli>openapi-typescript>@redocly/openapi- │
│                     │ core>minimatch                                         │
├─────────────────────┼────────────────────────────────────────────────────────┤
│ More info           │ https://github.com/advisories/GHSA-3ppc-4f35-3m26      │
└─────────────────────┴────────────────────────────────────────────────────────┘
2 vulnerabilities found
Severity: 2 high

The Gemini API rejects function declarations containing `examples`
fields in parameter schemas. The Python provider only stripped these
at the top level of properties, missing nested schemas (e.g. arrays
of objects). The TypeScript provider didn't strip them at all.

Both providers now use a schema-aware recursive helper that strips
`examples` only when it appears as a JSON Schema annotation keyword,
not when it appears as a property name in a `properties` mapping.
The helper recurses through `properties` (values), `items`, `anyOf`,
`oneOf`, `allOf`, and `additionalProperties`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sushmithamallesh added a commit that referenced this pull request Feb 17, 2026
…ic loop

- Restructured with Steps (Install, Configure API Keys, Create session)
- Added agentic loop using Chat API for both Python and TypeScript
- Python uses execute_tool_call + Part.from_function_response
- TypeScript uses executeToolCall + functionResponse parts
- Added groupId/persist tabs for cross-step language sync
- Pending full e2e test (blocked on SDK fix PR #2644 for examples stripping)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sushmithamallesh added a commit that referenced this pull request Feb 18, 2026
…ic loop

- Restructured with Steps (Install, Configure API Keys, Create session)
- Added agentic loop using Chat API for both Python and TypeScript
- Python uses execute_tool_call + Part.from_function_response
- TypeScript uses executeToolCall + functionResponse parts
- Added groupId/persist tabs for cross-step language sync
- Pending full e2e test (blocked on SDK fix PR #2644 for examples stripping)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cleaned.additionalProperties = cleanSchema(cleaned.additionalProperties as Record<string, unknown>);
}

return cleaned;
Copy link

Choose a reason for hiding this comment

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

TypeScript cleanSchema lacks non-object input guard

Low Severity

The Python _clean_schema guards against non-dict inputs at the top (if not isinstance(schema, dict): return schema), but the TypeScript cleanSchema has no equivalent guard. When recursing into anyOf/oneOf/allOf array elements via .map(s => cleanSchema(s)), if any element is null or undefined, Object.entries() will throw a TypeError. If an element is a boolean (valid in JSON Schema as a boolean schema), it silently returns {} instead of preserving the original value, corrupting the schema semantics.

Additional Locations (1)

Fix in Cursor Fix in Web

@jkomyno jkomyno changed the base branch from next to chore/improve-timeouts-e2e-tests February 18, 2026 06:45
@claude
Copy link
Contributor

claude bot commented Feb 18, 2026

Claude finished @jkomyno's task in 2m 4s —— View job


PR Review Complete

I've reviewed this PR according to the documentation review guidelines. Here are my findings:

Context

This PR contains:

  • Core fix (commit 57cd107): Recursive examples stripping in Google providers (Python + TypeScript)
  • Merged changes: Documentation updates from next branch and e2e test improvements from chore/improve-timeouts-e2e-tests

Implementation Review (Python & TypeScript Providers)

✅ What Works Well

The core fix correctly addresses the stated problem:

  • Both providers now recursively strip examples fields that cause Gemini API rejections
  • The implementation properly distinguishes between property names and schema keywords
  • Code is well-documented with clear docstrings explaining the intent
  • The recursive logic handles properties, items, anyOf, oneOf, allOf, and additionalProperties

⚠️ Technical Issues Found

Three legitimate issues raised by Cursor's review comments:

  1. Property name collision (Low severity) - python/providers/google/composio_google/provider.py:39 and ts/packages/providers/google/src/index.ts:38

    • The recursion into properties correctly preserves parameter names
    • However, if a tool has a parameter literally named "examples", it would be stripped at line 36 (Python) / 31 (TypeScript) before the properties recursion happens
    • Impact: Minimal - it's unlikely a real tool would have a parameter named "examples", but technically possible
  2. Array-form items not handled (Medium severity) - python/providers/google/composio_google/provider.py:44 and ts/packages/providers/google/src/index.ts:44

    • JSON Schema allows items to be either an object (single schema) or an array (tuple validation)
    • Current code only handles the object case: isinstance(cleaned["items"], dict) (Python) / !Array.isArray(cleaned.items) (TypeScript)
    • Impact: If a schema uses tuple validation with items: [schema1, schema2], any examples in those schemas won't be stripped, causing the same API rejection this PR aims to fix
  3. TypeScript missing input guard (Low severity) - ts/packages/providers/google/src/index.ts:28

    • Python version has if not isinstance(schema, dict): return schema (line 33)
    • TypeScript version lacks this guard
    • Impact: If anyOf/oneOf/allOf contain null, undefined, or boolean schemas, Object.entries() will throw or behave incorrectly

Suggested Fixes

For issue #2 (array-form items):

Python:

# Line 44, change from:
if "items" in cleaned and isinstance(cleaned["items"], dict):
    cleaned["items"] = _clean_schema(cleaned["items"])

# To:
if "items" in cleaned:
    if isinstance(cleaned["items"], dict):
        cleaned["items"] = _clean_schema(cleaned["items"])
    elif isinstance(cleaned["items"], list):
        cleaned["items"] = [_clean_schema(s) for s in cleaned["items"]]

TypeScript:

// Line 44, change from:
if (cleaned.items && typeof cleaned.items === 'object' && !Array.isArray(cleaned.items)) {
  cleaned.items = cleanSchema(cleaned.items as Record<string, unknown>);
}

// To:
if (cleaned.items && typeof cleaned.items === 'object') {
  if (Array.isArray(cleaned.items)) {
    cleaned.items = cleaned.items.map(s => cleanSchema(s as Record<string, unknown>));
  } else {
    cleaned.items = cleanSchema(cleaned.items as Record<string, unknown>);
  }
}

For issue #3 (TypeScript input guard):

Add at the start of cleanSchema function (line 28):

function cleanSchema(schema: Record<string, unknown>): Record<string, unknown> {
  if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
    return schema;
  }
  // ... rest of function

Documentation Review

The merged documentation changes (30+ FAQ files) are unrelated to this PR's core fix. I sampled several files - they appear to be legitimate documentation improvements (FAQ rewrites, internal link fixes) that were merged from the next branch.

No issues found - these are not code changes and don't contain code examples that could mislead developers.


Recommendation

Approve with suggested improvements:

The PR can be merged as-is if the team determines that tuple validation schemas are not currently used. However, implementing the fix for issue #2 would make the solution more robust and complete.

Base automatically changed from chore/improve-timeouts-e2e-tests to next February 18, 2026 07:21
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

| 6 | `ts/e2e-tests/README.md` | Update 3 code examples with `TIMEOUTS.FIXTURE` |
| 7 | `ts/e2e-tests/_utils/README.md` | Update TIMEOUTS table + code examples |
| 8 | `ts/e2e-tests/_utils/src/e2e.ts` | Update JSDoc example |
| 9 | `ts/e2e-tests/_utils/src/types.ts` | Update JSDoc example |
Copy link

Choose a reason for hiding this comment

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

Unrelated plan file accidentally committed with PR

Low Severity

The file plans/refactor-e2e-fixture-timeouts.md is entirely unrelated to this PR, which is about recursively stripping examples from Google provider schemas. This plan document is about bumping e2e fixture beforeAll timeouts and LLM_SHORT, a completely separate task. It also contains internal inconsistencies — the FIXTURE value is listed as 15_000 in the text descriptions (lines 24, 105, 151) but 60_000 in the code block (line 29).

Fix in Cursor Fix in Web

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.

2 participants