adachsoft/ai-integration-gemini

Gemini SPI provider for adachsoft/ai-integration: tool-calling chat integration with Google Gemini 2.5 and 3.x models.

Installs: 4

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Forks: 0

pkg:composer/adachsoft/ai-integration-gemini

v0.2.2 2025-12-03 16:05 UTC

This package is not auto-updated.

Last update: 2025-12-03 15:24:05 UTC


README

Integration library that provides a single gemini SPI provider for adachsoft/ai-integration.

It enables tool-calling and reasoning for Gemini 2.5 and 3.x models using Guzzle as HTTP client.

Status: Provider implementation and unit tests are complete. A production test and example script are available for real end-to-end verification against Gemini API.

Requirements

  • PHP: ^8.3
  • adachsoft/ai-integration (installed as a dependency)
  • guzzlehttp/guzzle: ^7.0
  • A valid Gemini API key exported as environment variable GOOGLE_GEMINI_API_KEY
  • Network access to https://generativelanguage.googleapis.com (v1beta/v1alpha endpoints, depending on model)

Installation

Install via Composer in a project that already uses adachsoft/ai-integration:

composer require adachsoft/ai-integration-gemini

Composer will register the AdachSoft\AiIntegrationGemini\ namespace pointing to the src/ directory.

Configuration

The provider is configured through the GeminiConfig value object:

use AdachSoft\AiIntegrationGemini\Config\GeminiConfig;

$config = new GeminiConfig(
    apiKey: getenv('GOOGLE_GEMINI_API_KEY') ?: '',
    defaultModelId: 'gemini-3.0-pro', // or any other supported Gemini model id
    defaultThinkingLevel: 'HIGH',     // optional, reasoning level for v3 models
    defaultThinkingBudget: 2000,      // optional, reasoning token budget for v3 models
    // baseUri and defaultTemperature have sensible defaults
);

GOOGLE_GEMINI_API_KEY must be available in the environment (for example via your framework's .env handling or system-level configuration). This library does not manage or modify .env files.

Quick Start

The Gemini provider is exposed as a single SPI provider gemini for the ToolCallingChatFacade from adachsoft/ai-integration.

1. Build the SPI provider

use AdachSoft\AiIntegrationGemini\Config\GeminiConfig;
use AdachSoft\AiIntegrationGemini\GeminiToolCallingChatSpi;
use AdachSoft\AiIntegrationGemini\Http\GeminiHttpClient;
use AdachSoft\AiIntegrationGemini\Mapper\GeminiResponseToSpiMapper;
use AdachSoft\AiIntegrationGemini\Mapper\SpiToGeminiRequestMapper;
use AdachSoft\AiIntegrationGemini\Version\GeminiApiVersionDetector;
use GuzzleHttp\Client;

$apiKey = getenv('GOOGLE_GEMINI_API_KEY');

if ($apiKey === false || $apiKey === '') {
    throw new RuntimeException('GOOGLE_GEMINI_API_KEY is not configured.');
}

$config = new GeminiConfig(
    apiKey: $apiKey,
    defaultModelId: 'gemini-2.5-pro',
    defaultThinkingLevel: 'HIGH',
    defaultThinkingBudget: 2000,
);

$httpClient = new GeminiHttpClient(
    httpClient: new Client(),
    config: $config,
);

$spiProvider = new GeminiToolCallingChatSpi(
    config: $config,
    versionDetector: new GeminiApiVersionDetector(),
    requestMapper: new SpiToGeminiRequestMapper(),
    responseMapper: new GeminiResponseToSpiMapper(),
    httpClient: $httpClient,
);

2. Register provider in the facade

use AdachSoft\AiIntegration\PublicApi\Builder\ToolCallingChatFacadeBuilder;

$facadeBuilder = new ToolCallingChatFacadeBuilder();
$facadeBuilder->withSpiProvider('gemini', $spiProvider);
$facade = $facadeBuilder->build();

3. Define tools and run a simple roundtrip

use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\ChatMessageDto;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\Collection\ChatMessageDtoCollection;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\Collection\ToolDefinitionDtoCollection;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\ToolCallingChatRequestDto;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\ToolDefinitionDto;

$tools = new ToolDefinitionDtoCollection([
    new ToolDefinitionDto(
        name: 'sum',
        description: 'Sums two integers',
        parametersSchema: [
            'type' => 'object',
            'properties' => [
                'a' => ['type' => 'integer'],
                'b' => ['type' => 'integer'],
            ],
            'required' => ['a', 'b'],
        ],
    ),
]);

$messages = new ChatMessageDtoCollection([
    new ChatMessageDto('user', 'Please call sum(a=2, b=3).'),
]);

$request1 = new ToolCallingChatRequestDto(
    messages: $messages,
    tools: $tools,
    providerId: 'gemini',
    modelId: 'gemini-2.5-pro',
);

$response1 = $facade->chat($request1);

$toolCall = $response1->toolCalls->first();
$result = ($toolCall->arguments['a'] ?? 0) + ($toolCall->arguments['b'] ?? 0);

$toolResponseMessage = new ChatMessageDto(
    role: 'tool',
    content: (string) $result,
    metadata: ['toolName' => $toolCall->toolName],
);

$messages2 = new ChatMessageDtoCollection([
    ...$messages,
    $toolResponseMessage,
]);

$request2 = new ToolCallingChatRequestDto(
    messages: $messages2,
    tools: $tools,
    providerId: 'gemini',
    modelId: 'gemini-3.0-pro',
);

$response2 = $facade->chat($request2);

$finalText = $response2->result; // string|null

Examples and production test

This repository contains two ways to validate the integration end-to-end against real Gemini models:

1. CLI example

examples/test_gemini_tool_calling_via_spi.php shows a full roundtrip:

  • Builds GeminiToolCallingChatSpi and registers it under provider id gemini.
  • Defines a simple sum(a, b) tool.
  • Runs two calls (2.5 and 3.x) and prints the final answer.
  • Exits with code 0 when a non-empty final result is returned; otherwise exits with 1.

Run it with:

export GOOGLE_GEMINI_API_KEY="your-key-here" # or equivalent for your environment
php examples/test_gemini_tool_calling_via_spi.php

2. Production PHPUnit test

tests/Production/GeminiProviderProductionTest.php contains a production-style PHPUnit test that:

  • Builds a real GeminiToolCallingChatSpi instance.
  • Registers it in ToolCallingChatFacadeBuilder under provider id gemini.
  • Uses a reveal_secret tool that returns a secret value.
  • Executes a two- or three-step tool-calling roundtrip for:
    • gemini-2.5-pro (expects at least one tool call and that the final response contains the secret),
    • gemini-3-pro-preview (same behaviour, additionally asserting presence of a non-empty thoughtSignature in response metadata).
  • Validates that, for Gemini 3.x models, the thoughtSignature field is propagated into SPI response metadata.

The test is skipped automatically when GOOGLE_GEMINI_API_KEY is not configured in the environment.

The PHPUnit configuration defines separate test suites:

  • unit (default) - fast unit tests under tests/Unit.
  • production - live integration test under tests/Production.

Run tests with:

# unit tests only (default)
vendor/bin/phpunit

# production test against real Gemini API
vendor/bin/phpunit --testsuite production

Error handling and reasoning metadata

The provider translates Gemini-specific HTTP and JSON errors into SPI-level exceptions defined by adachsoft/ai-integration:

  • Quota/limit issues (HTTP 429 or RESOURCE_EXHAUSTED) become ResourceExhaustedSpiException.
  • Transient errors (5xx) become RetriableSpiException with an optional retryAfterSeconds hint.
  • Invalid or unexpected JSON structures become SpiException via GeminiInvalidResponseException.

For Gemini 3.x models, the provider can additionally expose reasoning-related metadata in the SPI response, such as:

  • thinking and thoughtSignature (when present in Gemini response),
  • usageMetadata with token usage details.

These are made available through the metadata and tokenUsage fields of ToolCallingChatSpiResponse.