Skip to content

Commit 3ab26e3

Browse files
committed
fix
1 parent 8cb4528 commit 3ab26e3

File tree

9 files changed

+176
-8
lines changed

9 files changed

+176
-8
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\AI\Agent\Agent;
13+
use Symfony\AI\Agent\Chat;
14+
use Symfony\AI\Agent\Chat\MessageStore\InMemoryStore;
15+
use Symfony\AI\Platform\Bridge\OpenAi\Gpt;
16+
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory;
17+
use Symfony\AI\Platform\Message\Message;
18+
use Symfony\AI\Platform\Message\MessageBag;
19+
20+
require_once dirname(__DIR__).'/bootstrap.php';
21+
22+
$platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client());
23+
$llm = new Gpt(Gpt::GPT_4O_MINI);
24+
25+
$firstAgent = new Agent($platform, $llm, logger: logger());
26+
$secondAgent = new Agent($platform, $llm, logger: logger());
27+
28+
$store = new InMemoryStore();
29+
30+
$firstChatStore = $store->withSession($firstAgent->getId());
31+
$secondChatStore = $store->withSession($secondAgent->getId());
32+
33+
$firstChat = new Chat($firstAgent, $firstChatStore);
34+
$secondChat = new Chat($secondAgent, $secondChatStore);
35+
36+
$messages = new MessageBag(
37+
Message::forSystem('You are a helpful assistant. You only answer with short sentences.'),
38+
);
39+
40+
$firstChat->initiate($messages);
41+
$secondChat->initiate($messages);
42+
$firstChat->submit(Message::ofUser('My name is Christopher.'));
43+
$firstChatMessage = $firstChat->submit(Message::ofUser('What is my name?'));
44+
$secondChatMessage = $secondChat->submit(Message::ofUser('What is my name?'));
45+
46+
echo $firstChatMessage->content.\PHP_EOL;
47+
echo $secondChatMessage->content.\PHP_EOL;

src/agent/src/Agent.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
use Symfony\AI\Platform\Model;
2222
use Symfony\AI\Platform\PlatformInterface;
2323
use Symfony\AI\Platform\Result\ResultInterface;
24+
use Symfony\Component\Uid\AbstractUid;
25+
use Symfony\Component\Uid\TimeBasedUidInterface;
26+
use Symfony\Component\Uid\Uuid;
2427
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
2528
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
2629

@@ -29,6 +32,8 @@
2932
*/
3033
final readonly class Agent implements AgentInterface
3134
{
35+
private AbstractUid&TimeBasedUidInterface $id;
36+
3237
/**
3338
* @var InputProcessorInterface[]
3439
*/
@@ -52,6 +57,8 @@ public function __construct(
5257
) {
5358
$this->inputProcessors = $this->initializeProcessors($inputProcessors, InputProcessorInterface::class);
5459
$this->outputProcessors = $this->initializeProcessors($outputProcessors, OutputProcessorInterface::class);
60+
61+
$this->id = Uuid::v7();
5562
}
5663

5764
/**
@@ -97,6 +104,11 @@ public function call(MessageBagInterface $messages, array $options = []): Result
97104
return $output->result;
98105
}
99106

107+
public function getId(): AbstractUid&TimeBasedUidInterface
108+
{
109+
return $this->id;
110+
}
111+
100112
/**
101113
* @param InputProcessorInterface[]|OutputProcessorInterface[] $processors
102114
* @param class-string $interface

src/agent/src/AgentInterface.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Symfony\AI\Agent\Exception\ExceptionInterface;
1515
use Symfony\AI\Platform\Message\MessageBagInterface;
1616
use Symfony\AI\Platform\Result\ResultInterface;
17+
use Symfony\Component\Uid\AbstractUid;
18+
use Symfony\Component\Uid\TimeBasedUidInterface;
1719

1820
/**
1921
* @author Denis Zunke <[email protected]>
@@ -26,4 +28,6 @@ interface AgentInterface
2628
* @throws ExceptionInterface When the agent encounters an error (e.g., unsupported model capabilities, invalid arguments, network failures, or processor errors)
2729
*/
2830
public function call(MessageBagInterface $messages, array $options = []): ResultInterface;
31+
32+
public function getId(): AbstractUid&TimeBasedUidInterface;
2933
}

src/agent/src/Chat/MessageStore/CacheStore.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313

1414
use Psr\Cache\CacheItemPoolInterface;
1515
use Symfony\AI\Agent\Chat\MessageStoreInterface;
16+
use Symfony\AI\Agent\Chat\SessionAwareMessageStoreInterface;
1617
use Symfony\AI\Agent\Exception\RuntimeException;
1718
use Symfony\AI\Platform\Message\MessageBag;
1819
use Symfony\AI\Platform\Message\MessageBagInterface;
20+
use Symfony\Component\Uid\AbstractUid;
21+
use Symfony\Component\Uid\TimeBasedUidInterface;
1922

20-
final readonly class CacheStore implements MessageStoreInterface
23+
final readonly class CacheStore implements MessageStoreInterface, SessionAwareMessageStoreInterface
2124
{
2225
public function __construct(
2326
private CacheItemPoolInterface $cache,
@@ -50,4 +53,9 @@ public function clear(): void
5053
{
5154
$this->cache->deleteItem($this->cacheKey);
5255
}
56+
57+
public function withSession(AbstractUid&TimeBasedUidInterface $session): MessageStoreInterface&SessionAwareMessageStoreInterface
58+
{
59+
return new $this($this->cache, $session->toRfc4122(), $this->ttl);
60+
}
5361
}

src/agent/src/Chat/MessageStore/InMemoryStore.php

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,56 @@
1212
namespace Symfony\AI\Agent\Chat\MessageStore;
1313

1414
use Symfony\AI\Agent\Chat\MessageStoreInterface;
15+
use Symfony\AI\Agent\Chat\SessionAwareMessageStoreInterface;
1516
use Symfony\AI\Platform\Message\MessageBag;
1617
use Symfony\AI\Platform\Message\MessageBagInterface;
18+
use Symfony\Component\Uid\AbstractUid;
19+
use Symfony\Component\Uid\TimeBasedUidInterface;
1720

18-
final class InMemoryStore implements MessageStoreInterface
21+
final class InMemoryStore implements MessageStoreInterface, SessionAwareMessageStoreInterface
1922
{
20-
private MessageBagInterface $messages;
23+
/**
24+
* @var MessageBagInterface[]
25+
*/
26+
private array $messages;
27+
private (AbstractUid&TimeBasedUidInterface)|null $session = null;
2128

2229
public function save(MessageBagInterface $messages): void
2330
{
24-
$this->messages = $messages;
31+
if (null === $this->session) {
32+
$this->messages = $messages->getMessages();
33+
34+
return;
35+
}
36+
37+
$this->messages[$this->session->toRfc4122()] = $messages;
2538
}
2639

2740
public function load(): MessageBagInterface
2841
{
29-
return $this->messages ?? new MessageBag();
42+
if (null === $this->session) {
43+
return new MessageBag(...$this->messages);
44+
}
45+
46+
return $this->messages[$this->session->toRfc4122()] ?? new MessageBag();
3047
}
3148

3249
public function clear(): void
3350
{
34-
$this->messages = new MessageBag();
51+
if (null === $this->session) {
52+
$this->messages = [];
53+
54+
return;
55+
}
56+
57+
$this->messages[$this->session->toRfc4122()] = new MessageBag();
58+
}
59+
60+
public function withSession(AbstractUid&TimeBasedUidInterface $session): MessageStoreInterface&SessionAwareMessageStoreInterface
61+
{
62+
$store = clone $this;
63+
$store->session = $session;
64+
65+
return $store;
3566
}
3667
}

src/agent/src/Chat/MessageStore/SessionStore.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
namespace Symfony\AI\Agent\Chat\MessageStore;
1313

1414
use Symfony\AI\Agent\Chat\MessageStoreInterface;
15+
use Symfony\AI\Agent\Chat\SessionAwareMessageStoreInterface;
1516
use Symfony\AI\Agent\Exception\RuntimeException;
1617
use Symfony\AI\Platform\Message\MessageBag;
1718
use Symfony\AI\Platform\Message\MessageBagInterface;
1819
use Symfony\Component\HttpFoundation\RequestStack;
1920
use Symfony\Component\HttpFoundation\Session\SessionInterface;
21+
use Symfony\Component\Uid\AbstractUid;
22+
use Symfony\Component\Uid\TimeBasedUidInterface;
2023

21-
final readonly class SessionStore implements MessageStoreInterface
24+
final readonly class SessionStore implements MessageStoreInterface, SessionAwareMessageStoreInterface
2225
{
2326
private SessionInterface $session;
2427

@@ -46,4 +49,12 @@ public function clear(): void
4649
{
4750
$this->session->remove($this->sessionKey);
4851
}
52+
53+
public function withSession(AbstractUid&TimeBasedUidInterface $session): MessageStoreInterface&SessionAwareMessageStoreInterface
54+
{
55+
$store = clone $this;
56+
$store->session->setId($session->toRfc4122());
57+
58+
return $store;
59+
}
4960
}

src/agent/src/Chat/MessageStoreInterface.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
namespace Symfony\AI\Agent\Chat;
1313

1414
use Symfony\AI\Platform\Message\MessageBagInterface;
15+
use Symfony\Component\Uid\AbstractUid;
16+
use Symfony\Component\Uid\TimeBasedUidInterface;
1517

1618
interface MessageStoreInterface
1719
{
1820
public function save(MessageBagInterface $messages): void;
1921

20-
public function load(): MessageBagInterface;
22+
public function load((AbstractUid&TimeBasedUidInterface)|null $session = null): MessageBagInterface;
2123

2224
public function clear(): void;
2325
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Agent\Chat;
13+
14+
use Symfony\Component\Uid\AbstractUid;
15+
use Symfony\Component\Uid\TimeBasedUidInterface;
16+
17+
interface SessionAwareMessageStoreInterface
18+
{
19+
public function withSession(AbstractUid&TimeBasedUidInterface $session): MessageStoreInterface&SessionAwareMessageStoreInterface;
20+
}

src/agent/tests/AgentTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use Symfony\AI\Agent\Agent;
2020
use Symfony\AI\Agent\AgentAwareInterface;
2121
use Symfony\AI\Agent\AgentInterface;
22+
use Symfony\AI\Agent\Chat;
23+
use Symfony\AI\Agent\Chat\MessageStore\InMemoryStore;
2224
use Symfony\AI\Agent\Exception\InvalidArgumentException;
2325
use Symfony\AI\Agent\Exception\MissingModelSupportException;
2426
use Symfony\AI\Agent\Exception\RuntimeException;
@@ -30,6 +32,7 @@
3032
use Symfony\AI\Platform\Message\Content\Audio;
3133
use Symfony\AI\Platform\Message\Content\Image;
3234
use Symfony\AI\Platform\Message\Content\Text;
35+
use Symfony\AI\Platform\Message\Message;
3336
use Symfony\AI\Platform\Message\MessageBag;
3437
use Symfony\AI\Platform\Message\UserMessage;
3538
use Symfony\AI\Platform\Model;
@@ -49,6 +52,8 @@
4952
#[UsesClass(Text::class)]
5053
#[UsesClass(Audio::class)]
5154
#[UsesClass(Image::class)]
55+
#[UsesClass(InMemoryStore::class)]
56+
#[UsesClass(Chat::class)]
5257
#[Small]
5358
final class AgentTest extends TestCase
5459
{
@@ -395,4 +400,32 @@ public function testConstructorAcceptsTraversableProcessors()
395400

396401
$this->assertInstanceOf(AgentInterface::class, $agent);
397402
}
403+
404+
public function testDoubleAgentCanUseSameMessageStore()
405+
{
406+
$platform = $this->createMock(PlatformInterface::class);
407+
$model = $this->createMock(Model::class);
408+
409+
$firstAgent = new Agent($platform, $model);
410+
$secondAgent = new Agent($platform, $model);
411+
412+
$store = new InMemoryStore();
413+
$firstStore = $store->withSession($firstAgent->getId());
414+
$secondStore = $store->withSession($secondAgent->getId());
415+
416+
$firstChat = new Chat($firstAgent, $firstStore);
417+
$secondChat = new Chat($secondAgent, $secondStore);
418+
419+
$messages = new MessageBag(
420+
Message::forSystem('You are a helpful assistant. You only answer with short sentences.'),
421+
);
422+
423+
$firstChat->initiate($messages);
424+
$firstChat->submit(new UserMessage(new Text('Hello')));
425+
$secondChat->submit(new UserMessage(new Text('Hello')));
426+
$secondChat->submit(new UserMessage(new Text('Hello there')));
427+
428+
$this->assertCount(1, $firstStore->load());
429+
$this->assertCount(2, $secondStore->load());
430+
}
398431
}

0 commit comments

Comments
 (0)