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
Requires
- php: ^8.3
- adachsoft/ai-integration: ^0.3.0
- guzzlehttp/guzzle: ^7.0
Requires (Dev)
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_KEYmust be available in the environment (for example via your framework's.envhandling or system-level configuration). This library does not manage or modify.envfiles.
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
GeminiToolCallingChatSpiand registers it under provider idgemini. - Defines a simple
sum(a, b)tool. - Runs two calls (2.5 and 3.x) and prints the final answer.
- Exits with code
0when a non-empty final result is returned; otherwise exits with1.
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
GeminiToolCallingChatSpiinstance. - Registers it in
ToolCallingChatFacadeBuilderunder provider idgemini. - Uses a
reveal_secrettool 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-emptythoughtSignaturein response metadata).
- Validates that, for Gemini 3.x models, the
thoughtSignaturefield 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 undertests/Unit.production- live integration test undertests/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) becomeResourceExhaustedSpiException. - Transient errors (5xx) become
RetriableSpiExceptionwith an optionalretryAfterSecondshint. - Invalid or unexpected JSON structures become
SpiExceptionviaGeminiInvalidResponseException.
For Gemini 3.x models, the provider can additionally expose reasoning-related metadata in the SPI response, such as:
thinkingandthoughtSignature(when present in Gemini response),usageMetadatawith token usage details.
These are made available through the metadata and tokenUsage fields of ToolCallingChatSpiResponse.