Skip to content

Commit 2885f6e

Browse files
committed
feature #52 feat: Google Gemini server tools (valtzu)
This PR was merged into the main branch. Discussion ---------- feat: Google Gemini server tools | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Docs? | no | Issues | | License | MIT Cherry picking php-llm/llm-chain#356 Commits ------- 88ca18a feat: Google Gemini server tools (#356)
2 parents 499a3d9 + 88ca18a commit 2885f6e

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

examples/google/server-tools.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use PhpLlm\LlmChain\Chain\Chain;
13+
use PhpLlm\LlmChain\Chain\Toolbox\ChainProcessor;
14+
use PhpLlm\LlmChain\Chain\Toolbox\Tool\Clock;
15+
use PhpLlm\LlmChain\Chain\Toolbox\Toolbox;
16+
use PhpLlm\LlmChain\Platform\Bridge\Google\Gemini;
17+
use PhpLlm\LlmChain\Platform\Bridge\Google\PlatformFactory;
18+
use PhpLlm\LlmChain\Platform\Message\Message;
19+
use PhpLlm\LlmChain\Platform\Message\MessageBag;
20+
use Symfony\Component\Dotenv\Dotenv;
21+
22+
require_once dirname(__DIR__, 2).'/vendor/autoload.php';
23+
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');
24+
25+
if (empty($_ENV['GOOGLE_API_KEY'])) {
26+
echo 'Please set the GOOGLE_API_KEY environment variable.'.\PHP_EOL;
27+
exit(1);
28+
}
29+
30+
$platform = PlatformFactory::create($_ENV['GOOGLE_API_KEY']);
31+
32+
// Available server-side tools as of 2025-06-28: url_context, google_search, code_execution
33+
$llm = new Gemini('gemini-2.5-pro-preview-03-25', ['server_tools' => ['url_context' => true], 'temperature' => 1.0]);
34+
35+
$toolbox = Toolbox::create(new Clock());
36+
$processor = new ChainProcessor($toolbox);
37+
$chain = new Chain($platform, $llm);
38+
39+
$messages = new MessageBag(
40+
Message::ofUser(
41+
<<<'PROMPT'
42+
What was the 12 month Euribor rate a week ago based on https://www.euribor-rates.eu/en/current-euribor-rates/4/euribor-rate-12-months/
43+
PROMPT,
44+
),
45+
);
46+
47+
$response = $chain->call($messages);
48+
49+
echo $response->getContent().\PHP_EOL;

src/platform/src/Bridge/Google/ModelHandler.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,21 @@ public function request(Model $model, array|string $payload, array $options = []
7070
$generationConfig = ['generationConfig' => $options];
7171
unset($generationConfig['generationConfig']['stream']);
7272
unset($generationConfig['generationConfig']['tools']);
73+
unset($generationConfig['generationConfig']['server_tools']);
7374

7475
if (isset($options['tools'])) {
7576
$generationConfig['tools'] = $options['tools'];
7677
unset($options['tools']);
7778
}
7879

80+
foreach ($options['server_tools'] ?? [] as $tool => $params) {
81+
if (!$params) {
82+
continue;
83+
}
84+
85+
$generationConfig['tools'][] = [$tool => true === $params ? new \ArrayObject() : $params];
86+
}
87+
7988
return $this->httpClient->request('POST', $url, [
8089
'headers' => [
8190
'x-goog-api-key' => $this->apiKey,

src/platform/src/Contract.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Symfony\AI\Platform\Contract\Normalizer\Response\ToolCallNormalizer;
2424
use Symfony\AI\Platform\Contract\Normalizer\ToolNormalizer;
2525
use Symfony\AI\Platform\Tool\Tool;
26+
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
2627
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
2728
use Symfony\Component\Serializer\Serializer;
2829

@@ -81,6 +82,9 @@ public function createRequestPayload(Model $model, object|array|string $input):
8182
*/
8283
public function createToolOption(array $tools, Model $model): array
8384
{
84-
return $this->normalizer->normalize($tools, context: [self::CONTEXT_MODEL => $model]);
85+
return $this->normalizer->normalize($tools, context: [
86+
self::CONTEXT_MODEL => $model,
87+
AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS => true,
88+
]);
8589
}
8690
}

0 commit comments

Comments
 (0)