Skip to content

Commit 9c0fad4

Browse files
committed
ref
1 parent 6670c18 commit 9c0fad4

File tree

13 files changed

+231
-57
lines changed

13 files changed

+231
-57
lines changed

docs/bundles/ai-bundle.rst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,48 @@ The profiler panel provides insights into the agent's execution:
956956
.. image:: profiler.png
957957
:alt: Profiler Panel
958958

959+
Message stores
960+
--------------
961+
962+
Message stores are critical to store messages sent to agents in the short / long term, they can be configured
963+
and reused in multiple chats, providing the capacity to agents to keep previous interactions.
964+
965+
Configuring message stores
966+
~~~~~~~~~~~~~~~~~~~~~~~~~~
967+
968+
Message stores are defined in the ``message_store`` section of your configuration:
969+
970+
.. code-block:: yaml
971+
972+
ai:
973+
# ...
974+
message_store:
975+
youtube:
976+
cache:
977+
service: 'cache.app'
978+
key: 'youtube'
979+
980+
Chats
981+
-----
982+
983+
Chats are the entrypoint when it comes to sending messages to agents and retrieving content (mostly text)
984+
that contains the response from the agent.
985+
986+
Each chat requires to define an agent and a message store.
987+
988+
Configuring Chats
989+
~~~~~~~~~~~~~~~~~
990+
991+
Chats are defined in the ``chat`` section of your configuration:
992+
993+
.. code-block:: yaml
994+
995+
ai:
996+
# ...
997+
chat:
998+
youtube:
999+
agent: 'ai.agent.youtube'
1000+
message_store: 'ai.message_store.cache.youtube'
9591001
9601002
.. _`Symfony AI Agent`: https://github.com/symfony/ai-agent
9611003
.. _`Symfony AI Chat`: https://github.com/symfony/ai-chat

src/ai-bundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ CHANGELOG
3333
- Automatic registration of token output processors for Mistral, OpenAI and Vertex AI
3434
- Token usage metadata in agent results including prompt, completion, total, cached, and thinking tokens
3535
- Rate limit information tracking for supported platforms
36+
* Add support for configuring chats and message stores

src/ai-bundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"symfony/ai-chat": "@dev",
2020
"symfony/ai-platform": "@dev",
2121
"symfony/ai-store": "@dev",
22+
"symfony/clock": "^7.3|^8.0",
2223
"symfony/config": "^7.3|^8.0",
2324
"symfony/console": "^7.3|^8.0",
2425
"symfony/dependency-injection": "^7.3|^8.0",
@@ -30,7 +31,6 @@
3031
"phpstan/phpstan": "^2.1",
3132
"phpstan/phpstan-strict-rules": "^2.0",
3233
"phpunit/phpunit": "^11.5",
33-
"symfony/clock": "^7.3|^8.0",
3434
"symfony/expression-language": "^7.3|^8.0",
3535
"symfony/security-core": "^7.3|^8.0",
3636
"symfony/translation": "^7.3|^8.0"

src/ai-bundle/config/services.php

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
use Symfony\AI\AiBundle\Command\AgentCallCommand;
2424
use Symfony\AI\AiBundle\Command\PlatformInvokeCommand;
2525
use Symfony\AI\AiBundle\Profiler\DataCollector;
26-
use Symfony\AI\AiBundle\Profiler\TraceableChat;
27-
use Symfony\AI\AiBundle\Profiler\TraceableMessageStore;
28-
use Symfony\AI\AiBundle\Profiler\TraceableToolbox;
2926
use Symfony\AI\AiBundle\Security\EventListener\IsGrantedToolAttributeListener;
3027
use Symfony\AI\Chat\Command\DropStoreCommand as DropMessageStoreCommand;
3128
use Symfony\AI\Chat\Command\SetupStoreCommand as SetupMessageStoreCommand;
@@ -174,24 +171,6 @@
174171
tagged_iterator('ai.traceable_chat'),
175172
])
176173
->tag('data_collector')
177-
->set('ai.traceable_toolbox', TraceableToolbox::class)
178-
->decorate('ai.toolbox', priority: -1)
179-
->args([
180-
service('.inner'),
181-
])
182-
->tag('ai.traceable_toolbox')
183-
->set('ai.traceable_message_store', TraceableMessageStore::class)
184-
->decorate('ai.message_store')
185-
->args([
186-
service('.inner'),
187-
])
188-
->tag('ai.traceable_message_store')
189-
->set('ai.traceable_chat', TraceableChat::class)
190-
->decorate('ai.chat')
191-
->args([
192-
service('.inner'),
193-
])
194-
->tag('ai.traceable_chat')
195174

196175
// token usage processors
197176
->set('ai.platform.token_usage_processor.anthropic', AnthropicTokenOutputProcessor::class)

src/ai-bundle/src/AiBundle.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,10 @@ public function loadExtension(array $config, ContainerConfigurator $container, C
187187
foreach ($messageStores as $messageStore) {
188188
$traceableMessageStoreDefinition = (new Definition(TraceableMessageStore::class))
189189
->setDecoratedService($messageStore)
190-
->setArguments([new Reference('.inner')])
190+
->setArguments([
191+
new Reference('.inner'),
192+
new Reference(ClockInterface::class),
193+
])
191194
->addTag('ai.traceable_message_store');
192195
$suffix = u($messageStore)->afterLast('.')->toString();
193196
$builder->setDefinition('ai.traceable_message_store.'.$suffix, $traceableMessageStoreDefinition);
@@ -213,7 +216,10 @@ public function loadExtension(array $config, ContainerConfigurator $container, C
213216
foreach ($chats as $chat) {
214217
$traceableChatDefinition = (new Definition(TraceableChat::class))
215218
->setDecoratedService($chat)
216-
->setArguments([new Reference('.inner')])
219+
->setArguments([
220+
new Reference('.inner'),
221+
new Reference(ClockInterface::class),
222+
])
217223
->addTag('ai.traceable_chat');
218224
$suffix = u($chat)->afterLast('.')->toString();
219225
$builder->setDefinition('ai.traceable_chat.'.$suffix, $traceableChatDefinition);
@@ -1434,8 +1440,8 @@ private function processChatConfig(string $name, array $configuration, Container
14341440
$definition = new Definition(Chat::class);
14351441
$definition
14361442
->setArguments([
1437-
new Reference('ai.agent.'.$configuration['agent']),
1438-
new Reference('ai.message_store.'.$configuration['message_store']),
1443+
new Reference($configuration['agent']),
1444+
new Reference($configuration['message_store']),
14391445
])
14401446
->addTag('ai.chat');
14411447

src/ai-bundle/src/Profiler/DataCollector.php

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use Symfony\AI\Agent\Toolbox\ToolResult;
1515
use Symfony\AI\Platform\Metadata\Metadata;
16-
use Symfony\AI\Agent\Toolbox\ToolboxInterface;
1716
use Symfony\AI\Platform\Tool\Tool;
1817
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
1918
use Symfony\Component\HttpFoundation\Request;
@@ -26,6 +25,7 @@
2625
* @phpstan-import-type PlatformCallData from TraceablePlatform
2726
* @phpstan-import-type ToolCallData from TraceableToolbox
2827
* @phpstan-import-type MessageStoreData from TraceableMessageStore
28+
* @phpstan-import-type ChatData from TraceableChat
2929
*/
3030
final class DataCollector extends AbstractDataCollector implements LateDataCollectorInterface
3131
{
@@ -50,10 +50,10 @@ final class DataCollector extends AbstractDataCollector implements LateDataColle
5050
private readonly array $chats;
5151

5252
/**
53-
* @param TraceablePlatform[] $platforms
54-
* @param TraceableToolbox[] $toolboxes
53+
* @param TraceablePlatform[] $platforms
54+
* @param TraceableToolbox[] $toolboxes
5555
* @param TraceableMessageStore[] $messageStores
56-
* @param TraceableChat[] $chats
56+
* @param TraceableChat[] $chats
5757
*/
5858
public function __construct(
5959
iterable $platforms,
@@ -79,6 +79,7 @@ public function lateCollect(): void
7979
'platform_calls' => array_merge(...array_map($this->awaitCallResults(...), $this->platforms)),
8080
'tool_calls' => array_merge(...array_map(fn (TraceableToolbox $toolbox) => $toolbox->calls, $this->toolboxes)),
8181
'messages' => array_merge(...array_map(static fn (TraceableMessageStore $messageStore): array => $messageStore->calls, $this->messageStores)),
82+
'chats' => array_merge(...array_map(static fn (TraceableChat $chat): array => $chat->calls, $this->chats)),
8283
];
8384
}
8485

@@ -112,19 +113,27 @@ public function getToolCalls(): array
112113
}
113114

114115
/**
115-
* @return Tool[]
116+
* @return MessageStoreData[]
116117
*/
117-
private function getAllTools(): array
118+
public function getMessages(): array
118119
{
119-
return array_merge(...array_map(fn (TraceableToolbox $toolbox) => $toolbox->getTools(), $this->toolboxes));
120+
return $this->data['messages'] ?? [];
120121
}
121122

122123
/**
123-
* @return MessageStoreData[]
124+
* @return ChatData[]
124125
*/
125-
public function getMessages(): array
126+
public function getChats(): array
126127
{
127-
return $this->data['messages'] ?? [];
128+
return $this->data['chats'] ?? [];
129+
}
130+
131+
/**
132+
* @return Tool[]
133+
*/
134+
private function getAllTools(): array
135+
{
136+
return array_merge(...array_map(fn (TraceableToolbox $toolbox) => $toolbox->getTools(), $this->toolboxes));
128137
}
129138

130139
/**

src/ai-bundle/src/Profiler/TraceableChat.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,46 @@
1515
use Symfony\AI\Platform\Message\AssistantMessage;
1616
use Symfony\AI\Platform\Message\MessageBag;
1717
use Symfony\AI\Platform\Message\UserMessage;
18+
use Symfony\Component\Clock\ClockInterface;
1819

1920
/**
2021
* @author Guillaume Loulier <personal@guillaumeloulier.fr>
2122
*
22-
* @phpstan-type MessageStoreData array{
23+
* @phpstan-type ChatData array{
24+
* action: string,
2325
* bag: MessageBag,
26+
* saved_at: \DateTimeImmutable,
2427
* }
2528
*/
2629
final class TraceableChat implements ChatInterface
2730
{
28-
/**
29-
* @var array
30-
*/
3131
public array $calls = [];
3232

3333
public function __construct(
3434
private readonly ChatInterface $chat,
35+
private readonly ClockInterface $clock,
3536
) {
3637
}
3738

3839
public function initiate(MessageBag $messages): void
3940
{
40-
// TODO: Implement initiate() method.
41+
$this->calls[] = [
42+
'action' => __FUNCTION__,
43+
'bag' => $messages,
44+
'saved_at' => $this->clock->now(),
45+
];
46+
47+
$this->chat->initiate($messages);
4148
}
4249

4350
public function submit(UserMessage $message): AssistantMessage
4451
{
45-
// TODO: Implement submit() method.
52+
$this->calls[] = [
53+
'action' => __FUNCTION__,
54+
'message' => $message,
55+
'saved_at' => $this->clock->now(),
56+
];
57+
58+
return $this->chat->submit($message);
4659
}
4760
}

src/ai-bundle/src/Profiler/TraceableMessageStore.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
use Symfony\AI\Chat\ManagedStoreInterface;
1515
use Symfony\AI\Chat\MessageStoreInterface;
1616
use Symfony\AI\Platform\Message\MessageBag;
17+
use Symfony\Component\Clock\ClockInterface;
1718

1819
/**
1920
* @author Guillaume Loulier <personal@guillaumeloulier.fr>
2021
*
2122
* @phpstan-type MessageStoreData array{
2223
* bag: MessageBag,
24+
* saved_at: \DateTimeImmutable,
2325
* }
2426
*/
2527
final class TraceableMessageStore implements ManagedStoreInterface, MessageStoreInterface
@@ -31,13 +33,24 @@ final class TraceableMessageStore implements ManagedStoreInterface, MessageStore
3133

3234
public function __construct(
3335
private readonly MessageStoreInterface|ManagedStoreInterface $messageStore,
36+
private readonly ClockInterface $clock,
3437
) {
3538
}
3639

40+
public function setup(array $options = []): void
41+
{
42+
if (!$this->messageStore instanceof ManagedStoreInterface) {
43+
return;
44+
}
45+
46+
$this->messageStore->setup($options);
47+
}
48+
3749
public function save(MessageBag $messages): void
3850
{
3951
$this->calls[] = [
4052
'bag' => $messages,
53+
'saved_at' => $this->clock->now(),
4154
];
4255

4356
$this->messageStore->save($messages);
@@ -48,15 +61,6 @@ public function load(): MessageBag
4861
return $this->messageStore->load();
4962
}
5063

51-
public function setup(array $options = []): void
52-
{
53-
if (!$this->messageStore instanceof ManagedStoreInterface) {
54-
return;
55-
}
56-
57-
$this->messageStore->setup($options);
58-
}
59-
6064
public function drop(): void
6165
{
6266
if (!$this->messageStore instanceof ManagedStoreInterface) {

src/ai-bundle/templates/data_collector.html.twig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
<b class="label">Registered Tools</b>
2525
<span class="sf-toolbar-status">{{ collector.tools|length }}</span>
2626
</div>
27+
<div class="sf-toolbar-info-piece">
28+
<b class="label">Messages stored</b>
29+
<span class="sf-toolbar-status">{{ collector.messages|length }}</span>
30+
</div>
2731
<div class="sf-toolbar-info-piece">
2832
<b class="label">Tool Calls</b>
2933
<span class="sf-toolbar-status">{{ collector.toolCalls|length }}</span>

src/ai-bundle/tests/DependencyInjection/AiBundleTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ public function testInjectionChatAliasIsRegistered()
211211
],
212212
'chat' => [
213213
'main' => [
214-
'agent' => 'my_agent',
215-
'message_store' => 'memory.main',
214+
'agent' => 'ai.agent.my_agent',
215+
'message_store' => 'ai.message_store.memory.main',
216216
],
217217
],
218218
],

0 commit comments

Comments
 (0)