From 9dde800e4c0718bd99923fd04858d0d29677b50d Mon Sep 17 00:00:00 2001 From: Denis Zunke Date: Sat, 5 Jul 2025 16:50:59 +0200 Subject: [PATCH] feat: allow JsonSerializable objects in contract (#377) As brought up in #371 it could be a possible extension point to the contract to reintroduce the support for `JsonSerializable` objects when there are no normalizers for an object. So it would be a possible alternative for custom `MessageBagInterface`, `MessageInterface`, `ContentInterface`, etc. by allowing them to implement the `JsonSerializable` interface. --- src/platform/src/Contract.php | 4 ++++ src/platform/tests/ContractTest.php | 34 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/platform/src/Contract.php b/src/platform/src/Contract.php index e18f5efc0..a4afbab80 100644 --- a/src/platform/src/Contract.php +++ b/src/platform/src/Contract.php @@ -24,6 +24,7 @@ use Symfony\AI\Platform\Contract\Normalizer\ToolNormalizer; use Symfony\AI\Platform\Tool\Tool; use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; +use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Serializer; @@ -60,6 +61,9 @@ public static function create(NormalizerInterface ...$normalizer): self // Response $normalizer[] = new ToolCallNormalizer(); + // JsonSerializable objects as extension point to library interfaces + $normalizer[] = new JsonSerializableNormalizer(); + return new self( new Serializer($normalizer), ); diff --git a/src/platform/tests/ContractTest.php b/src/platform/tests/ContractTest.php index 3875791a9..5e9e67085 100644 --- a/src/platform/tests/ContractTest.php +++ b/src/platform/tests/ContractTest.php @@ -37,9 +37,12 @@ use Symfony\AI\Platform\Message\Content\ImageUrl; use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; +use Symfony\AI\Platform\Message\MessageInterface; +use Symfony\AI\Platform\Message\Role; use Symfony\AI\Platform\Message\SystemMessage; use Symfony\AI\Platform\Message\UserMessage; use Symfony\AI\Platform\Model; +use Symfony\Component\Uid\Uuid; #[Large] #[CoversClass(Contract::class)] @@ -198,6 +201,37 @@ public static function providePayloadTestCases(): iterable 'model' => 'gpt-4o', ], ]; + + $customSerializableMessage = new class implements MessageInterface, \JsonSerializable { + public function getRole(): Role + { + return Role::User; + } + + public function getId(): Uuid + { + return Uuid::v7(); + } + + public function jsonSerialize(): array + { + return [ + 'role' => 'user', + 'content' => 'This is a custom serializable message.', + ]; + } + }; + + yield 'MessageBag with custom message from GPT' => [ + 'model' => new GPT(), + 'input' => new MessageBag($customSerializableMessage), + 'expected' => [ + 'messages' => [ + ['role' => 'user', 'content' => 'This is a custom serializable message.'], + ], + 'model' => 'gpt-4o', + ], + ]; } #[Test]