Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 56c7c92

Browse files
committed
feat\!: add UUID to all messages and serialize in normalizers
- Add unique ID (UUIDv7) to all message types - Serialize message IDs in all normalizers - Create UuidAssertionTrait for testing UUID v7 validity - Update all message tests with UUID assertions - Add getId() method to MessageInterface - Update symfony/uid dependency to ^6.4 || ^7.0 BREAKING CHANGE: MessageInterface now requires getId() method
1 parent 929a7c1 commit 56c7c92

19 files changed

+296
-41
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,32 @@ a **MessageBag** to a **Chain**, which takes care of LLM invocation and response
8989
Messages can be of different types, most importantly `UserMessage`, `SystemMessage`, or `AssistantMessage`, and can also
9090
have different content types, like `Text`, `Image` or `Audio`.
9191

92+
#### Message Unique IDs
93+
94+
Each message automatically receives a unique identifier (UUID v7) upon creation.
95+
This provides several benefits:
96+
97+
- **Traceability**: Track individual messages through your application
98+
- **Time-ordered**: UUIDs are naturally sortable by creation time
99+
- **Timestamp extraction**: Get the exact creation time from the ID
100+
- **Database-friendly**: Sequential nature improves index performance
101+
102+
```php
103+
use PhpLlm\LlmChain\Platform\Message\Message;
104+
105+
$message = Message::ofUser('Hello, AI!');
106+
107+
// Access the unique ID
108+
$id = $message->getId(); // Returns Symfony\Component\Uid\Uuid instance
109+
110+
// Extract creation timestamp
111+
$createdAt = $id->getDateTime(); // Returns \DateTimeImmutable
112+
echo $createdAt->format('Y-m-d H:i:s.u'); // e.g., "2025-06-29 15:30:45.123456"
113+
114+
// Get string representation
115+
echo $id->toRfc4122(); // e.g., "01928d1f-6f2e-7123-a456-123456789abc"
116+
```
117+
92118
#### Example Chain call with messages
93119

94120
```php

src/Platform/Contract/Normalizer/Message/AssistantMessageNormalizer.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ public function getSupportedTypes(?string $format): array
3131
/**
3232
* @param AssistantMessage $data
3333
*
34-
* @return array{role: 'assistant', content: string}
34+
* @return array{role: 'assistant', id: string, content?: string, tool_calls?: array<array<string, mixed>>}
3535
*/
3636
public function normalize(mixed $data, ?string $format = null, array $context = []): array
3737
{
3838
$array = [
3939
'role' => $data->getRole()->value,
40+
'id' => $data->getId()->toRfc4122(),
4041
];
4142

4243
if (null !== $data->content) {

src/Platform/Contract/Normalizer/Message/SystemMessageNormalizer.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ public function getSupportedTypes(?string $format): array
2727
/**
2828
* @param SystemMessage $data
2929
*
30-
* @return array{role: 'system', content: string}
30+
* @return array{role: 'system', content: string, id: string}
3131
*/
3232
public function normalize(mixed $data, ?string $format = null, array $context = []): array
3333
{
3434
return [
3535
'role' => $data->getRole()->value,
3636
'content' => $data->content,
37+
'id' => $data->getId()->toRfc4122(),
3738
];
3839
}
3940
}

src/Platform/Contract/Normalizer/Message/ToolCallMessageNormalizer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public function getSupportedTypes(?string $format): array
3333
* role: 'tool',
3434
* content: string,
3535
* tool_call_id: string,
36+
* id: string,
3637
* }
3738
*/
3839
public function normalize(mixed $data, ?string $format = null, array $context = []): array
@@ -41,6 +42,7 @@ public function normalize(mixed $data, ?string $format = null, array $context =
4142
'role' => $data->getRole()->value,
4243
'content' => $this->normalizer->normalize($data->content, $format, $context),
4344
'tool_call_id' => $data->toolCall->id,
45+
'id' => $data->getId()->toRfc4122(),
4446
];
4547
}
4648
}

src/Platform/Contract/Normalizer/Message/UserMessageNormalizer.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ public function getSupportedTypes(?string $format): array
3232
/**
3333
* @param UserMessage $data
3434
*
35-
* @return array{role: 'assistant', content: string}
35+
* @return array{role: 'assistant', content: string, id: string}
3636
*/
3737
public function normalize(mixed $data, ?string $format = null, array $context = []): array
3838
{
39-
$array = ['role' => $data->getRole()->value];
39+
$array = [
40+
'role' => $data->getRole()->value,
41+
'id' => $data->getId()->toRfc4122(),
42+
];
4043

4144
if (1 === \count($data->content) && $data->content[0] instanceof Text) {
4245
$array['content'] = $data->content[0]->text;

src/Platform/Message/AssistantMessage.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,35 @@
55
namespace PhpLlm\LlmChain\Platform\Message;
66

77
use PhpLlm\LlmChain\Platform\Response\ToolCall;
8+
use Symfony\Component\Uid\Uuid;
89

910
/**
1011
* @author Denis Zunke <[email protected]>
1112
*/
1213
final readonly class AssistantMessage implements MessageInterface
1314
{
15+
public Uuid $id;
16+
1417
/**
1518
* @param ?ToolCall[] $toolCalls
1619
*/
1720
public function __construct(
1821
public ?string $content = null,
1922
public ?array $toolCalls = null,
2023
) {
24+
$this->id = Uuid::v7();
2125
}
2226

2327
public function getRole(): Role
2428
{
2529
return Role::Assistant;
2630
}
2731

32+
public function getId(): Uuid
33+
{
34+
return $this->id;
35+
}
36+
2837
public function hasToolCalls(): bool
2938
{
3039
return null !== $this->toolCalls && 0 !== \count($this->toolCalls);

src/Platform/Message/MessageInterface.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44

55
namespace PhpLlm\LlmChain\Platform\Message;
66

7+
use Symfony\Component\Uid\Uuid;
8+
79
/**
810
* @author Denis Zunke <[email protected]>
911
*/
1012
interface MessageInterface
1113
{
1214
public function getRole(): Role;
15+
16+
public function getId(): Uuid;
1317
}

src/Platform/Message/SystemMessage.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,27 @@
44

55
namespace PhpLlm\LlmChain\Platform\Message;
66

7+
use Symfony\Component\Uid\Uuid;
8+
79
/**
810
* @author Denis Zunke <[email protected]>
911
*/
1012
final readonly class SystemMessage implements MessageInterface
1113
{
14+
public Uuid $id;
15+
1216
public function __construct(public string $content)
1317
{
18+
$this->id = Uuid::v7();
1419
}
1520

1621
public function getRole(): Role
1722
{
1823
return Role::System;
1924
}
25+
26+
public function getId(): Uuid
27+
{
28+
return $this->id;
29+
}
2030
}

src/Platform/Message/ToolCallMessage.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,29 @@
55
namespace PhpLlm\LlmChain\Platform\Message;
66

77
use PhpLlm\LlmChain\Platform\Response\ToolCall;
8+
use Symfony\Component\Uid\Uuid;
89

910
/**
1011
* @author Denis Zunke <[email protected]>
1112
*/
1213
final readonly class ToolCallMessage implements MessageInterface
1314
{
15+
public Uuid $id;
16+
1417
public function __construct(
1518
public ToolCall $toolCall,
1619
public string $content,
1720
) {
21+
$this->id = Uuid::v7();
1822
}
1923

2024
public function getRole(): Role
2125
{
2226
return Role::ToolCall;
2327
}
28+
29+
public function getId(): Uuid
30+
{
31+
return $this->id;
32+
}
2433
}

src/Platform/Message/UserMessage.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpLlm\LlmChain\Platform\Message\Content\ContentInterface;
99
use PhpLlm\LlmChain\Platform\Message\Content\Image;
1010
use PhpLlm\LlmChain\Platform\Message\Content\ImageUrl;
11+
use Symfony\Component\Uid\Uuid;
1112

1213
/**
1314
* @author Denis Zunke <[email protected]>
@@ -19,17 +20,25 @@
1920
*/
2021
public array $content;
2122

23+
public Uuid $id;
24+
2225
public function __construct(
2326
ContentInterface ...$content,
2427
) {
2528
$this->content = $content;
29+
$this->id = Uuid::v7();
2630
}
2731

2832
public function getRole(): Role
2933
{
3034
return Role::User;
3135
}
3236

37+
public function getId(): Uuid
38+
{
39+
return $this->id;
40+
}
41+
3342
public function hasAudioContent(): bool
3443
{
3544
foreach ($this->content as $content) {

0 commit comments

Comments
 (0)