Skip to content

Commit 6209d9b

Browse files
committed
feature #725 [Chat] Add interfaces for MessageStore management (Guikingone)
This PR was merged into the main branch. Discussion ---------- [Chat] Add interfaces for MessageStore management | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Docs? | yes | Issues | Fix none | License | MIT Hi 👋🏻 This PR introduce a new interface like in #328, this PR would allow to add commands later and improve the storage part of the `Chat` component. Commits ------- 1d080de feat(chat): add interface for management
2 parents f3cfd77 + 1d080de commit 6209d9b

File tree

13 files changed

+200
-62
lines changed

13 files changed

+200
-62
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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\Chat\Bridge\Local\CacheStore;
14+
use Symfony\AI\Chat\Chat;
15+
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory;
16+
use Symfony\AI\Platform\Message\Message;
17+
use Symfony\AI\Platform\Message\MessageBag;
18+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
19+
20+
require_once dirname(__DIR__).'/bootstrap.php';
21+
22+
$platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client());
23+
24+
$store = new CacheStore(new ArrayAdapter(), 'chat');
25+
$store->setup();
26+
27+
$agent = new Agent($platform, 'gpt-4o-mini', logger: logger());
28+
$chat = new Chat($agent, $store);
29+
30+
$messages = new MessageBag(
31+
Message::forSystem('You are a helpful assistant. You only answer with short sentences.'),
32+
);
33+
34+
$chat->initiate($messages);
35+
$chat->submit(Message::ofUser('My name is Christopher.'));
36+
$message = $chat->submit(Message::ofUser('What is my name?'));
37+
38+
echo $message->content.\PHP_EOL;
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\Chat\Bridge\HttpFoundation\SessionStore;
14+
use Symfony\AI\Chat\Chat;
15+
use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory;
16+
use Symfony\AI\Platform\Message\Message;
17+
use Symfony\AI\Platform\Message\MessageBag;
18+
use Symfony\Component\HttpFoundation\Request;
19+
use Symfony\Component\HttpFoundation\RequestStack;
20+
use Symfony\Component\HttpFoundation\Session\Session;
21+
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
22+
23+
require_once dirname(__DIR__).'/bootstrap.php';
24+
25+
$platform = PlatformFactory::create(env('OPENAI_API_KEY'), http_client());
26+
27+
$request = Request::create('/');
28+
$request->setSession(new Session(new MockArraySessionStorage()));
29+
30+
$requestStack = new RequestStack();
31+
$requestStack->push($request);
32+
33+
$store = new SessionStore($requestStack, 'chat');
34+
$store->setup();
35+
36+
$agent = new Agent($platform, 'gpt-4o-mini', logger: logger());
37+
$chat = new Chat($agent, $store);
38+
39+
$messages = new MessageBag(
40+
Message::forSystem('You are a helpful assistant. You only answer with short sentences.'),
41+
);
42+
43+
$chat->initiate($messages);
44+
$chat->submit(Message::ofUser('My name is Christopher.'));
45+
$message = $chat->submit(Message::ofUser('What is my name?'));
46+
47+
echo $message->content.\PHP_EOL;

examples/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"symfony/event-dispatcher": "^7.3|^8.0",
3030
"symfony/filesystem": "^7.3|^8.0",
3131
"symfony/finder": "^7.3|^8.0",
32+
"symfony/http-foundation": "^7.3|^8.0",
3233
"symfony/process": "^7.3|^8.0",
3334
"symfony/var-dumper": "^7.3|^8.0"
3435
},

src/chat/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Library for building chats with agents using messages. Built on Platform and Age
1212
- **Chat** (`src/Chat.php`): Main orchestration class
1313
- **ChatInterface**: Contract for implementations
1414
- **MessageStoreInterface** High-level conversation storage interface
15+
- **ManagedStoreInterface** High-level store management interface
1516

1617
### Key Features
1718
- **Bridge** (`src/Bridge/`): Storage capacity for messages and conversations

src/chat/CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Library for building chats with agents using messages. Built on Platform and Age
1212
- **Chat** (`src/Chat.php`): Main orchestration class
1313
- **ChatInterface**: Contract for implementations
1414
- **MessageStoreInterface** High-level conversation storage interface
15+
- **ManagedStoreInterface** High-level store management interface
1516

1617
### Key Features
1718
- **Bridge** (`src/Bridge/`): Storage capacity for messages and conversations

src/chat/doc/index.rst

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,53 @@ with a ``Symfony\AI\Agent\AgentInterface`` and a ``Symfony\AI\Chat\MessageStoreI
3434

3535
$chat->submit(Message::ofUser('Hello'));
3636

37+
38+
Implementing a Bridge
39+
---------------------
40+
41+
The main extension points of the Chat component is the ``Symfony\AI\Chat\MessageStoreInterface``, that defines the methods
42+
for adding messages to the message store, and returning the messages from a store.
43+
44+
This leads to a store implementing two methods::
45+
46+
use Symfony\AI\Store\MessageStoreInterface;
47+
48+
class MyCustomStore implements MessageStoreInterface
49+
{
50+
public function save(MessageBag $messages): void
51+
{
52+
// Implementation to add a message bag to the store
53+
}
54+
55+
public function load(): MessageBag
56+
{
57+
// Implementation to return a message bag from the store
58+
}
59+
}
60+
61+
Managing a store
62+
----------------
63+
64+
Some store might requires to create table, indexes and so on before storing messages,
65+
the ``Symfony\AI\Chat\ManagedStoreInterface`` defines the methods
66+
to setup and drop the store.
67+
68+
This leads to a store implementing two methods::
69+
70+
use Symfony\AI\Store\ManagedStoreInterface;
71+
use Symfony\AI\Store\MessageStoreInterface;
72+
73+
class MyCustomStore implements ManagedStoreInterface, MessageStoreInterface
74+
{
75+
# ...
76+
77+
public function setup(array $options = []): void
78+
{
79+
// Implementation to create the store
80+
}
81+
82+
public function drop(): void
83+
{
84+
// Implementation to drop the store (and related messages)
85+
}
86+
}

src/chat/src/Bridge/HttpFoundation/SessionStore.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\AI\Chat\Bridge\HttpFoundation;
1313

1414
use Symfony\AI\Agent\Exception\RuntimeException;
15+
use Symfony\AI\Chat\ManagedStoreInterface;
1516
use Symfony\AI\Chat\MessageStoreInterface;
1617
use Symfony\AI\Platform\Message\MessageBag;
1718
use Symfony\Component\HttpFoundation\RequestStack;
@@ -20,7 +21,7 @@
2021
/**
2122
* @author Christopher Hertel <[email protected]>
2223
*/
23-
final readonly class SessionStore implements MessageStoreInterface
24+
final readonly class SessionStore implements ManagedStoreInterface, MessageStoreInterface
2425
{
2526
private SessionInterface $session;
2627

@@ -31,9 +32,15 @@ public function __construct(
3132
if (!class_exists(RequestStack::class)) {
3233
throw new RuntimeException('For using the SessionStore as message store, the symfony/http-foundation package is required. Try running "composer require symfony/http-foundation".');
3334
}
35+
3436
$this->session = $requestStack->getSession();
3537
}
3638

39+
public function setup(array $options = []): void
40+
{
41+
$this->session->set($this->sessionKey, new MessageBag());
42+
}
43+
3744
public function save(MessageBag $messages): void
3845
{
3946
$this->session->set($this->sessionKey, $messages);
@@ -44,7 +51,7 @@ public function load(): MessageBag
4451
return $this->session->get($this->sessionKey, new MessageBag());
4552
}
4653

47-
public function clear(): void
54+
public function drop(): void
4855
{
4956
$this->session->remove($this->sessionKey);
5057
}

src/chat/src/Bridge/Local/CacheStore.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313

1414
use Psr\Cache\CacheItemPoolInterface;
1515
use Symfony\AI\Agent\Exception\RuntimeException;
16+
use Symfony\AI\Chat\ManagedStoreInterface;
1617
use Symfony\AI\Chat\MessageStoreInterface;
1718
use Symfony\AI\Platform\Message\MessageBag;
1819

1920
/**
2021
* @author Christopher Hertel <[email protected]>
2122
*/
22-
final readonly class CacheStore implements MessageStoreInterface
23+
final readonly class CacheStore implements ManagedStoreInterface, MessageStoreInterface
2324
{
2425
public function __construct(
2526
private CacheItemPoolInterface $cache,
@@ -31,6 +32,16 @@ public function __construct(
3132
}
3233
}
3334

35+
public function setup(array $options = []): void
36+
{
37+
$item = $this->cache->getItem($this->cacheKey);
38+
39+
$item->set(new MessageBag());
40+
$item->expiresAfter($this->ttl);
41+
42+
$this->cache->save($item);
43+
}
44+
3445
public function save(MessageBag $messages): void
3546
{
3647
$item = $this->cache->getItem($this->cacheKey);
@@ -48,7 +59,7 @@ public function load(): MessageBag
4859
return $item->isHit() ? $item->get() : new MessageBag();
4960
}
5061

51-
public function clear(): void
62+
public function drop(): void
5263
{
5364
$this->cache->deleteItem($this->cacheKey);
5465
}

src/chat/src/Bridge/Local/InMemoryStore.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,22 @@
1111

1212
namespace Symfony\AI\Chat\Bridge\Local;
1313

14+
use Symfony\AI\Chat\ManagedStoreInterface;
1415
use Symfony\AI\Chat\MessageStoreInterface;
1516
use Symfony\AI\Platform\Message\MessageBag;
1617

1718
/**
1819
* @author Christopher Hertel <[email protected]>
1920
*/
20-
final class InMemoryStore implements MessageStoreInterface
21+
final class InMemoryStore implements ManagedStoreInterface, MessageStoreInterface
2122
{
2223
private MessageBag $messages;
2324

25+
public function setup(array $options = []): void
26+
{
27+
$this->messages = new MessageBag();
28+
}
29+
2430
public function save(MessageBag $messages): void
2531
{
2632
$this->messages = $messages;
@@ -31,7 +37,7 @@ public function load(): MessageBag
3137
return $this->messages ?? new MessageBag();
3238
}
3339

34-
public function clear(): void
40+
public function drop(): void
3541
{
3642
$this->messages = new MessageBag();
3743
}

src/chat/src/Chat.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
{
2626
public function __construct(
2727
private AgentInterface $agent,
28-
private MessageStoreInterface $store,
28+
private MessageStoreInterface&ManagedStoreInterface $store,
2929
) {
3030
}
3131

3232
public function initiate(MessageBag $messages): void
3333
{
34-
$this->store->clear();
34+
$this->store->drop();
3535
$this->store->save($messages);
3636
}
3737

0 commit comments

Comments
 (0)