-
The
SimilaritySearch::$usedDocumentsproperty is no longer public. UsegetUsedDocuments()instead:-$usedDocuments = $similaritySearch->usedDocuments; +$usedDocuments = $similaritySearch->getUsedDocuments();
-
The
public array $callsproperty ofTraceableAgentandTraceableToolboxhas been changed toprivate. Use the newgetCalls()method instead:-$traceableAgent->calls; +$traceableAgent->getCalls(); -$traceableToolbox->calls; +$traceableToolbox->getCalls();
-
The constructors of
StaticMemoryProviderandToolCallsExecutedno longer accept variadic parameters. Pass an array instead:-new StaticMemoryProvider('fact1', 'fact2'); +new StaticMemoryProvider(['fact1', 'fact2']); -new StaticMemoryProvider('fact1'); +new StaticMemoryProvider(['fact1']); -new ToolCallsExecuted($toolResult1, $toolResult2); +new ToolCallsExecuted([$toolResult1, $toolResult2]); -new ToolCallsExecuted($toolResult1); +new ToolCallsExecuted([$toolResult1]);
-
The service ID
ai.agent.response_format_factoryhas been renamed toai.platform.response_format_factory:-$container->get('ai.agent.response_format_factory'); +$container->get('ai.platform.response_format_factory');
-
The
public array $callsproperty ofTraceableChatandTraceableMessageStorehas been changed toprivate. Use the newgetCalls()method instead:-$traceableChat->calls; +$traceableChat->getCalls(); -$traceableMessageStore->calls; +$traceableMessageStore->getCalls();
-
The
#[With]attribute has been renamed to#[Schema]. TheWithAttributeDescriberclass has been renamed toSchemaAttributeDescriberand the related service idai.platform.json_schema.describer.with_attributetoai.platform.json_schema.describer.schema_attribute.-use Symfony\AI\Platform\Contract\JsonSchema\Attribute\With; +use Symfony\AI\Platform\Contract\JsonSchema\Attribute\Schema; -#[With(minimum: 0, maximum: 10)] +#[Schema(minimum: 0, maximum: 10)] int $number,
-
The
ImageResult::$revisedPromptproperty is no longer public. UsegetRevisedPrompt()instead:-$revisedPrompt = $imageResult->revisedPrompt; +$revisedPrompt = $imageResult->getRevisedPrompt();
-
The
public array $callsproperty andpublic \WeakMap $resultCacheproperty ofTraceablePlatformhave been changed toprivate. Use the newgetCalls()andgetResultCache()methods instead:-$traceablePlatform->calls; +$traceablePlatform->getCalls(); -$traceablePlatform->resultCache; +$traceablePlatform->getResultCache();
-
The constructors of
VectorResult,ToolCallResult,RerankingResult,ToolCallComplete, andImageResult(OpenAI DallE bridge) no longer accept variadic parameters. Pass an array instead:-new VectorResult($vector1, $vector2); +new VectorResult([$vector1, $vector2]); -new ToolCallResult($toolCall1, $toolCall2); +new ToolCallResult([$toolCall1, $toolCall2]); -new RerankingResult($entry1, $entry2); +new RerankingResult([$entry1, $entry2]); -new ToolCallComplete($toolCall1, $toolCall2); +new ToolCallComplete([$toolCall1, $toolCall2]); -new ImageResult(null, $image1, $image2); +new ImageResult(null, [$image1, $image2]);
-
Properties of all HuggingFace Output classes have been changed from public to private readonly. Use getter methods instead:
-$classification->label; -$classification->score; +$classification->getLabel(); +$classification->getScore();
Affected classes:
Classification,ClassificationResult,DetectedObject,FillMaskResult,ImageSegment,ImageSegmentationResult,MaskFill,ObjectDetectionResult,QuestionAnsweringResult,SentenceSimilarityResult,TableQuestionAnsweringResult,Token,TokenClassificationResult,ZeroShotClassificationResult. -
The
Contract::create()factory method and all bridge-specificContract::create()methods no longer accept variadicNormalizerInterfacearguments. Pass an array instead:-Contract::create(new MyNormalizer(), new AnotherNormalizer()); +Contract::create([new MyNormalizer(), new AnotherNormalizer()]); -AnthropicContract::create(new MyNormalizer()); +AnthropicContract::create([new MyNormalizer()]);
This affects the following classes:
Contract,AnthropicContract,CartesiaContract,ClaudeCodeContract,CodexContract,DecartContract,ElevenLabsContract,GeminiContract(Gemini and VertexAi bridges),HuggingFaceContract,OllamaContract,OpenAiContract,OpenResponsesContract,PerplexityContract,VoyageContract.
-
The
public array $callsproperty ofTraceableStorehas been changed toprivate. Use the newgetCalls()method instead:-$traceableStore->calls; +$traceableStore->getCalls();
-
The
Symfony\AI\Agent\Toolbox\ToolFactory\AbstractToolFactoryclass has been removed. If you extended it to create a custom tool factory, implementToolFactoryInterfaceyourself and useSymfony\AI\Platform\Contract\JsonSchema\Factorydirectly if needed. -
The
ToolFactoryInterface::getTool()method signature has changed to acceptobject|stringinstead ofstring:-public function getTool(string $reference): iterable; +public function getTool(object|string $reference): iterable;
-
The
SimilaritySearchtool now requires aRetrieverInterfaceinstead ofVectorizerInterfaceandStoreInterface:-use Symfony\AI\Store\Document\VectorizerInterface; -use Symfony\AI\Store\StoreInterface; +use Symfony\AI\Store\Retriever; -$similaritySearch = new SimilaritySearch($vectorizer, $store); +$retriever = new Retriever($store, $vectorizer); +$similaritySearch = new SimilaritySearch($retriever);
-
The
SimilaritySearchtool now accepts an optional$promptTemplateparameter to customize the result header (default:'Found documents with the following information:') -
Toolbox\StreamListener::onChunk()has been renamed toonDelta(). The listener now checks$delta instanceof TextDeltainstead ofis_string($chunk)to accumulate the assistant text buffer. -
The
StreamListenernow reacts toToolCallCompleteinstead ofToolCallResult. If you have a customStreamListeneror check forToolCallResultin stream consumers, update toToolCallComplete.
-
The traceable profiler decorators have been moved to their respective components. Update your imports if you reference them directly:
-use Symfony\AI\AiBundle\Profiler\TraceablePlatform; +use Symfony\AI\Platform\TraceablePlatform; -use Symfony\AI\AiBundle\Profiler\TraceableAgent; +use Symfony\AI\Agent\TraceableAgent; -use Symfony\AI\AiBundle\Profiler\TraceableToolbox; +use Symfony\AI\Agent\Toolbox\TraceableToolbox; -use Symfony\AI\AiBundle\Profiler\TraceableStore; +use Symfony\AI\Store\TraceableStore; -use Symfony\AI\AiBundle\Profiler\TraceableChat; +use Symfony\AI\Chat\TraceableChat; -use Symfony\AI\AiBundle\Profiler\TraceableMessageStore; +use Symfony\AI\Chat\TraceableMessageStore;
-
The
api_catalogoption forOllamahas been removed as the catalog is now automatically fetched from the Ollama server -
The
api_keyoption forOllamais nownullby default to allow the usage of aScopingHttpClient -
The
endpointoption forOllamais nownullby default to allow the usage of aScopingHttpClient -
The
strategyoption forCachestore is nowcosineby default -
The
DistanceCalculatoris no longer a service when usingCachestore
- The
ChatInterfacenow has astream()method. If you implement this interface, you need to add this method to your implementation.
- Run
vendor/bin/mate discoverto update the generatedAGENT_INSTRUCTIONS.mdfile with the latest tool descriptions and agent instructions.
-
ModelCataloginOllamahas been replaced byOllamaApiCatalog -
OllamaApiCataloginOllamahas been renamed toModelCatalog -
Ollamamodel is nowfinal -
ModelCataloginElevenLabshas been replaced byElevenLabsApiCatalog -
ElevenLabsApiCataloginElevenLabshas been renamed toModelCatalog -
ChunkEventhas been replaced byDeltaEvent. TheonChunk(ChunkEvent)method onListenerInterfaceis nowonDelta(DeltaEvent). Update all implementations:onChunk(ChunkEvent $event)→onDelta(DeltaEvent $event)$event->getChunk()→$event->getDelta()$event->setChunk(...)→$event->setDelta(...)$event->skipChunk()→$event->skipDelta()$event->isChunkSkipped()→$event->isDeltaSkipped()
-
Stream generators in bridge
ResultConverterclasses now yield typedDeltaInterfaceobjects instead of raw strings. Consumers iteratingStreamResult::getContent()that expectstringchunks must check forTextDeltainstead:is_string($chunk)→$chunk instanceof TextDelta, then use$chunk->getText()
-
New streaming delta types in
Symfony\AI\Platform\Result\Stream\Delta\:TextDelta,ThinkingDelta,ThinkingSignature,ThinkingStart,ToolCallStart,ToolInputDelta,BinaryDelta,ChoiceDelta,ToolCallComplete,ThinkingComplete. These are yielded by bridge converters during streaming. -
Symfony\AI\Platform\Bridge\Ollama\OllamaMessageChunkhas been removed. Ollama streams now yield semantic deltas like the other bridges:- text content →
TextDelta - thinking content →
ThinkingDelta - completed tool calls →
ToolCallComplete - final usage →
TokenUsage
-if ($chunk instanceof OllamaMessageChunk) { - echo $chunk->getContent(); -} +if ($chunk instanceof TextDelta) { + echo $chunk->getText(); +}
- text content →
-
Symfony\AI\Platform\Bridge\Perplexity\PerplexitySearchResults,Symfony\AI\Platform\Bridge\Perplexity\PerplexityCitations, andSymfony\AI\Platform\Bridge\Perplexity\StreamListenerhave been removed. Perplexity now emits genericMetadataDeltainstances internally, which are promoted to result metadata during stream consumption.If you relied on those deltas directly, read metadata instead:
-if ($delta instanceof PerplexitySearchResults) { - $results = $delta->getSearchResults(); -} -if ($delta instanceof PerplexityCitations) { - $citations = $delta->getCitations(); -} +$results = $result->getMetadata()->get('search_results'); +$citations = $result->getMetadata()->get('citations');
-
BinaryResult,ChoiceResult,ToolCallResult, andThinkingContentno longer implementDeltaInterface. Stream generators now yield proper delta types instead of result objects:ToolCallResult→ToolCallComplete: use$delta instanceof ToolCallCompleteand$delta->getToolCalls().ThinkingContent→ThinkingComplete: use$delta instanceof ThinkingCompleteand$delta->getThinking()/$delta->getSignature().BinaryResult→BinaryDelta: use$delta instanceof BinaryDeltaand$delta->getData()/$delta->getMimeType().ChoiceResult→ChoiceDelta: use$delta instanceof ChoiceDeltaand$delta->getDeltas().
-
ThinkingContenthas been removed in favor ofThinkingComplete. -
The
Usagedelta class has been removed. Bridges now yieldTokenUsageobjects directly in streams instead.
-
The
Retrieverconstructor has a new?EventDispatcherInterface $eventDispatcherparameter inserted as 3rd argument beforeLoggerInterface $logger. If you pass$loggerpositionally, update to use a named argument:-$retriever = new Retriever($store, $vectorizer, $logger); +$retriever = new Retriever($store, $vectorizer, logger: $logger);
-
Add support for
ScopingHttpClientinAzureSearchStore -
The
endpointUrlparameter forAzureSearchStorehas been removed -
The
apiKeyparameter forAzureSearchStorehas been removed -
The
apiVersionparameter forAzureSearchStorehas been removed -
A
StoreFactoryhas been introduced forAzureSearchStore -
The
endpointUrlparameter for WeaviateStorehas been removed -
The
apiKeyparameter for WeaviateStorehas been removed -
A
StoreFactoryhas been introduced forCache
- The
api_keyoption forElevenLabsis not required anymore if aScopedHttpClientis used inhttp_clientoption
- The
PlatformFactoryis now in charge of creatingElevenLabsApiCatalogifapiCatalogis provided astrue Symfony\AI\Platform\TokenUsage\TokenUsageInterfacehas two new methods:getCacheCreationTokens()andgetCacheReadTokens()
- The
hostUrlparameter forElevenLabsClienthas been removed - The
hostparameter forElevenLabsApiCataloghas been removed - The
hostUrlparameter forPlatformFactory::create()inElevenLabshas been renamed toendpoint
-
The
keepToolMessagesparameter ofAgentProcessorhas been removed and replaced withexcludeToolMessages. Tool messages (AssistantMessagewith tool call invocations andToolCallMessagewith tool call results) are now preserved in theMessageBagby default.If you were opting in to keep tool messages, just remove the parameter:
-$processor = new AgentProcessor($toolbox, keepToolMessages: true); +$processor = new AgentProcessor($toolbox);
If you were explicitly discarding tool messages, use the new parameter:
-$processor = new AgentProcessor($toolbox, keepToolMessages: false); +$processor = new AgentProcessor($toolbox, excludeToolMessages: true);
If you were relying on the previous default (tool messages discarded), opt in explicitly:
-$processor = new AgentProcessor($toolbox); +$processor = new AgentProcessor($toolbox, excludeToolMessages: true);
-
The
Symfony\AI\Agent\Toolbox\Tool\Agentclass has been renamed toSymfony\AI\Agent\Toolbox\Tool\Subagent:-use Symfony\AI\Agent\Toolbox\Tool\Agent; +use Symfony\AI\Agent\Toolbox\Tool\Subagent; -$agentTool = new Agent($agent); +$subagent = new Subagent($agent);
-
The service ID prefix for agent tools wrapping sub-agents has changed from
ai.toolbox.{agent}.agent_wrapper.toai.toolbox.{agent}.subagent.:-$container->get('ai.toolbox.my_agent.agent_wrapper.research_agent'); +$container->get('ai.toolbox.my_agent.subagent.research_agent');
-
An indexer configured with a
source, now wraps the indexer with aSymfony\AI\Store\Indexer\ConfiguredSourceIndexerdecorator. This is transparent - the configured source is still used by default, but can be overridden by passing a source toindex(). -
The
host_urlparameter forOllamaplatform has been renamedendpoint.
- The
hostUrlparameter forOllamaClienthas been removed - The
hostparameter forOllamaApiCataloghas been removed - The
hostUrlparameter forPlatformFactory::create()inOllamahas been renamed toendpoint
-
The
Symfony\AI\Store\Indexerclass has been replaced with two specialized implementations:Symfony\AI\Store\Indexer\SourceIndexer: For indexing from sources (file paths, URLs, etc.) using aLoaderInterfaceSymfony\AI\Store\Indexer\DocumentIndexer: For indexing documents directly without a loader
-use Symfony\AI\Store\Indexer; +use Symfony\AI\Store\Indexer\SourceIndexer; -$indexer = new Indexer($loader, $vectorizer, $store, '/path/to/source'); -$indexer->index(); +$indexer = new SourceIndexer($loader, $vectorizer, $store); +$indexer->index('/path/to/file');
For indexing documents directly:
use Symfony\AI\Store\Document\TextDocument; use Symfony\AI\Store\Indexer\DocumentIndexer; $indexer = new DocumentIndexer($processor); $indexer->index(new TextDocument($id, 'content')); $indexer->index([$document1, $document2]);
-
The
Symfony\AI\Store\ConfiguredIndexerclass has been renamed toSymfony\AI\Store\Indexer\ConfiguredSourceIndexer:-use Symfony\AI\Store\ConfiguredIndexer; +use Symfony\AI\Store\Indexer\ConfiguredSourceIndexer; -$indexer = new ConfiguredIndexer($innerIndexer, 'default-source'); +$indexer = new ConfiguredSourceIndexer($sourceIndexer, 'default-source');
-
The
Symfony\AI\Store\IndexerInterface::index()method signature has changed - the input parameter is no longer nullable:-public function index(string|iterable|null $source = null, array $options = []): void; +public function index(string|iterable|object $input, array $options = []): void;
-
The
Symfony\AI\Store\IndexerInterface::withSource()method has been removed. Use the$sourceparameter ofindex()instead:-$indexer->withSource('/new/source')->index(); +$indexer->index('/new/source');
-
The
Symfony\AI\Store\Document\TextDocumentandSymfony\AI\Store\Document\VectorDocumentclasses now only acceptstringorinttypes for the$idproperty. TheUuidtype has been removed and auto-casting touuidin store bridges has been removed as well:use Symfony\AI\Store\Document\TextDocument; use Symfony\AI\Store\Document\VectorDocument; use Symfony\Component\Uid\Uuid; -$textDoc = new TextDocument(Uuid::v4(), 'content'); +$textDoc = new TextDocument(Uuid::v4()->toString(), 'content'); -$vectorDoc = new VectorDocument(Uuid::v4(), [0.1, ...]); +$vectorDoc = new VectorDocument(Uuid::v4()->toString(), [0.1, ...]);
-
The
Symfony\AI\Store\Document\EmbeddableDocumentInterface::getId()can only returnstringorinttypes now. -
Properties of
Symfony\AI\Store\Document\VectorDocumentandSymfony\AI\Store\Document\Loader\Rss\RssItemhave been changed to private, use getters instead of public properties:-$document->id; -$document->metadata; -$document->score; -$document->vector; +$document->getId(); +$document->getMetadata(); +$document->getScore(); +$document->getVector();
-
The
StoreInterface::query()method signature has changed to accept aQueryInterfaceinstead of aVector:-use Symfony\AI\Platform\Vector\Vector; +use Symfony\AI\Store\Query\VectorQuery; -$results = $store->query($vector, ['limit' => 10]); +$results = $store->query(new VectorQuery($vector), ['limit' => 10]);
The Store component now supports multiple query types through a query abstraction system. Available query types:
VectorQuery: For vector similarity search (replaces the oldVectorparameter)TextQuery: For full-text search (when supported by the store)HybridQuery: For combined vector + text search (when supported by the store)
Check if a store supports a specific query type using the new
supports()method:if ($store->supports(VectorQuery::class)) { $results = $store->query(new VectorQuery($vector)); }
-
The
Symfony\AI\Store\Retrieverconstructor signature has changed - the first two arguments have been swapped:-use Symfony\AI\Store\Retriever; - -$retriever = new Retriever($vectorizer, $store, $logger); +$retriever = new Retriever($store, $vectorizer, $logger);
This change aligns the constructor with the primary dependency (the store) being first, followed by the optional vectorizer.
- The
Symfony\AI\Agent\Toolbox\StreamResultclass has been removed in favor of aStreamListener. Checks should now targetSymfony\AI\Platform\Result\StreamResultinstead. - The
Symfony\AI\Agent\Toolbox\Source\SourceMapclass has been renamed toSourceCollection. Its methods have also been renamed:getSources()is nowall()addSource()is nowadd()
- The third argument of the
Symfony\AI\Agent\Toolbox\ToolResult::__construct()method now expects aSourceCollectioninstead of anarray<int, Source>
-
The
TokenUsageAggregation::__construct()method signature has changed from variadic to accept an array ofTokenUsageInterface-$aggregation = new TokenUsageAggregation($usage1, $usage2); +$aggregation = new TokenUsageAggregation([$usage1, $usage2]);
-
The
Symfony\AI\Platform\CachedPlatformhas been renamedSymfony\AI\Platform\Bridge\Cache\CachePlatform- To use it, consider the following steps:
- Run
composer require symfony/ai-cache-platform - Change
Symfony\AI\Platform\CachedPlatformnamespace usages toSymfony\AI\Platform\Bridge\Cache\CachePlatform - The
ttloption can be used in the configuration
- Run
- To use it, consider the following steps:
-
Adopt usage of class
Symfony\AI\Platform\Serializer\StructuredOutputSerializertoSymfony\AI\Platform\StructuredOutput\Serializer
-
Agents are now injected using their configuration name directly, instead of appending Agent or MultiAgent
public function __construct( - private AgentInterface $blogAgent, + private AgentInterface $blog, - private AgentInterface $supportMultiAgent, + private AgentInterface $support, ) {}
-
Constructor of
MemoryInputProcessornow accepts an iterable of inputs instead of variadic arguments.use Symfony\AI\Agent\Memory\MemoryInputProcessor; // Before $processor = new MemoryInputProcessor($input1, $input2); // After $processor = new MemoryInputProcessor([$input1, $input2]);
-
The
ChoiceResult::__construct()method signature has changed from variadic to accept an array ofResultInterfaceuse Symfony\AI\Platform\Result\ChoiceResult; // Before $choiceResult = new ChoiceResult($result1, $result2); // After $choiceResult = new ChoiceResult([$result1, $result2]);
-
The
StoreInterface::remove()method was added to the interfacepublic function remove(string|array $ids, array $options = []): void; // Usage $store->remove('vector-id-1'); $store->remove(['vid-1', 'vid-2']);
-
The
StoreInterface::add()method signature has changed from variadic to accept a single document or an arrayBefore:
public function add(VectorDocument ...$documents): void; // Usage $store->add($document1, $document2); $store->add(...$documents);
After:
public function add(VectorDocument|array $documents): void; // Usage $store->add($document); $store->add([$document1, $document2]); $store->add($documents);