Skip to content

Commit

Permalink
initial draft
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisB-TL committed Dec 12, 2024
1 parent ffac3a5 commit 1fc1127
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 12 deletions.
7 changes: 6 additions & 1 deletion docs/providers/anthropic.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ While Anthropic models don't have native JSON mode or structured output like som
## Limitations
### Messages

Does not support the `SystemMessage` message type, we automatically convert `SystemMessage` to `UserMessage`.
Most providers' API include system messages in the messages array with a "system" role. Anthropic does not support the system role, and instead has a "system" property, separate from messages.

Therefore, for Anthropic we:
* Filter all `SystemMessage`s out, omitting them from messages.
* Always submit the prompt defined with `->withSystemPrompt()` at the top of the system prompts array.
* Move all `SystemMessage`s to the system prompts array in the order they were declared.

### Images

Expand Down
2 changes: 1 addition & 1 deletion src/Providers/Anthropic/Handlers/Structured.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function sendRequest(Request $request): Response
'messages' => MessageMap::map($request->messages),
'max_tokens' => $request->maxTokens ?? 2048,
], array_filter([
'system' => $request->systemPrompt,
'system' => MessageMap::mapSystemMessages($request->messages, $request->systemPrompt),
'temperature' => $request->temperature,
'top_p' => $request->topP,
'tools' => ToolMap::map($request->tools),
Expand Down
2 changes: 1 addition & 1 deletion src/Providers/Anthropic/Handlers/Text.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function sendRequest(Request $request): Response
'messages' => MessageMap::map($request->messages),
'max_tokens' => $request->maxTokens ?? 2048,
], array_filter([
'system' => $request->systemPrompt,
'system' => MessageMap::mapSystemMessages($request->messages, $request->systemPrompt),
'temperature' => $request->temperature,
'top_p' => $request->topP,
'tools' => ToolMap::map($request->tools),
Expand Down
25 changes: 22 additions & 3 deletions src/Providers/Anthropic/Maps/MessageMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,26 @@ class MessageMap
*/
public static function map(array $messages): array
{
return array_map(fn (Message $message): array => self::mapMessage($message), $messages);
return array_values(array_map(
fn (Message $message): array => self::mapMessage($message),
array_filter($messages, fn (Message $message): bool => !$message instanceof SystemMessage)
));
}

/**
* @param array<int, Message> $messages
* @param null|string $systemPrompt
* @return array<int, mixed>
*/
public static function mapSystemMessages(array $messages, ?string $systemPrompt): array
{
return array_values(array_merge(
$systemPrompt !== null ? [self::mapSystemMessage(new SystemMessage($systemPrompt))] : [],
array_map(
fn (Message $message): array => self::mapMessage($message),
array_filter($messages, fn (Message $message): bool => $message instanceof SystemMessage)
)
));
}

/**
Expand All @@ -46,8 +65,8 @@ protected static function mapMessage(Message $message): array
protected static function mapSystemMessage(SystemMessage $systemMessage): array
{
return [
'role' => 'user',
'content' => $systemMessage->content,
'type' => 'text',
'text' => $systemMessage->content,
];
}

Expand Down
31 changes: 25 additions & 6 deletions tests/Providers/Anthropic/MessageMapTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@
]]);
});

it('filters system messages out when calling map', function (): void {
expect(MessageMap::map([
new UserMessage('Who are you?'),
new SystemMessage('I am Groot.')
]))->toBe([[
'role' => 'user',
'content' => [
['type' => 'text', 'text' => 'Who are you?'],
],
]]);
});

it('maps user messages with images from path', function (): void {
$mappedMessage = MessageMap::map([
new UserMessage('Who are you?', [
Expand Down Expand Up @@ -136,10 +148,17 @@
});

it('maps system messages', function (): void {
expect(MessageMap::map([
new SystemMessage('Who are you?'),
]))->toBe([[
'role' => 'user',
'content' => 'Who are you?',
]]);
expect(MessageMap::mapSystemMessages(
[new SystemMessage('Who are you?'), new UserMessage('I am rocket.')],
'I am Thanos. Me first.'
))->toBe([
[
'type' => 'text',
'text' => 'I am Thanos. Me first.',
],
[
'type' => 'text',
'text' => 'Who are you?',
]
]);
});

0 comments on commit 1fc1127

Please sign in to comment.