From f3fa8e72e7c379ad3c33003d8946c76e701919b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Lochm=C3=BCller?= Date: Fri, 28 Nov 2025 14:59:58 +0100 Subject: [PATCH 1/2] feat: Streamline message bag integration - Add and prepand behave same now (do not clone the object, keep the state / avoid that `prepand` also clone the object, because only with* methods should do so) - Add and prepand both return the current object for chain-calls - Add a ID for the message bag - Renew the ID in case of cloning the message bag - Merge do NOT clone the object anymore, because it just merge messages (clone can be done manually, if needed) - Remove the `with` method, because this was used just once (keep the focus to explicit clone and add, if needed) - Add `IteratorAggregate` interface for easy access the current messages Fix #962 Related #1018 --- examples/misc/parallel-chat-gpt.php | 2 +- src/platform/src/Message/MessageBag.php | 55 ++++++++++++------- src/platform/tests/Message/MessageBagTest.php | 22 +------- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/examples/misc/parallel-chat-gpt.php b/examples/misc/parallel-chat-gpt.php index 5357f82db..de26d384f 100644 --- a/examples/misc/parallel-chat-gpt.php +++ b/examples/misc/parallel-chat-gpt.php @@ -25,7 +25,7 @@ $results = []; foreach (range('A', 'D') as $letter) { echo ' - Request for the letter '.$letter.' initiated.'.\PHP_EOL; - $results[] = $platform->invoke('gpt-4o-mini', $messages->with(Message::ofUser($letter))); + $results[] = $platform->invoke('gpt-4o-mini', (clone $messages)->add(Message::ofUser($letter))); } echo 'Waiting for the responses ...'.\PHP_EOL; diff --git a/src/platform/src/Message/MessageBag.php b/src/platform/src/Message/MessageBag.php index c480f107f..48306df6b 100644 --- a/src/platform/src/Message/MessageBag.php +++ b/src/platform/src/Message/MessageBag.php @@ -12,14 +12,19 @@ namespace Symfony\AI\Platform\Message; use Symfony\AI\Platform\Metadata\MetadataAwareTrait; +use Symfony\Component\Uid\AbstractUid; +use Symfony\Component\Uid\TimeBasedUidInterface; +use Symfony\Component\Uid\Uuid; /** * @author Christopher Hertel */ -class MessageBag implements \Countable +class MessageBag implements \IteratorAggregate, \Countable { use MetadataAwareTrait; + private AbstractUid&TimeBasedUidInterface $id; + /** * @var list */ @@ -28,11 +33,31 @@ class MessageBag implements \Countable public function __construct(MessageInterface ...$messages) { $this->messages = array_values($messages); + $this->id = Uuid::v7(); + } + + public function __clone() + { + $this->id = Uuid::v7(); } - public function add(MessageInterface $message): void + public function getId(): AbstractUid&TimeBasedUidInterface + { + return $this->id; + } + + public function add(MessageInterface $message): self { $this->messages[] = $message; + + return $this; + } + + public function prepend(MessageInterface $message): self + { + $this->messages = array_merge([$message], $this->messages); + + return $this; } /** @@ -65,20 +90,11 @@ public function getUserMessage(): ?UserMessage return null; } - public function with(MessageInterface $message): self - { - $messages = clone $this; - $messages->add($message); - - return $messages; - } - public function merge(self $messageBag): self { - $messages = clone $this; - $messages->messages = array_merge($messages->messages, $messageBag->getMessages()); + $this->messages = array_merge($this->messages, $messageBag->getMessages()); - return $messages; + return $this; } public function withoutSystemMessage(): self @@ -92,14 +108,6 @@ public function withoutSystemMessage(): self return $messages; } - public function prepend(MessageInterface $message): self - { - $messages = clone $this; - $messages->messages = array_merge([$message], $messages->messages); - - return $messages; - } - public function containsAudio(): bool { foreach ($this->messages as $message) { @@ -126,4 +134,9 @@ public function count(): int { return \count($this->messages); } + + public function getIterator(): \Traversable + { + return new \ArrayIterator($this->messages); + } } diff --git a/src/platform/tests/Message/MessageBagTest.php b/src/platform/tests/Message/MessageBagTest.php index cbe88e179..260b26284 100644 --- a/src/platform/tests/Message/MessageBagTest.php +++ b/src/platform/tests/Message/MessageBagTest.php @@ -48,26 +48,6 @@ public function testGetSystemMessageWithoutSystemMessage() $this->assertNull($messageBag->getSystemMessage()); } - public function testWith() - { - $messageBag = new MessageBag( - Message::forSystem('My amazing system prompt.'), - Message::ofAssistant('It is time to sleep.'), - Message::ofUser('Hello, world!'), - ); - - $newMessage = Message::ofAssistant('It is time to wake up.'); - $newMessageBag = $messageBag->with($newMessage); - - $this->assertCount(3, $messageBag); - $this->assertCount(4, $newMessageBag); - - $newMessageFromBag = $newMessageBag->getMessages()[3]; - - $this->assertInstanceOf(AssistantMessage::class, $newMessageFromBag); - $this->assertSame('It is time to wake up.', $newMessageFromBag->getContent()); - } - public function testMerge() { $messageBag = new MessageBag( @@ -121,7 +101,7 @@ public function testPrepend() ); $newMessage = Message::forSystem('My amazing system prompt.'); - $newMessageBag = $messageBag->prepend($newMessage); + $newMessageBag = (clone $messageBag)->prepend($newMessage); $this->assertCount(2, $messageBag); $this->assertCount(3, $newMessageBag); From 50b69d0a5ec3550946ac1f1632e4c138cee07b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Lochm=C3=BCller?= Date: Fri, 28 Nov 2025 15:09:02 +0100 Subject: [PATCH 2/2] fix: Add missing phpstan annotation --- src/platform/src/Message/MessageBag.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform/src/Message/MessageBag.php b/src/platform/src/Message/MessageBag.php index 48306df6b..fe9e4978a 100644 --- a/src/platform/src/Message/MessageBag.php +++ b/src/platform/src/Message/MessageBag.php @@ -18,6 +18,8 @@ /** * @author Christopher Hertel + * + * @implements \IteratorAggregate */ class MessageBag implements \IteratorAggregate, \Countable {