Skip to content

Commit 4eb5f12

Browse files
DZunkechr-hertel
authored andcommitted
feat: open contract for more flexible normalizer configuration (#372)
Could fix part of #371 - the question for flexibility. Why? Messages are given on platform calls and are given with the `MessageInterface`. So it is very flexible what could be given on call. Normalizers are only configured once, internally. So one side is highly flexible, the other side not. Giving the contract an interface allows creating own contracts with whatever backed technology one wants. So more flexible. Additionally it allows to add a contract that has an amount of normalizers one wants. For making it easier i thought about having model contract sets. I did it for anthropic, google and the platform itself. So a custom contract could look like ```php use PhpLlm\LlmChain\Platform\Bridge\OpenAI\PlatformFactory; use PhpLlm\LlmChain\Platform\Contract; $platform = PlatformFactory::create( 'my-api-key', contract: Contract::create(new MyOwnMessageBagNormalizer(), new MyOwnMessageThingyNormalizer()), ); ``` or, totally flexible: ```php use PhpLlm\LlmChain\Platform\Bridge\OpenAI\PlatformFactory; $platform = PlatformFactory::create( 'my-api-key', contract: new MyVeryOwnContractUtilizingJsonStreamer(), ); ``` Maybe this could be a way for more flexibility with the combination of non configurable normalizer and "unknown" message input?
1 parent 7f0b662 commit 4eb5f12

File tree

15 files changed

+116
-49
lines changed

15 files changed

+116
-49
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
namespace Symfony\AI\Platform\Bridge\Anthropic\Contract;
13+
14+
use Symfony\AI\Platform\Contract;
15+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
16+
17+
/**
18+
* @author Denis Zunke <[email protected]>
19+
*/
20+
final readonly class AnthropicContract extends Contract
21+
{
22+
public static function create(NormalizerInterface ...$normalizer): Contract
23+
{
24+
return parent::create(
25+
new AssistantMessageNormalizer(),
26+
new DocumentNormalizer(),
27+
new DocumentUrlNormalizer(),
28+
new ImageNormalizer(),
29+
new ImageUrlNormalizer(),
30+
new MessageBagNormalizer(),
31+
new ToolCallMessageNormalizer(),
32+
new ToolNormalizer(),
33+
...$normalizer,
34+
);
35+
}
36+
}

src/platform/src/Bridge/Anthropic/PlatformFactory.php

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,7 @@
1111

1212
namespace Symfony\AI\Platform\Bridge\Anthropic;
1313

14-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\AssistantMessageNormalizer;
15-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\DocumentNormalizer;
16-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\DocumentUrlNormalizer;
17-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\ImageNormalizer;
18-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\ImageUrlNormalizer;
19-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\MessageBagNormalizer;
20-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\ToolCallMessageNormalizer;
21-
use Symfony\AI\Platform\Bridge\Anthropic\Contract\ToolNormalizer;
14+
use Symfony\AI\Platform\Bridge\Anthropic\Contract\AnthropicContract;
2215
use Symfony\AI\Platform\Contract;
2316
use Symfony\AI\Platform\Platform;
2417
use Symfony\Component\HttpClient\EventSourceHttpClient;
@@ -34,22 +27,14 @@ public static function create(
3427
string $apiKey,
3528
string $version = '2023-06-01',
3629
?HttpClientInterface $httpClient = null,
30+
?Contract $contract = null,
3731
): Platform {
3832
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
3933

4034
return new Platform(
4135
[new ModelClient($httpClient, $apiKey, $version)],
4236
[new ResponseConverter()],
43-
Contract::create(
44-
new AssistantMessageNormalizer(),
45-
new DocumentNormalizer(),
46-
new DocumentUrlNormalizer(),
47-
new ImageNormalizer(),
48-
new ImageUrlNormalizer(),
49-
new MessageBagNormalizer(),
50-
new ToolCallMessageNormalizer(),
51-
new ToolNormalizer(),
52-
)
37+
$contract ?? AnthropicContract::create(),
5338
);
5439
}
5540
}

src/platform/src/Bridge/Azure/Meta/PlatformFactory.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\AI\Platform\Bridge\Azure\Meta;
1313

14+
use Symfony\AI\Platform\Contract;
1415
use Symfony\AI\Platform\Platform;
1516
use Symfony\Component\HttpClient\HttpClient;
1617
use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -25,9 +26,10 @@ public static function create(
2526
#[\SensitiveParameter]
2627
string $apiKey,
2728
?HttpClientInterface $httpClient = null,
29+
?Contract $contract = null,
2830
): Platform {
2931
$modelClient = new LlamaHandler($httpClient ?? HttpClient::create(), $baseUrl, $apiKey);
3032

31-
return new Platform([$modelClient], [$modelClient]);
33+
return new Platform([$modelClient], [$modelClient], $contract);
3234
}
3335
}

src/platform/src/Bridge/Azure/OpenAI/PlatformFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public static function create(
3131
#[\SensitiveParameter]
3232
string $apiKey,
3333
?HttpClientInterface $httpClient = null,
34+
?Contract $contract = null,
3435
): Platform {
3536
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
3637
$embeddingsResponseFactory = new EmbeddingsModelClient($httpClient, $baseUrl, $deployment, $apiVersion, $apiKey);
@@ -40,7 +41,7 @@ public static function create(
4041
return new Platform(
4142
[$GPTResponseFactory, $embeddingsResponseFactory, $whisperResponseFactory],
4243
[new ResponseConverter(), new Embeddings\ResponseConverter(), new \Symfony\AI\Platform\Bridge\OpenAI\Whisper\ResponseConverter()],
43-
Contract::create(new AudioNormalizer()),
44+
$contract ?? Contract::create(new AudioNormalizer()),
4445
);
4546
}
4647
}

src/platform/src/Bridge/Bedrock/PlatformFactory.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\AI\Platform\Bridge\Bedrock\Anthropic\ClaudeHandler;
1616
use Symfony\AI\Platform\Bridge\Bedrock\Meta\LlamaModelClient;
1717
use Symfony\AI\Platform\Bridge\Bedrock\Nova\NovaHandler;
18+
use Symfony\AI\Platform\Contract;
1819

1920
/**
2021
* @author Björn Altmann
@@ -23,11 +24,12 @@
2324
{
2425
public static function create(
2526
BedrockRuntimeClient $bedrockRuntimeClient = new BedrockRuntimeClient(),
27+
?Contract $contract = null,
2628
): Platform {
2729
$modelClient[] = new ClaudeHandler($bedrockRuntimeClient);
2830
$modelClient[] = new NovaHandler($bedrockRuntimeClient);
2931
$modelClient[] = new LlamaModelClient($bedrockRuntimeClient);
3032

31-
return new Platform($modelClient);
33+
return new Platform($modelClient, $contract);
3234
}
3335
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
namespace Symfony\AI\Platform\Bridge\Google\Contract;
13+
14+
use Symfony\AI\Platform\Contract;
15+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
16+
17+
/**
18+
* @author Denis Zunke <[email protected]>
19+
*/
20+
final readonly class GoogleContract extends Contract
21+
{
22+
public static function create(NormalizerInterface ...$normalizer): Contract
23+
{
24+
return parent::create(
25+
new AssistantMessageNormalizer(),
26+
new MessageBagNormalizer(),
27+
new ToolNormalizer(),
28+
new ToolCallMessageNormalizer(),
29+
new UserMessageNormalizer(),
30+
...$normalizer,
31+
);
32+
}
33+
}

src/platform/src/Bridge/Google/PlatformFactory.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@
1111

1212
namespace Symfony\AI\Platform\Bridge\Google;
1313

14-
use Symfony\AI\Platform\Bridge\Google\Contract\AssistantMessageNormalizer;
15-
use Symfony\AI\Platform\Bridge\Google\Contract\MessageBagNormalizer;
16-
use Symfony\AI\Platform\Bridge\Google\Contract\ToolCallMessageNormalizer;
17-
use Symfony\AI\Platform\Bridge\Google\Contract\ToolNormalizer;
18-
use Symfony\AI\Platform\Bridge\Google\Contract\UserMessageNormalizer;
14+
use Symfony\AI\Platform\Bridge\Google\Contract\GoogleContract;
1915
use Symfony\AI\Platform\Bridge\Google\Embeddings\ModelClient;
2016
use Symfony\AI\Platform\Contract;
2117
use Symfony\AI\Platform\Platform;
@@ -31,17 +27,16 @@ public static function create(
3127
#[\SensitiveParameter]
3228
string $apiKey,
3329
?HttpClientInterface $httpClient = null,
30+
?Contract $contract = null,
3431
): Platform {
3532
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
3633
$responseHandler = new ModelHandler($httpClient, $apiKey);
3734
$embeddings = new ModelClient($httpClient, $apiKey);
3835

39-
return new Platform([$responseHandler, $embeddings], [$responseHandler, $embeddings], Contract::create(
40-
new AssistantMessageNormalizer(),
41-
new MessageBagNormalizer(),
42-
new ToolNormalizer(),
43-
new ToolCallMessageNormalizer(),
44-
new UserMessageNormalizer(),
45-
));
36+
return new Platform(
37+
[$responseHandler, $embeddings],
38+
[$responseHandler, $embeddings],
39+
$contract ?? GoogleContract::create(),
40+
);
4641
}
4742
}

src/platform/src/Bridge/HuggingFace/PlatformFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ public static function create(
2828
string $apiKey,
2929
string $provider = Provider::HF_INFERENCE,
3030
?HttpClientInterface $httpClient = null,
31+
?Contract $contract = null,
3132
): Platform {
3233
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
3334

3435
return new Platform(
3536
[new ModelClient($httpClient, $provider, $apiKey)],
3637
[new ResponseConverter()],
37-
Contract::create(
38+
$contract ?? Contract::create(
3839
new FileNormalizer(),
3940
new MessageBagNormalizer(),
4041
),

src/platform/src/Bridge/Mistral/PlatformFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ public static function create(
3030
#[\SensitiveParameter]
3131
string $apiKey,
3232
?HttpClientInterface $httpClient = null,
33+
?Contract $contract = null,
3334
): Platform {
3435
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
3536

3637
return new Platform(
3738
[new EmbeddingsModelClient($httpClient, $apiKey), new MistralModelClient($httpClient, $apiKey)],
3839
[new EmbeddingsResponseConverter(), new MistralResponseConverter()],
39-
Contract::create(new ToolNormalizer()),
40+
$contract ?? Contract::create(new ToolNormalizer()),
4041
);
4142
}
4243
}

src/platform/src/Bridge/Ollama/PlatformFactory.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\AI\Platform\Bridge\Ollama;
1313

14+
use Symfony\AI\Platform\Contract;
1415
use Symfony\AI\Platform\Platform;
1516
use Symfony\Component\HttpClient\EventSourceHttpClient;
1617
use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -23,10 +24,11 @@ final class PlatformFactory
2324
public static function create(
2425
string $hostUrl = 'http://localhost:11434',
2526
?HttpClientInterface $httpClient = null,
27+
?Contract $contract = null,
2628
): Platform {
2729
$httpClient = $httpClient instanceof EventSourceHttpClient ? $httpClient : new EventSourceHttpClient($httpClient);
2830
$handler = new LlamaModelHandler($httpClient, $hostUrl);
2931

30-
return new Platform([$handler], [$handler]);
32+
return new Platform([$handler], [$handler], $contract);
3133
}
3234
}

0 commit comments

Comments
 (0)