UNPKG

ai-sdk-provider-gemini-cli

Version:

Community AI SDK provider for Google Gemini using the official CLI/SDK

255 lines (203 loc) 7.46 kB
# Known Limitations This document details known limitations when using the AI SDK Provider for Gemini CLI, particularly around structured output and schema complexity. ## Structured Output (generateObject) Limitations The provider supports native structured output via Gemini's `responseJsonSchema` parameter. However, Gemini's API has internal limits on schema complexity that can cause requests to fail. ### Schema Complexity Limits Gemini uses an internal "state machine" to enforce JSON schema constraints. When a schema is too complex, the API will reject it with an error: ``` The specified schema produces a constraint that has too many states for serving. ``` **This is not a provider bug** - it's a Gemini API limitation. The schema is rejected before generation begins. #### What Makes a Schema "Too Complex" Schemas that combine multiple of these features may exceed Gemini's limits: | Feature | Risk Level | Example | |---------|------------|---------| | Deeply nested objects (3+ levels) | Medium | `product.variants[].inventory.warehouse` | | Arrays of objects with nested arrays | High | `variants[].images[]` inside `product` | | Many numeric constraints (min/max) | Medium | Multiple fields with `.min()`, `.max()`, `.positive()` | | Record types with nested values | High | `z.record(z.string(), z.object({...}))` | | Large array length limits | High | `.min(1).max(100)` on nested arrays | | Multiple enum fields | Low | Several `z.enum([...])` fields | #### Examples That May Fail ```typescript // TOO COMPLEX - likely to fail const complexSchema = z.object({ product: z.object({ variants: z.array(z.object({ inventory: z.object({ warehouse: z.record(z.string(), z.number()), }), images: z.array(z.object({ url: z.string().url(), isPrimary: z.boolean(), })).min(1).max(10), pricing: z.object({ price: z.number().positive().min(0.99).max(99999), margin: z.number().min(0).max(100), }), })).min(1).max(10), reviews: z.object({ distribution: z.object({ 5: z.number().int(), 4: z.number().int(), // ... more fields }), }), }), }); ``` ```typescript // SIMPLER - more likely to succeed const simplerSchema = z.object({ product: z.object({ name: z.string(), price: z.number().positive(), category: z.enum(['electronics', 'clothing', 'home']), features: z.array(z.string()).max(5), inStock: z.boolean(), }), }); ``` ### Problematic Constraints Some Zod constraints don't work reliably with Gemini's structured output: | Constraint | Issue | Workaround | |------------|-------|------------| | `.multipleOf(0.01)` | Floating-point multiples cause validation failures | Remove or use `.refine()` post-validation | | `.multipleOf(0.5)` | Same issue with decimal multiples | Use integer cents/units instead | | `.regex()` with complex patterns | May not be enforced | Validate after generation | | `.url().startsWith('https://')` | Combined constraints may fail | Use simpler `.url()` only | #### Example: multipleOf Issue ```typescript // PROBLEMATIC - multipleOf with decimals const schema = z.object({ price: z.number().multipleOf(0.01), // May cause validation failures rating: z.number().multipleOf(0.5), // Same issue }); // WORKAROUND - validate after generation const schema = z.object({ price: z.number().positive(), rating: z.number().min(0).max(5), }); const { object } = await generateObject({ model, schema, prompt }); // Post-validate const validatedPrice = Math.round(object.price * 100) / 100; ``` ## Workarounds ### 1. Simplify Your Schema Break complex schemas into smaller, focused schemas: ```typescript // Instead of one massive schema, use multiple calls const productBasics = await generateObject({ schema: z.object({ name: z.string(), price: z.number(), category: z.string(), }), prompt: 'Generate basic product info for a laptop', }); const productFeatures = await generateObject({ schema: z.object({ features: z.array(z.string()).max(5), specs: z.object({ cpu: z.string(), ram: z.string(), storage: z.string(), }), }), prompt: `Generate features for: ${productBasics.object.name}`, }); ``` ### 2. Reduce Nesting Depth Flatten nested structures where possible: ```typescript // Instead of deep nesting const deep = z.object({ order: z.object({ customer: z.object({ address: z.object({ street: z.string(), city: z.string(), }), }), }), }); // Flatten to reduce complexity const flat = z.object({ customerStreet: z.string(), customerCity: z.string(), // ... other fields at top level }); ``` ### 3. Remove Unnecessary Constraints Only include constraints that are essential: ```typescript // Over-constrained const strict = z.object({ price: z.number().positive().min(0.01).max(999999.99).multipleOf(0.01), quantity: z.number().int().nonnegative().min(0).max(10000), }); // Minimal constraints const minimal = z.object({ price: z.number().positive(), quantity: z.number().int().nonnegative(), }); ``` ### 4. Use Gemini 3 Pro for Complex Schemas `gemini-3-pro-preview` may handle more complex schemas than other models: ```typescript const model = gemini('gemini-3-pro-preview'); // Better for complex schemas ``` ### 5. Post-Generation Validation For constraints that Gemini can't enforce, validate after generation: ```typescript import { z } from 'zod'; // Relaxed schema for generation const generationSchema = z.object({ email: z.string(), price: z.number(), }); // Strict schema for validation const validationSchema = z.object({ email: z.string().email(), price: z.number().multipleOf(0.01), }); const { object } = await generateObject({ model, schema: generationSchema, prompt: 'Generate a user with email and price', }); // Validate and transform const validated = validationSchema.parse(object); ``` ## Error Handling When schema complexity causes failures, handle them gracefully: ```typescript try { const { object } = await generateObject({ model: gemini('gemini-2.5-pro'), schema: complexSchema, prompt: 'Generate complex data', }); } catch (error) { if (error.message?.includes('too many states')) { console.error('Schema too complex for Gemini. Try simplifying.'); // Fall back to simpler schema or different approach } else if (error.message?.includes('could not parse')) { console.error('Generation succeeded but validation failed.'); // The raw response may be available in error.text } else { throw error; } } ``` ## Summary | Limitation | Cause | Solution | |------------|-------|----------| | "too many states" error | Schema complexity exceeds Gemini's internal limits | Simplify schema, reduce nesting | | Validation failures with `multipleOf` | Floating-point precision issues | Remove constraint, validate post-generation | | Complex regex not enforced | Limited regex support in schema | Validate after generation | | Nested arrays of objects | Combinatorial explosion of states | Flatten structure or split into multiple calls | ## Related Documentation - [Zod to Gemini Mapping](./zod-to-gemini-mapping.md) - How Zod types map to Gemini schemas - [Tool Schema Mapping](./tool-schema-mapping.md) - Schema mapping for tool calls - [Examples](../examples/) - Working examples including `generate-object-basic.mjs`