Skip to content

Gemini ToolNormalizer doesn't handle nullable parameter types correctlyΒ #1127

@nsrosenqvist

Description

@nsrosenqvist

Disclaimer: I debugged this issue with copilot and asked it to write up the report

Describe Your Problem 🎯

The problem:
The ToolNormalizer for Gemini produces JSON Schema with array-style nullable types ("type": ["string", "null"]) which Gemini's API does not accept. Gemini expects the format "type": "string", "nullable": true instead.

Expected behavior:
Tool parameter schemas with nullable types should be formatted as:

{
  "optional": {
    "type": "string",
    "nullable": true
  }
}

Actual behavior:
The schema is produced with array-style types:

{
  "optional": {
    "type": ["string", "null"]
  }
}

This causes Gemini to return an error:

Invalid JSON payload received. Unknown name "type" at 'tools[0].function_declarations[X].parameters.properties[Y].value': Proto field is not repeating, cannot start list.

Steps to reproduce:

  1. Create a tool with nullable parameters:
#[AsTool(
    name: 'example_tool',
    description: 'An example tool with nullable parameters',
)]
final class ExampleTool
{
    public function __invoke(
        string $required,
        ?string $optional = null,
    ): string {
        return 'result';
    }
}
  1. Register the tool with an Agent using the Gemini platform
  2. Send a chat message that triggers tool schema serialization

Provide Detailed Information πŸ“‹

Component version: symfony/ai-platform (latest/main)

Root cause:
The JsonSchema\Factory class in src/Contract/JsonSchema/Factory.php produces the array-style type format (around line 104):

if ($type->isNullable()) {
    if (!isset($schema['anyOf'])) {
        $schema['type'] = [$schema['type'], 'null'];
    }
}

The ToolNormalizer for Gemini (src/Bridge/Gemini/Contract/ToolNormalizer.php) only removes additionalProperties but doesn't convert the array-style types to Gemini's expected format.

Suggested fix:
The Gemini ToolNormalizer should recursively transform the schema to convert "type": ["string", "null"] to "type": "string", "nullable": true.

Reference: Gemini API Schema documentation shows nullable as a boolean property on Schema objects.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions