Skip to content

Commit 5d8ead5

Browse files
authored
Merge pull request #10 from b13/issue-1
Dynamically resolve correct max tokens key
2 parents c1f007b + 5d45f57 commit 5d8ead5

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

Classes/Provider/SymfonyAi/SymfonyAiPlatformAdapter.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,18 @@ class SymfonyAiPlatformAdapter implements
6464
/** @var array<string, PlatformInterface> Platforms cached by configuration key */
6565
private array $platforms = [];
6666

67+
private readonly string $maxTokensKey;
68+
6769
/**
6870
* @param string $factoryClass Fully-qualified class name of the bridge's PlatformFactory
6971
* @param string $factoryParam Name of the factory parameter to pass the config value to ('apiKey' or 'endpoint')
7072
*/
7173
public function __construct(
7274
private readonly string $factoryClass,
7375
private readonly string $factoryParam = 'apiKey',
74-
) {}
76+
) {
77+
$this->maxTokensKey = self::resolveMaxTokensKey($factoryClass);
78+
}
7579

7680
public function processVisionRequest(VisionRequest $request): TextResponse
7781
{
@@ -433,13 +437,26 @@ private function buildMessageBag(array $aiMessages, string $systemPrompt): Messa
433437
*/
434438
private function buildOptions(string $model, int $maxTokens, float $temperature, array $extra = []): array
435439
{
436-
$options = ['max_output_tokens' => $maxTokens] + $extra;
440+
$options = [$this->maxTokensKey => $maxTokens] + $extra;
437441
if (!$this->isReasoningModel($model)) {
438442
$options['temperature'] = $temperature;
439443
}
440444
return $options;
441445
}
442446

447+
/**
448+
* Resolve the max-tokens option key expected by a Symfony AI bridge based on the used bridge
449+
*/
450+
public static function resolveMaxTokensKey(string $factoryClass): string
451+
{
452+
if (str_contains($factoryClass, '\\Bridge\\OpenAi\\')
453+
|| str_contains($factoryClass, '\\Bridge\\OpenResponses\\')
454+
) {
455+
return 'max_output_tokens';
456+
}
457+
return 'max_tokens';
458+
}
459+
443460
/**
444461
* Check if a model is a reasoning model that doesn't support temperature.
445462
*
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of TYPO3 CMS-based extension "aim" by b13.
7+
*
8+
* It is free software; you can redistribute it and/or modify it under
9+
* the terms of the GNU General Public License, either version 2
10+
* of the License, or any later version.
11+
*/
12+
13+
namespace B13\Aim\Tests\Unit\Provider\SymfonyAi;
14+
15+
use B13\Aim\Provider\SymfonyAi\SymfonyAiPlatformAdapter;
16+
use PHPUnit\Framework\Attributes\DataProvider;
17+
use PHPUnit\Framework\Attributes\Test;
18+
use PHPUnit\Framework\TestCase;
19+
20+
final class SymfonyAiPlatformAdapterTest extends TestCase
21+
{
22+
public static function maxTokensKeyProvider(): \Generator
23+
{
24+
yield 'OpenAI Responses API' => [
25+
'Symfony\\AI\\Platform\\Bridge\\OpenAi\\PlatformFactory',
26+
'max_output_tokens',
27+
];
28+
yield 'OpenResponses bridge' => [
29+
'Symfony\\AI\\Platform\\Bridge\\OpenResponses\\PlatformFactory',
30+
'max_output_tokens',
31+
];
32+
yield 'Anthropic Messages API' => [
33+
'Symfony\\AI\\Platform\\Bridge\\Anthropic\\PlatformFactory',
34+
'max_tokens',
35+
];
36+
yield 'Mistral' => [
37+
'Symfony\\AI\\Platform\\Bridge\\Mistral\\PlatformFactory',
38+
'max_tokens',
39+
];
40+
yield 'Ollama' => [
41+
'Symfony\\AI\\Platform\\Bridge\\Ollama\\PlatformFactory',
42+
'max_tokens',
43+
];
44+
yield 'unknown bridge falls back to max_tokens' => [
45+
'Acme\\AiBridge\\PlatformFactory',
46+
'max_tokens',
47+
];
48+
}
49+
50+
#[Test]
51+
#[DataProvider('maxTokensKeyProvider')]
52+
public function resolveMaxTokensKeyMapsBridgeToCorrectOptionName(string $factoryClass, string $expectedKey): void
53+
{
54+
self::assertSame($expectedKey, SymfonyAiPlatformAdapter::resolveMaxTokensKey($factoryClass));
55+
}
56+
}

0 commit comments

Comments
 (0)