mirror of
https://github.com/symfony/ai.git
synced 2026-03-23 23:42:18 +01:00
refactor(ollama): remove ModelCatalog
This commit is contained in:
14
UPGRADE.md
14
UPGRADE.md
@@ -1,6 +1,20 @@
|
||||
UPGRADE FROM 0.6 to 0.7
|
||||
=======================
|
||||
|
||||
AI Bundle
|
||||
---------
|
||||
|
||||
* The `api_catalog` option for `Ollama` has been removed as the catalog is now automatically fetched from the Ollama server
|
||||
* The `api_key` option for `Ollama` is now `null` by default to allow the usage of a `ScopingHttpClient`
|
||||
* The `endpoint` option for `Ollama` is now `null` by default to allow the usage of a `ScopingHttpClient`
|
||||
|
||||
Platform
|
||||
-----
|
||||
|
||||
* `ModelCatalog` in `Ollama` has been replaced by `OllamaApiCatalog`
|
||||
* `OllamaApiCatalog` in `Ollama` has been replaced to `ModelCatalog`
|
||||
* `Ollama` model is now `final`
|
||||
|
||||
Store
|
||||
-----
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ use Symfony\AI\Platform\Message\MessageBag;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
try {
|
||||
$result = $platform->invoke(env('OLLAMA_LLM'), new MessageBag(
|
||||
|
||||
@@ -15,7 +15,7 @@ use Symfony\AI\Platform\Message\MessageBag;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
$messages = new MessageBag(
|
||||
Message::forSystem('You are a helpful assistant.'),
|
||||
|
||||
@@ -13,7 +13,7 @@ use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
$response = $platform->invoke(env('OLLAMA_EMBEDDINGS'), <<<TEXT
|
||||
Once upon a time, there was a country called Japan. It was a beautiful country with a lot of mountains and rivers.
|
||||
|
||||
@@ -21,7 +21,8 @@ use Symfony\AI\Store\Query\VectorQuery;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
$store = new InMemoryStore();
|
||||
$vectorizer = new Vectorizer($platform, env('OLLAMA_EMBEDDINGS'), logger());
|
||||
$indexer = new SourceIndexer(
|
||||
|
||||
@@ -41,7 +41,7 @@ foreach (Movies::all() as $i => $movie) {
|
||||
}
|
||||
|
||||
// create embeddings for documents
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
$vectorizer = new Vectorizer($platform, env('OLLAMA_EMBEDDINGS'), logger());
|
||||
$indexer = new DocumentIndexer(new DocumentProcessor($vectorizer, $store, logger: logger()));
|
||||
$indexer->index($documents);
|
||||
|
||||
@@ -19,7 +19,7 @@ use Symfony\AI\Platform\Message\MessageBag;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
$toolbox = new Toolbox([new Clock()], logger: logger());
|
||||
$processor = new AgentProcessor($toolbox);
|
||||
|
||||
@@ -15,7 +15,7 @@ use Symfony\AI\Platform\Message\MessageBag;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
$messages = new MessageBag(
|
||||
Message::forSystem('You are a helpful assistant.'),
|
||||
|
||||
@@ -15,7 +15,7 @@ use Symfony\AI\Platform\Message\MessageBag;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
$messages = new MessageBag(
|
||||
Message::forSystem('You are a helpful assistant.'),
|
||||
|
||||
@@ -21,7 +21,7 @@ require_once dirname(__DIR__).'/bootstrap.php';
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->addSubscriber(new PlatformSubscriber());
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client(), eventDispatcher: $dispatcher);
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client(), eventDispatcher: $dispatcher);
|
||||
$messages = new MessageBag(
|
||||
Message::forSystem('You are a helpful math tutor. Guide the user through the solution step by step.'),
|
||||
Message::ofUser('how can I solve 8x + 7 = -23'),
|
||||
|
||||
@@ -19,7 +19,7 @@ use Symfony\AI\Platform\Message\MessageBag;
|
||||
|
||||
require_once dirname(__DIR__).'/bootstrap.php';
|
||||
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), httpClient: http_client());
|
||||
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), env('OLLAMA_API_KEY'), httpClient: http_client());
|
||||
|
||||
$toolbox = new Toolbox([new Clock()], logger: logger());
|
||||
$processor = new AgentProcessor($toolbox);
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.7
|
||||
---
|
||||
|
||||
* The `api_catalog` option for `Ollama` has been removed as the catalog is now automatically fetched from the Ollama server
|
||||
* The `api_key` option for `Ollama` is now `null` by default to allow the usage of a `ScopingHttpClient`
|
||||
* The `endpoint` option for `Ollama` is now `null` by default to allow the usage of a `ScopingHttpClient`
|
||||
|
||||
0.6
|
||||
---
|
||||
|
||||
|
||||
@@ -16,18 +16,13 @@ use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
return (new ArrayNodeDefinition('ollama'))
|
||||
->children()
|
||||
->stringNode('endpoint')
|
||||
->defaultNull()
|
||||
->info('Endpoint for Ollama (e.g. "http://127.0.0.1:11434" for local, or a cloud endpoint). If null, the http_client is used as-is and must already be configured with a base URI.')
|
||||
->end()
|
||||
->stringNode('api_key')
|
||||
->defaultNull()
|
||||
->info('API key for Ollama Cloud authentication (optional for local usage)')
|
||||
->end()
|
||||
->stringNode('http_client')
|
||||
->defaultValue('http_client')
|
||||
->info('Service ID of the HTTP client to use. When "endpoint" is null, this client must be pre-configured (e.g. with a base_uri).')
|
||||
->end()
|
||||
->booleanNode('api_catalog')
|
||||
->info('If set, the Ollama API will be used to build the catalog and retrieve models information, using this option leads to additional HTTP calls')
|
||||
->end()
|
||||
->end();
|
||||
|
||||
@@ -46,7 +46,6 @@ use Symfony\AI\Platform\Bridge\LmStudio\ModelCatalog as LmStudioModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Meta\ModelCatalog as MetaModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Mistral\ModelCatalog as MistralModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\Contract\OllamaContract;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\ModelCatalog as OllamaModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\OpenAi\Contract\OpenAiContract;
|
||||
use Symfony\AI\Platform\Bridge\OpenAi\ModelCatalog as OpenAiModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\OpenRouter\ModelCatalog as OpenRouterModelCatalog;
|
||||
@@ -122,9 +121,6 @@ return static function (ContainerConfigurator $container): void {
|
||||
->set('ai.platform.model_catalog.lmstudio', LmStudioModelCatalog::class)
|
||||
->set('ai.platform.model_catalog.meta', MetaModelCatalog::class)
|
||||
->set('ai.platform.model_catalog.mistral', MistralModelCatalog::class)
|
||||
->set('ai.platform.model_catalog.ollama', OllamaModelCatalog::class)
|
||||
->lazy()
|
||||
->tag('proxy', ['interface' => ModelCatalogInterface::class])
|
||||
->set('ai.platform.model_catalog.openai', OpenAiModelCatalog::class)
|
||||
->set('ai.platform.model_catalog.openrouter', OpenRouterModelCatalog::class)
|
||||
->set('ai.platform.model_catalog.ovh', OvhModelCatalog::class)
|
||||
|
||||
@@ -68,7 +68,7 @@ use Symfony\AI\Platform\Bridge\Generic\PlatformFactory as GenericPlatformFactory
|
||||
use Symfony\AI\Platform\Bridge\HuggingFace\PlatformFactory as HuggingFacePlatformFactory;
|
||||
use Symfony\AI\Platform\Bridge\LmStudio\PlatformFactory as LmStudioPlatformFactory;
|
||||
use Symfony\AI\Platform\Bridge\Mistral\PlatformFactory as MistralPlatformFactory;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\OllamaApiCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\ModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory as OllamaPlatformFactory;
|
||||
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory as OpenAiPlatformFactory;
|
||||
use Symfony\AI\Platform\Bridge\OpenRouter\PlatformFactory as OpenRouterPlatformFactory;
|
||||
@@ -81,7 +81,6 @@ use Symfony\AI\Platform\Bridge\Voyage\PlatformFactory as VoyagePlatformFactory;
|
||||
use Symfony\AI\Platform\Capability;
|
||||
use Symfony\AI\Platform\Exception\RuntimeException;
|
||||
use Symfony\AI\Platform\Message\Content\File;
|
||||
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
|
||||
use Symfony\AI\Platform\ModelClientInterface;
|
||||
use Symfony\AI\Platform\Platform;
|
||||
use Symfony\AI\Platform\PlatformInterface;
|
||||
@@ -137,7 +136,6 @@ use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Symfony\Component\HttpClient\ScopingHttpClient;
|
||||
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Component\Translation\TranslatableMessage;
|
||||
@@ -849,47 +847,13 @@ final class AiBundle extends AbstractBundle
|
||||
throw new RuntimeException('Ollama platform configuration requires "symfony/ai-ollama-platform" package. Try running "composer require symfony/ai-ollama-platform".');
|
||||
}
|
||||
|
||||
$httpClientReference = new Reference($platform['http_client']);
|
||||
|
||||
if (null !== $platform['endpoint']) {
|
||||
$defaultOptions = [];
|
||||
if (null !== ($platform['api_key'] ?? null)) {
|
||||
$defaultOptions['auth_bearer'] = $platform['api_key'];
|
||||
}
|
||||
|
||||
$scopedClientDefinition = (new Definition(ScopingHttpClient::class))
|
||||
->setFactory([ScopingHttpClient::class, 'forBaseUri'])
|
||||
->setArguments([
|
||||
$httpClientReference,
|
||||
$platform['endpoint'],
|
||||
$defaultOptions,
|
||||
]);
|
||||
|
||||
$container->setDefinition('ai.platform.ollama.scoped_http_client', $scopedClientDefinition);
|
||||
|
||||
$httpClientReference = new Reference('ai.platform.ollama.scoped_http_client');
|
||||
}
|
||||
|
||||
if (\array_key_exists('api_catalog', $platform)) {
|
||||
$catalogDefinition = (new Definition(OllamaApiCatalog::class))
|
||||
->setLazy(true)
|
||||
->setArguments([
|
||||
$httpClientReference,
|
||||
])
|
||||
->addTag('proxy', ['interface' => ModelCatalogInterface::class])
|
||||
;
|
||||
|
||||
$container->setDefinition('ai.platform.model_catalog.ollama', $catalogDefinition);
|
||||
}
|
||||
|
||||
$definition = (new Definition(Platform::class))
|
||||
->setFactory(OllamaPlatformFactory::class.'::create')
|
||||
->setLazy(true)
|
||||
->setArguments([
|
||||
$platform['endpoint'],
|
||||
$platform['endpoint'] ?? null,
|
||||
$platform['api_key'] ?? null,
|
||||
$httpClientReference,
|
||||
new Reference('ai.platform.model_catalog.ollama'),
|
||||
new Reference($platform['http_client']),
|
||||
new Reference('ai.platform.contract.ollama'),
|
||||
new Reference('event_dispatcher'),
|
||||
])
|
||||
|
||||
@@ -38,8 +38,6 @@ use Symfony\AI\Platform\Bridge\ElevenLabs\ModelCatalog as ElevenLabsModelCatalog
|
||||
use Symfony\AI\Platform\Bridge\ElevenLabs\PlatformFactory as ElevenLabsPlatformFactory;
|
||||
use Symfony\AI\Platform\Bridge\Failover\FailoverPlatform;
|
||||
use Symfony\AI\Platform\Bridge\Failover\FailoverPlatformFactory;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\ModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\OllamaApiCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory as OllamaPlatformFactory;
|
||||
use Symfony\AI\Platform\Capability;
|
||||
use Symfony\AI\Platform\EventListener\TemplateRendererListener;
|
||||
@@ -3912,35 +3910,24 @@ class AiBundleTest extends TestCase
|
||||
]);
|
||||
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.ollama'));
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.ollama.scoped_http_client'));
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.model_catalog.ollama'));
|
||||
|
||||
$definition = $container->getDefinition('ai.platform.ollama');
|
||||
$this->assertSame([OllamaPlatformFactory::class, 'create'], $definition->getFactory());
|
||||
$this->assertTrue($definition->isLazy());
|
||||
|
||||
$this->assertCount(6, $definition->getArguments());
|
||||
$this->assertCount(5, $definition->getArguments());
|
||||
$this->assertSame('http://127.0.0.1:11434', $definition->getArgument(0));
|
||||
$this->assertNull($definition->getArgument(1));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(2));
|
||||
$this->assertSame('ai.platform.ollama.scoped_http_client', (string) $definition->getArgument(2));
|
||||
$this->assertSame('http_client', (string) $definition->getArgument(2));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(3));
|
||||
$this->assertSame('ai.platform.model_catalog.ollama', (string) $definition->getArgument(3));
|
||||
$this->assertSame('ai.platform.contract.ollama', (string) $definition->getArgument(3));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(4));
|
||||
$this->assertSame('ai.platform.contract.ollama', (string) $definition->getArgument(4));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(5));
|
||||
$this->assertSame('event_dispatcher', (string) $definition->getArgument(5));
|
||||
$this->assertSame('event_dispatcher', (string) $definition->getArgument(4));
|
||||
|
||||
$this->assertTrue($definition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => PlatformInterface::class]], $definition->getTag('proxy'));
|
||||
|
||||
$catalogDefinition = $container->getDefinition('ai.platform.model_catalog.ollama');
|
||||
$this->assertTrue($catalogDefinition->isLazy());
|
||||
$this->assertSame(ModelCatalog::class, $catalogDefinition->getClass());
|
||||
|
||||
$this->assertTrue($catalogDefinition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => ModelCatalogInterface::class]], $catalogDefinition->getTag('proxy'));
|
||||
|
||||
// Ollama.com usage (with API key)
|
||||
$container = $this->buildContainer([
|
||||
'ai' => [
|
||||
@@ -3954,35 +3941,24 @@ class AiBundleTest extends TestCase
|
||||
]);
|
||||
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.ollama'));
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.ollama.scoped_http_client'));
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.model_catalog.ollama'));
|
||||
|
||||
$definition = $container->getDefinition('ai.platform.ollama');
|
||||
$this->assertSame([OllamaPlatformFactory::class, 'create'], $definition->getFactory());
|
||||
$this->assertTrue($definition->isLazy());
|
||||
|
||||
$this->assertCount(6, $definition->getArguments());
|
||||
$this->assertCount(5, $definition->getArguments());
|
||||
$this->assertSame('https://ollama.com', $definition->getArgument(0));
|
||||
$this->assertSame('foo', $definition->getArgument(1));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(2));
|
||||
$this->assertSame('ai.platform.ollama.scoped_http_client', (string) $definition->getArgument(2));
|
||||
$this->assertSame('http_client', (string) $definition->getArgument(2));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(3));
|
||||
$this->assertSame('ai.platform.model_catalog.ollama', (string) $definition->getArgument(3));
|
||||
$this->assertSame('ai.platform.contract.ollama', (string) $definition->getArgument(3));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(4));
|
||||
$this->assertSame('ai.platform.contract.ollama', (string) $definition->getArgument(4));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(5));
|
||||
$this->assertSame('event_dispatcher', (string) $definition->getArgument(5));
|
||||
$this->assertSame('event_dispatcher', (string) $definition->getArgument(4));
|
||||
|
||||
$this->assertTrue($definition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => PlatformInterface::class]], $definition->getTag('proxy'));
|
||||
|
||||
$catalogDefinition = $container->getDefinition('ai.platform.model_catalog.ollama');
|
||||
$this->assertTrue($catalogDefinition->isLazy());
|
||||
$this->assertSame(ModelCatalog::class, $catalogDefinition->getClass());
|
||||
|
||||
$this->assertTrue($catalogDefinition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => ModelCatalogInterface::class]], $catalogDefinition->getTag('proxy'));
|
||||
|
||||
// Custom HTTPClient
|
||||
$container = $this->buildContainer([
|
||||
'ai' => [
|
||||
@@ -3995,82 +3971,23 @@ class AiBundleTest extends TestCase
|
||||
]);
|
||||
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.ollama'));
|
||||
$this->assertFalse($container->hasDefinition('ai.platform.ollama.scoped_http_client'));
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.model_catalog.ollama'));
|
||||
|
||||
$definition = $container->getDefinition('ai.platform.ollama');
|
||||
$this->assertSame([OllamaPlatformFactory::class, 'create'], $definition->getFactory());
|
||||
$this->assertTrue($definition->isLazy());
|
||||
|
||||
$this->assertCount(6, $definition->getArguments());
|
||||
$this->assertCount(5, $definition->getArguments());
|
||||
$this->assertNull($definition->getArgument(0));
|
||||
$this->assertNull($definition->getArgument(1));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(2));
|
||||
$this->assertSame('foo', (string) $definition->getArgument(2));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(3));
|
||||
$this->assertSame('ai.platform.model_catalog.ollama', (string) $definition->getArgument(3));
|
||||
$this->assertSame('ai.platform.contract.ollama', (string) $definition->getArgument(3));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(4));
|
||||
$this->assertSame('ai.platform.contract.ollama', (string) $definition->getArgument(4));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(5));
|
||||
$this->assertSame('event_dispatcher', (string) $definition->getArgument(5));
|
||||
$this->assertSame('event_dispatcher', (string) $definition->getArgument(4));
|
||||
|
||||
$this->assertTrue($definition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => PlatformInterface::class]], $definition->getTag('proxy'));
|
||||
|
||||
$catalogDefinition = $container->getDefinition('ai.platform.model_catalog.ollama');
|
||||
$this->assertTrue($catalogDefinition->isLazy());
|
||||
$this->assertSame(ModelCatalog::class, $catalogDefinition->getClass());
|
||||
|
||||
$this->assertTrue($catalogDefinition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => ModelCatalogInterface::class]], $catalogDefinition->getTag('proxy'));
|
||||
}
|
||||
|
||||
public function testOllamaCanBeCreatedWithCatalogFromApi()
|
||||
{
|
||||
$container = $this->buildContainer([
|
||||
'ai' => [
|
||||
'platform' => [
|
||||
'ollama' => [
|
||||
'endpoint' => 'http://127.0.0.1:11434',
|
||||
'api_catalog' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.ollama'));
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.ollama.scoped_http_client'));
|
||||
$this->assertTrue($container->hasDefinition('ai.platform.model_catalog.ollama'));
|
||||
|
||||
$definition = $container->getDefinition('ai.platform.ollama');
|
||||
$this->assertSame([OllamaPlatformFactory::class, 'create'], $definition->getFactory());
|
||||
$this->assertTrue($definition->isLazy());
|
||||
|
||||
$this->assertCount(6, $definition->getArguments());
|
||||
$this->assertSame('http://127.0.0.1:11434', $definition->getArgument(0));
|
||||
$this->assertNull($definition->getArgument(1));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(2));
|
||||
$this->assertSame('ai.platform.ollama.scoped_http_client', (string) $definition->getArgument(2));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(3));
|
||||
$this->assertSame('ai.platform.model_catalog.ollama', (string) $definition->getArgument(3));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(4));
|
||||
$this->assertSame('ai.platform.contract.ollama', (string) $definition->getArgument(4));
|
||||
$this->assertInstanceOf(Reference::class, $definition->getArgument(5));
|
||||
$this->assertSame('event_dispatcher', (string) $definition->getArgument(5));
|
||||
|
||||
$this->assertTrue($definition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => PlatformInterface::class]], $definition->getTag('proxy'));
|
||||
|
||||
$catalogDefinition = $container->getDefinition('ai.platform.model_catalog.ollama');
|
||||
|
||||
$this->assertTrue($catalogDefinition->isLazy());
|
||||
$this->assertSame(OllamaApiCatalog::class, $catalogDefinition->getClass());
|
||||
$this->assertCount(1, $catalogDefinition->getArguments());
|
||||
$this->assertInstanceOf(Reference::class, $catalogDefinition->getArgument(0));
|
||||
$this->assertSame('ai.platform.ollama.scoped_http_client', (string) $catalogDefinition->getArgument(0));
|
||||
|
||||
$this->assertTrue($catalogDefinition->hasTag('proxy'));
|
||||
$this->assertSame([['interface' => ModelCatalogInterface::class]], $catalogDefinition->getTag('proxy'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,9 @@ CHANGELOG
|
||||
---
|
||||
|
||||
* Add support for `structured_output` capability in `OllamaApiCatalog`
|
||||
* Replace `ModelCatalog` by `OllamaApiCatalog`
|
||||
* Rename `OllamaApiCatalog` to `ModelCatalog`
|
||||
* [BC BREAK] `Ollama` model is now `final`
|
||||
|
||||
0.4
|
||||
---
|
||||
|
||||
@@ -12,212 +12,72 @@
|
||||
namespace Symfony\AI\Platform\Bridge\Ollama;
|
||||
|
||||
use Symfony\AI\Platform\Capability;
|
||||
use Symfony\AI\Platform\Model;
|
||||
use Symfony\AI\Platform\ModelCatalog\AbstractModelCatalog;
|
||||
use Symfony\AI\Platform\Exception\InvalidArgumentException;
|
||||
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
/**
|
||||
* @author Oskar Stark <oskarstark@googlemail.com>
|
||||
* @author Guillaume Loulier <personal@guillaumeloulier.fr>
|
||||
*/
|
||||
final class ModelCatalog extends AbstractModelCatalog
|
||||
final class ModelCatalog implements ModelCatalogInterface
|
||||
{
|
||||
/**
|
||||
* @param array<string, array{class: class-string<Model>, capabilities: list<Capability>}> $additionalModels
|
||||
*/
|
||||
public function __construct(array $additionalModels = [])
|
||||
{
|
||||
$defaultModels = [
|
||||
'deepseek-r1' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'gpt-oss' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'llama3.1' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'llama3.2' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'llama3' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'mistral' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'qwen3' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'qwen' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'qwen2' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'qwen2.5' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'qwen2.5-coder' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
Capability::TOOL_CALLING,
|
||||
],
|
||||
],
|
||||
'gemma3n' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'gemma3' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'qwen2.5vl' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'llava' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'phi3' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'gemma2' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'gemma' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'llama2' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_MESSAGES,
|
||||
Capability::OUTPUT_TEXT,
|
||||
Capability::OUTPUT_STRUCTURED,
|
||||
],
|
||||
],
|
||||
'nomic-embed-text' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_TEXT,
|
||||
Capability::INPUT_MULTIPLE,
|
||||
Capability::EMBEDDINGS,
|
||||
],
|
||||
],
|
||||
'bge-m3' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_TEXT,
|
||||
Capability::INPUT_MULTIPLE,
|
||||
Capability::EMBEDDINGS,
|
||||
],
|
||||
],
|
||||
'all-minilm' => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => [
|
||||
Capability::INPUT_TEXT,
|
||||
Capability::INPUT_MULTIPLE,
|
||||
Capability::EMBEDDINGS,
|
||||
],
|
||||
],
|
||||
];
|
||||
public function __construct(
|
||||
private readonly HttpClientInterface $httpClient,
|
||||
) {
|
||||
}
|
||||
|
||||
$this->models = [
|
||||
...$defaultModels,
|
||||
...$additionalModels,
|
||||
];
|
||||
public function getModel(string $modelName): Ollama
|
||||
{
|
||||
$response = $this->httpClient->request('POST', '/api/show', [
|
||||
'json' => [
|
||||
'model' => $modelName,
|
||||
],
|
||||
]);
|
||||
|
||||
$payload = $response->toArray();
|
||||
|
||||
if ([] === $payload['capabilities']) {
|
||||
throw new InvalidArgumentException('The model information could not be retrieved from the Ollama API. Your Ollama server might be too old. Try upgrade it.');
|
||||
}
|
||||
|
||||
$capabilities = array_map(
|
||||
static fn (string $capability): Capability => match ($capability) {
|
||||
'embedding' => Capability::EMBEDDINGS,
|
||||
'completion' => Capability::INPUT_MESSAGES,
|
||||
'tools' => Capability::TOOL_CALLING,
|
||||
'thinking' => Capability::THINKING,
|
||||
'vision' => Capability::INPUT_IMAGE,
|
||||
default => throw new InvalidArgumentException(\sprintf('The "%s" capability is not supported', $capability)),
|
||||
},
|
||||
$payload['capabilities'],
|
||||
);
|
||||
|
||||
if (!\in_array(Capability::EMBEDDINGS, $capabilities, true)) {
|
||||
$capabilities[] = Capability::OUTPUT_STRUCTURED;
|
||||
}
|
||||
|
||||
return new Ollama($modelName, $capabilities);
|
||||
}
|
||||
|
||||
public function getModels(): array
|
||||
{
|
||||
$response = $this->httpClient->request('GET', '/api/tags');
|
||||
|
||||
$models = $response->toArray();
|
||||
|
||||
return array_merge(...array_map(
|
||||
function (array $model): array {
|
||||
$retrievedModel = $this->getModel($model['name']);
|
||||
|
||||
return [
|
||||
$retrievedModel->getName() => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => $retrievedModel->getCapabilities(),
|
||||
],
|
||||
];
|
||||
},
|
||||
$models['models'],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@ use Symfony\AI\Platform\Model;
|
||||
/**
|
||||
* @author Joshua Behrens <code@joshua-behrens.de>
|
||||
*/
|
||||
class Ollama extends Model
|
||||
final class Ollama extends Model
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\AI\Platform\Bridge\Ollama;
|
||||
|
||||
use Symfony\AI\Platform\Capability;
|
||||
use Symfony\AI\Platform\Exception\InvalidArgumentException;
|
||||
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
/**
|
||||
* @author Guillaume Loulier <personal@guillaumeloulier.fr>
|
||||
*/
|
||||
final class OllamaApiCatalog implements ModelCatalogInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly HttpClientInterface $httpClient,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getModel(string $modelName): Ollama
|
||||
{
|
||||
$response = $this->httpClient->request('POST', '/api/show', [
|
||||
'json' => [
|
||||
'model' => $modelName,
|
||||
],
|
||||
]);
|
||||
|
||||
$payload = $response->toArray();
|
||||
|
||||
if ([] === $payload['capabilities']) {
|
||||
throw new InvalidArgumentException('The model information could not be retrieved from the Ollama API. Your Ollama server might be too old. Try upgrade it.');
|
||||
}
|
||||
|
||||
$capabilities = array_map(
|
||||
static fn (string $capability): Capability => match ($capability) {
|
||||
'embedding' => Capability::EMBEDDINGS,
|
||||
'completion' => Capability::INPUT_MESSAGES,
|
||||
'tools' => Capability::TOOL_CALLING,
|
||||
'thinking' => Capability::THINKING,
|
||||
'vision' => Capability::INPUT_IMAGE,
|
||||
default => throw new InvalidArgumentException(\sprintf('The "%s" capability is not supported', $capability)),
|
||||
},
|
||||
$payload['capabilities'],
|
||||
);
|
||||
|
||||
if (!\in_array(Capability::EMBEDDINGS, $capabilities, true)) {
|
||||
$capabilities[] = Capability::OUTPUT_STRUCTURED;
|
||||
}
|
||||
|
||||
return new Ollama($modelName, $capabilities);
|
||||
}
|
||||
|
||||
public function getModels(): array
|
||||
{
|
||||
$response = $this->httpClient->request('GET', '/api/tags');
|
||||
|
||||
$models = $response->toArray();
|
||||
|
||||
return array_merge(...array_map(
|
||||
function (array $model): array {
|
||||
$retrievedModel = $this->getModel($model['name']);
|
||||
|
||||
return [
|
||||
$retrievedModel->getName() => [
|
||||
'class' => Ollama::class,
|
||||
'capabilities' => $retrievedModel->getCapabilities(),
|
||||
],
|
||||
];
|
||||
},
|
||||
$models['models'],
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ namespace Symfony\AI\Platform\Bridge\Ollama;
|
||||
|
||||
use Symfony\AI\Platform\Bridge\Ollama\Contract\OllamaContract;
|
||||
use Symfony\AI\Platform\Contract;
|
||||
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
|
||||
use Symfony\AI\Platform\Platform;
|
||||
use Symfony\Component\HttpClient\EventSourceHttpClient;
|
||||
use Symfony\Component\HttpClient\ScopingHttpClient;
|
||||
@@ -26,10 +25,9 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
final class PlatformFactory
|
||||
{
|
||||
public static function create(
|
||||
?string $endpoint = 'http://localhost:11434',
|
||||
?string $endpoint = null,
|
||||
#[\SensitiveParameter] ?string $apiKey = null,
|
||||
?HttpClientInterface $httpClient = null,
|
||||
ModelCatalogInterface $modelCatalog = new ModelCatalog(),
|
||||
?Contract $contract = null,
|
||||
?EventDispatcherInterface $eventDispatcher = null,
|
||||
): Platform {
|
||||
@@ -47,7 +45,7 @@ final class PlatformFactory
|
||||
return new Platform(
|
||||
[new OllamaClient($httpClient)],
|
||||
[new OllamaResultConverter()],
|
||||
$modelCatalog,
|
||||
new ModelCatalog($httpClient),
|
||||
$contract ?? OllamaContract::create(),
|
||||
$eventDispatcher,
|
||||
);
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\AI\Platform\Bridge\Ollama\Tests;
|
||||
|
||||
use Symfony\AI\Platform\Bridge\Ollama\ModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\Ollama;
|
||||
use Symfony\AI\Platform\Capability;
|
||||
use Symfony\AI\Platform\ModelCatalog\ModelCatalogInterface;
|
||||
use Symfony\AI\Platform\Test\ModelCatalogTestCase;
|
||||
|
||||
/**
|
||||
* @author Oskar Stark <oskarstark@googlemail.com>
|
||||
*/
|
||||
final class ModelCatalogTest extends ModelCatalogTestCase
|
||||
{
|
||||
public static function modelsProvider(): iterable
|
||||
{
|
||||
yield 'deepseek-r1' => ['deepseek-r1', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'gpt-oss' => ['gpt-oss', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'llama3.1' => ['llama3.1', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'llama3.2' => ['llama3.2', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'llama3' => ['llama3', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'mistral' => ['mistral', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'qwen3' => ['qwen3', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'qwen3:32b' => ['qwen3:32b', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'qwen' => ['qwen', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'qwen2' => ['qwen2', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'qwen2.5' => ['qwen2.5', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'qwen2.5-coder' => ['qwen2.5-coder', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED, Capability::TOOL_CALLING]];
|
||||
yield 'gemma3n' => ['gemma3n', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'gemma3' => ['gemma3', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'qwen2.5vl' => ['qwen2.5vl', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'llava' => ['llava', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'phi3' => ['phi3', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'gemma2' => ['gemma2', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'gemma' => ['gemma', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'llama2' => ['llama2', Ollama::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STRUCTURED]];
|
||||
yield 'nomic-embed-text' => ['nomic-embed-text', Ollama::class, [Capability::INPUT_TEXT, Capability::EMBEDDINGS, Capability::INPUT_MULTIPLE]];
|
||||
yield 'bge-m3' => ['bge-m3', Ollama::class, [Capability::INPUT_TEXT, Capability::EMBEDDINGS, Capability::INPUT_MULTIPLE]];
|
||||
yield 'all-minilm' => ['all-minilm', Ollama::class, [Capability::INPUT_TEXT, Capability::EMBEDDINGS, Capability::INPUT_MULTIPLE]];
|
||||
yield 'all-minilm:33m' => ['all-minilm:33m', Ollama::class, [Capability::INPUT_TEXT, Capability::EMBEDDINGS, Capability::INPUT_MULTIPLE]];
|
||||
}
|
||||
|
||||
protected function createModelCatalog(): ModelCatalogInterface
|
||||
{
|
||||
return new ModelCatalog();
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@
|
||||
namespace Symfony\AI\Platform\Bridge\Ollama\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\ModelCatalog;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\Ollama;
|
||||
use Symfony\AI\Platform\Bridge\Ollama\OllamaApiCatalog;
|
||||
use Symfony\AI\Platform\Capability;
|
||||
use Symfony\Component\HttpClient\MockHttpClient;
|
||||
use Symfony\Component\HttpClient\Response\JsonMockResponse;
|
||||
@@ -28,7 +28,7 @@ final class OllamaApiCatalogTest extends TestCase
|
||||
]),
|
||||
], 'http://127.0.0.1:11434');
|
||||
|
||||
$modelCatalog = new OllamaApiCatalog($httpClient);
|
||||
$modelCatalog = new ModelCatalog($httpClient);
|
||||
|
||||
$model = $modelCatalog->getModel('foo');
|
||||
|
||||
@@ -56,7 +56,7 @@ final class OllamaApiCatalogTest extends TestCase
|
||||
]),
|
||||
], 'http://127.0.0.1:11434');
|
||||
|
||||
$modelCatalog = new OllamaApiCatalog($httpClient);
|
||||
$modelCatalog = new ModelCatalog($httpClient);
|
||||
|
||||
$models = $modelCatalog->getModels();
|
||||
|
||||
@@ -88,7 +88,7 @@ final class OllamaApiCatalogTest extends TestCase
|
||||
]),
|
||||
], 'http://127.0.0.1:11434');
|
||||
|
||||
$modelCatalog = new OllamaApiCatalog($httpClient);
|
||||
$modelCatalog = new ModelCatalog($httpClient);
|
||||
|
||||
$models = $modelCatalog->getModels();
|
||||
|
||||
|
||||
@@ -93,6 +93,9 @@ final class OllamaClientTest extends TestCase
|
||||
public function testStreamingIsSupported()
|
||||
{
|
||||
$httpClient = new MockHttpClient([
|
||||
new JsonMockResponse([
|
||||
'capabilities' => ['completion'],
|
||||
]),
|
||||
new MockResponse('data: '.json_encode([
|
||||
'model' => 'llama3.2',
|
||||
'created_at' => '2025-08-23T10:00:00Z',
|
||||
@@ -124,7 +127,7 @@ final class OllamaClientTest extends TestCase
|
||||
|
||||
$this->assertInstanceOf(StreamResult::class, $result);
|
||||
$this->assertInstanceOf(\Generator::class, $result->getContent());
|
||||
$this->assertSame(1, $httpClient->getRequestsCount());
|
||||
$this->assertSame(2, $httpClient->getRequestsCount());
|
||||
}
|
||||
|
||||
public function testStreamingConverterWithDirectResponse()
|
||||
|
||||
Reference in New Issue
Block a user