Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/misc/agent-with-cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
require_once dirname(__DIR__).'/bootstrap.php';

$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), http_client());
$cachedPlatform = new CachedPlatform($platform, new TagAwareAdapter(new ArrayAdapter()));
$cachedPlatform = new CachedPlatform($platform, cache: new TagAwareAdapter(new ArrayAdapter()));

$agent = new Agent($cachedPlatform, 'qwen3:0.6b-q4_K_M');
$messages = new MessageBag(
Expand Down
4 changes: 3 additions & 1 deletion src/ai-bundle/src/AiBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -402,13 +402,15 @@ private function processPlatformConfig(string $type, array $platform, ContainerB
->setLazy(true)
->setArguments([
new Reference($cachedPlatformConfig['platform']),
new Reference(ClockInterface::class),
new Reference($cachedPlatformConfig['service'], ContainerInterface::NULL_ON_INVALID_REFERENCE),
$cachedPlatformConfig['cache_key'] ?? $name,
])
->addTag('proxy', ['interface' => PlatformInterface::class])
->addTag('ai.platform', ['name' => 'cache'.$name]);
->addTag('ai.platform', ['name' => 'cache.'.$name]);

$container->setDefinition('ai.platform.cache.'.$name, $definition);
$container->registerAliasForArgument('ai.platform.'.$type, PlatformInterface::class, $type.'_'.$name);
}

return;
Expand Down
46 changes: 36 additions & 10 deletions src/ai-bundle/tests/DependencyInjection/AiBundleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Symfony\AI\Platform\Bridge\ElevenLabs\ModelCatalog as ElevenLabsModelCatalog;
use Symfony\AI\Platform\Bridge\ElevenLabs\PlatformFactory as ElevenLabsPlatformFactory;
use Symfony\AI\Platform\Bridge\Ollama\OllamaApiCatalog;
use Symfony\AI\Platform\CachedPlatform;
use Symfony\AI\Platform\Capability;
use Symfony\AI\Platform\EventListener\TemplateRendererListener;
use Symfony\AI\Platform\Message\TemplateRenderer\ExpressionLanguageTemplateRenderer;
Expand Down Expand Up @@ -74,6 +75,8 @@
use Symfony\AI\Store\ManagedStoreInterface;
use Symfony\AI\Store\RetrieverInterface;
use Symfony\AI\Store\StoreInterface;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\Clock\MonotonicClock;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
Expand Down Expand Up @@ -6225,18 +6228,29 @@ public function testCachedPlatformCanBeUsed()
$this->assertTrue($container->hasDefinition('ai.platform.cache.ollama'));

$definition = $container->getDefinition('ai.platform.cache.ollama');

$this->assertSame(CachedPlatform::class, $definition->getClass());
$this->assertTrue($definition->isLazy());
$this->assertCount(3, $definition->getArguments());
$this->assertCount(4, $definition->getArguments());

$this->assertInstanceOf(Reference::class, $definition->getArgument(0));
$platformArgument = $definition->getArgument(0);
$this->assertSame('ai.platform.ollama', (string) $platformArgument);

$this->assertSame(ClockInterface::class, (string) $definition->getArgument(1));
$this->assertInstanceOf(Reference::class, $definition->getArgument(1));
$cacheArgument = $definition->getArgument(1);
$this->assertSame('cache.app', (string) $cacheArgument);
$this->assertSame('cache.app', (string) $definition->getArgument(2));
$this->assertSame('ollama', $definition->getArgument(3));

$this->assertSame([
['interface' => PlatformInterface::class],
], $definition->getTag('proxy'));
$this->assertTrue($definition->hasTag('ai.platform'));
$this->assertSame([
['name' => 'cache.ollama'],
], $definition->getTag('ai.platform'));

$this->assertSame('ollama', $definition->getArgument(2));
$this->assertTrue($container->hasAlias('.Symfony\AI\Platform\PlatformInterface $cache_ollama'));
$this->assertTrue($container->hasAlias('Symfony\AI\Platform\PlatformInterface $cacheOllama'));
}

public function testCachedPlatformCanBeUsedWithoutCustomCacheKey()
Expand All @@ -6260,18 +6274,29 @@ public function testCachedPlatformCanBeUsedWithoutCustomCacheKey()
$this->assertTrue($container->hasDefinition('ai.platform.cache.ollama'));

$definition = $container->getDefinition('ai.platform.cache.ollama');

$this->assertSame(CachedPlatform::class, $definition->getClass());
$this->assertTrue($definition->isLazy());
$this->assertCount(3, $definition->getArguments());
$this->assertCount(4, $definition->getArguments());

$this->assertInstanceOf(Reference::class, $definition->getArgument(0));
$platformArgument = $definition->getArgument(0);
$this->assertSame('ai.platform.ollama', (string) $platformArgument);

$this->assertSame(ClockInterface::class, (string) $definition->getArgument(1));
$this->assertInstanceOf(Reference::class, $definition->getArgument(1));
$cacheArgument = $definition->getArgument(1);
$this->assertSame('cache.app', (string) $cacheArgument);
$this->assertSame('cache.app', (string) $definition->getArgument(2));
$this->assertSame('ollama', $definition->getArgument(3));

$this->assertSame([
['interface' => PlatformInterface::class],
], $definition->getTag('proxy'));
$this->assertTrue($definition->hasTag('ai.platform'));
$this->assertSame([
['name' => 'cache.ollama'],
], $definition->getTag('ai.platform'));

$this->assertSame('ollama', $definition->getArgument(2));
$this->assertTrue($container->hasAlias('.Symfony\AI\Platform\PlatformInterface $cache_ollama'));
$this->assertTrue($container->hasAlias('Symfony\AI\Platform\PlatformInterface $cacheOllama'));
}

public function testCacheMessageStoreCanBeConfiguredWithCustomKey()
Expand Down Expand Up @@ -6987,6 +7012,7 @@ private function buildContainer(array $configuration): ContainerBuilder
$container->setParameter('kernel.debug', true);
$container->setParameter('kernel.environment', 'dev');
$container->setParameter('kernel.build_dir', 'public');
$container->setDefinition(ClockInterface::class, new Definition(MonotonicClock::class));

$extension = (new AiBundle())->getContainerExtension();
$extension->load($configuration, $container);
Expand Down
7 changes: 5 additions & 2 deletions src/platform/src/CachedPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
use Symfony\AI\Platform\Result\DeferredResult;
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\Clock\MonotonicClock;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;

Expand All @@ -24,6 +26,7 @@ final class CachedPlatform implements PlatformInterface
{
public function __construct(
private readonly PlatformInterface $platform,
private readonly ClockInterface $clock = new MonotonicClock(),
private readonly (CacheInterface&TagAwareAdapterInterface)|null $cache = null,
private readonly ?string $cacheKey = null,
) {
Expand All @@ -38,7 +41,7 @@ public function invoke(string $model, array|string|object $input, array $options

unset($options['prompt_cache_key']);

return $this->cache->get($cacheKey, static function (ItemInterface $item) use ($invokeCall, $model, $input, $options, $cacheKey): DeferredResult {
return $this->cache->get($cacheKey, function (ItemInterface $item) use ($invokeCall, $model, $input, $options, $cacheKey): DeferredResult {
$item->tag($model);

$result = $invokeCall($model, $input, $options);
Expand All @@ -52,7 +55,7 @@ public function invoke(string $model, array|string|object $input, array $options
$result->getMetadata()->set([
'cached' => true,
'cache_key' => $cacheKey,
'cached_at' => (new \DateTimeImmutable())->getTimestamp(),
'cached_at' => $this->clock->now()->getTimestamp(),
]);

return $result;
Expand Down
2 changes: 1 addition & 1 deletion src/platform/tests/CachedPlatformTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function testPlatformCanReturnCachedResultWhenCalledTwice()

$cachedPlatform = new CachedPlatform(
$platform,
new TagAwareAdapter(new ArrayAdapter()),
cache: new TagAwareAdapter(new ArrayAdapter()),
);

$deferredResult = $cachedPlatform->invoke('foo', 'bar', [
Expand Down