|
18 | 18 | use PHPUnit\Framework\Attributes\TestWith; |
19 | 19 | use PHPUnit\Framework\TestCase; |
20 | 20 | use Probots\Pinecone\Client as PineconeClient; |
| 21 | +use Psr\Log\LoggerInterface; |
| 22 | +use Psr\Log\NullLogger; |
21 | 23 | use Symfony\AI\Agent\AgentInterface; |
22 | 24 | use Symfony\AI\Agent\Memory\MemoryInputProcessor; |
23 | 25 | use Symfony\AI\Agent\Memory\StaticMemoryProvider; |
|
31 | 33 | use Symfony\AI\Platform\Bridge\ElevenLabs\ElevenLabsApiCatalog; |
32 | 34 | use Symfony\AI\Platform\Bridge\ElevenLabs\ModelCatalog as ElevenLabsModelCatalog; |
33 | 35 | use Symfony\AI\Platform\Bridge\ElevenLabs\PlatformFactory as ElevenLabsPlatformFactory; |
| 36 | +use Symfony\AI\Platform\Bridge\Failover\FailoverPlatform; |
| 37 | +use Symfony\AI\Platform\Bridge\Failover\FailoverPlatformFactory; |
34 | 38 | use Symfony\AI\Platform\Bridge\Ollama\OllamaApiCatalog; |
35 | 39 | use Symfony\AI\Platform\CachedPlatform; |
36 | 40 | use Symfony\AI\Platform\Capability; |
|
84 | 88 | use Symfony\Component\DependencyInjection\Reference; |
85 | 89 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
86 | 90 | use Symfony\Component\HttpClient\HttpClient; |
| 91 | +use Symfony\Component\RateLimiter\RateLimiterFactory; |
| 92 | +use Symfony\Component\RateLimiter\Storage\InMemoryStorage; |
87 | 93 | use Symfony\Contracts\HttpClient\HttpClientInterface; |
88 | 94 |
|
89 | 95 | class AiBundleTest extends TestCase |
@@ -3947,6 +3953,62 @@ public function testElevenLabsPlatformWithApiCatalogCanBeRegistered() |
3947 | 3953 | $this->assertSame([['interface' => ModelCatalogInterface::class]], $modelCatalogDefinition->getTag('proxy')); |
3948 | 3954 | } |
3949 | 3955 |
|
| 3956 | + public function testFailoverPlatformCanBeCreated() |
| 3957 | + { |
| 3958 | + $container = $this->buildContainer([ |
| 3959 | + 'ai' => [ |
| 3960 | + 'platform' => [ |
| 3961 | + 'ollama' => [ |
| 3962 | + 'host_url' => 'http://127.0.0.1:11434', |
| 3963 | + ], |
| 3964 | + 'openai' => [ |
| 3965 | + 'api_key' => 'sk-openai_key_full', |
| 3966 | + ], |
| 3967 | + 'failover' => [ |
| 3968 | + 'main' => [ |
| 3969 | + 'platforms' => [ |
| 3970 | + 'ai.platform.ollama', |
| 3971 | + 'ai.platform.openai', |
| 3972 | + ], |
| 3973 | + 'rate_limiter' => 'limiter.failover_platform', |
| 3974 | + ], |
| 3975 | + ], |
| 3976 | + ], |
| 3977 | + ], |
| 3978 | + ]); |
| 3979 | + |
| 3980 | + $this->assertTrue($container->hasDefinition('ai.platform.failover.main')); |
| 3981 | + |
| 3982 | + $definition = $container->getDefinition('ai.platform.failover.main'); |
| 3983 | + |
| 3984 | + $this->assertSame([ |
| 3985 | + FailoverPlatformFactory::class, |
| 3986 | + 'create', |
| 3987 | + ], $definition->getFactory()); |
| 3988 | + $this->assertTrue($definition->isLazy()); |
| 3989 | + $this->assertSame(FailoverPlatform::class, $definition->getClass()); |
| 3990 | + |
| 3991 | + $this->assertCount(4, $definition->getArguments()); |
| 3992 | + $this->assertCount(2, $definition->getArgument(0)); |
| 3993 | + $this->assertEquals([ |
| 3994 | + new Reference('ai.platform.ollama'), |
| 3995 | + new Reference('ai.platform.openai'), |
| 3996 | + ], $definition->getArgument(0)); |
| 3997 | + $this->assertInstanceOf(Reference::class, $definition->getArgument(1)); |
| 3998 | + $this->assertSame('limiter.failover_platform', (string) $definition->getArgument(1)); |
| 3999 | + $this->assertInstanceOf(Reference::class, $definition->getArgument(2)); |
| 4000 | + $this->assertSame(ClockInterface::class, (string) $definition->getArgument(2)); |
| 4001 | + $this->assertInstanceOf(Reference::class, $definition->getArgument(3)); |
| 4002 | + $this->assertSame(LoggerInterface::class, (string) $definition->getArgument(3)); |
| 4003 | + |
| 4004 | + $this->assertTrue($definition->hasTag('proxy')); |
| 4005 | + $this->assertSame([['interface' => PlatformInterface::class]], $definition->getTag('proxy')); |
| 4006 | + $this->assertTrue($definition->hasTag('ai.platform')); |
| 4007 | + $this->assertSame([['name' => 'failover']], $definition->getTag('ai.platform')); |
| 4008 | + |
| 4009 | + $this->assertTrue($container->hasAlias('Symfony\AI\Platform\PlatformInterface $main')); |
| 4010 | + } |
| 4011 | + |
3950 | 4012 | public function testOpenAiPlatformWithDefaultRegion() |
3951 | 4013 | { |
3952 | 4014 | $container = $this->buildContainer([ |
@@ -6981,6 +7043,16 @@ private function buildContainer(array $configuration): ContainerBuilder |
6981 | 7043 | $container->setParameter('kernel.environment', 'dev'); |
6982 | 7044 | $container->setParameter('kernel.build_dir', 'public'); |
6983 | 7045 | $container->setDefinition(ClockInterface::class, new Definition(MonotonicClock::class)); |
| 7046 | + $container->setDefinition(LoggerInterface::class, new Definition(NullLogger::class)); |
| 7047 | + $container->setDefinition('limiter.failover_platform', new Definition(RateLimiterFactory::class, [ |
| 7048 | + [ |
| 7049 | + 'policy' => 'sliding_window', |
| 7050 | + 'id' => 'test', |
| 7051 | + 'interval' => '60 seconds', |
| 7052 | + 'limit' => 1, |
| 7053 | + ], |
| 7054 | + new Definition(InMemoryStorage::class), |
| 7055 | + ])); |
6984 | 7056 |
|
6985 | 7057 | $extension = (new AiBundle())->getContainerExtension(); |
6986 | 7058 | $extension->load($configuration, $container); |
@@ -7036,6 +7108,15 @@ private function getFullConfig(): array |
7036 | 7108 | 'host' => 'https://api.elevenlabs.io/v1', |
7037 | 7109 | 'api_key' => 'elevenlabs_key_full', |
7038 | 7110 | ], |
| 7111 | + 'failover' => [ |
| 7112 | + 'main' => [ |
| 7113 | + 'platforms' => [ |
| 7114 | + 'ai.platform.ollama', |
| 7115 | + 'ai.platform.openai', |
| 7116 | + ], |
| 7117 | + 'rate_limiter' => 'limiter.failover_platform', |
| 7118 | + ], |
| 7119 | + ], |
7039 | 7120 | 'gemini' => [ |
7040 | 7121 | 'api_key' => 'gemini_key_full', |
7041 | 7122 | ], |
|
0 commit comments