Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 6356789

Browse files
authored
feat: Google Gemini server tools (#356)
Add support for Google server-side tools like [Google search](https://ai.google.dev/gemini-api/docs/google-search), [URL context](https://ai.google.dev/gemini-api/docs/url-context) & [Code execution](https://ai.google.dev/gemini-api/docs/code-execution) --- I thought of using `Tool` classes for this but didn't find any solution I was happy with, so went the easy way for now. Ideally no changes would've been required for this approach at all, but there were 2 issues: 1. Gemini API insist on providing empty object, and IMO it's not feasible to expect end-user to provide `new \ArrayObject()` 2. If you provide `tools` in `call`'s `$options`, then all toolbox tools go away – hence the new `server_tools` _(open to better naming – `remote_tools`?)_ --- If someone has already given this a thought, please share your thoughts / if there is some clear better approach
1 parent b430dcb commit 6356789

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

examples/google/server-tools.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
use PhpLlm\LlmChain\Chain\Chain;
4+
use PhpLlm\LlmChain\Chain\Toolbox\ChainProcessor;
5+
use PhpLlm\LlmChain\Chain\Toolbox\Tool\Clock;
6+
use PhpLlm\LlmChain\Chain\Toolbox\Toolbox;
7+
use PhpLlm\LlmChain\Platform\Bridge\Google\Gemini;
8+
use PhpLlm\LlmChain\Platform\Bridge\Google\PlatformFactory;
9+
use PhpLlm\LlmChain\Platform\Message\Message;
10+
use PhpLlm\LlmChain\Platform\Message\MessageBag;
11+
use Symfony\Component\Dotenv\Dotenv;
12+
13+
require_once dirname(__DIR__, 2).'/vendor/autoload.php';
14+
(new Dotenv())->loadEnv(dirname(__DIR__, 2).'/.env');
15+
16+
if (empty($_ENV['GOOGLE_API_KEY'])) {
17+
echo 'Please set the GOOGLE_API_KEY environment variable.'.\PHP_EOL;
18+
exit(1);
19+
}
20+
21+
$platform = PlatformFactory::create($_ENV['GOOGLE_API_KEY']);
22+
23+
// Available server-side tools as of 2025-06-28: url_context, google_search, code_execution
24+
$llm = new Gemini('gemini-2.5-pro-preview-03-25', ['server_tools' => ['url_context' => true], 'temperature' => 1.0]);
25+
26+
$toolbox = Toolbox::create(new Clock());
27+
$processor = new ChainProcessor($toolbox);
28+
$chain = new Chain($platform, $llm);
29+
30+
$messages = new MessageBag(
31+
Message::ofUser(
32+
<<<'PROMPT'
33+
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/
34+
PROMPT,
35+
),
36+
);
37+
38+
$response = $chain->call($messages);
39+
40+
echo $response->getContent().\PHP_EOL;

src/Platform/Bridge/Google/ModelHandler.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,21 @@ public function request(Model $model, array|string $payload, array $options = []
6363
$generationConfig = ['generationConfig' => $options];
6464
unset($generationConfig['generationConfig']['stream']);
6565
unset($generationConfig['generationConfig']['tools']);
66+
unset($generationConfig['generationConfig']['server_tools']);
6667

6768
if (isset($options['tools'])) {
6869
$generationConfig['tools'] = $options['tools'];
6970
unset($options['tools']);
7071
}
7172

73+
foreach ($options['server_tools'] ?? [] as $tool => $params) {
74+
if (!$params) {
75+
continue;
76+
}
77+
78+
$generationConfig['tools'][] = [$tool => true === $params ? new \ArrayObject() : $params];
79+
}
80+
7281
return $this->httpClient->request('POST', $url, [
7382
'headers' => [
7483
'x-goog-api-key' => $this->apiKey,

src/Platform/Contract.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use PhpLlm\LlmChain\Platform\Contract\Normalizer\Response\ToolCallNormalizer;
1717
use PhpLlm\LlmChain\Platform\Contract\Normalizer\ToolNormalizer;
1818
use PhpLlm\LlmChain\Platform\Tool\Tool;
19+
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
1920
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
2021
use Symfony\Component\Serializer\Serializer;
2122

@@ -74,6 +75,6 @@ public function createRequestPayload(Model $model, object|array|string $input):
7475
*/
7576
public function createToolOption(array $tools, Model $model): array
7677
{
77-
return $this->normalizer->normalize($tools, context: [self::CONTEXT_MODEL => $model]);
78+
return $this->normalizer->normalize($tools, context: [self::CONTEXT_MODEL => $model, AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS => true]);
7879
}
7980
}

0 commit comments

Comments
 (0)