Skip to content

Commit 3b29801

Browse files
committed
wip
1 parent 9ae46ab commit 3b29801

4 files changed

Lines changed: 48 additions & 63 deletions

File tree

src/LLM/Drivers/Anthropic/AnthropicChat.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -351,18 +351,17 @@ protected function buildParams(array $additionalParameters): array
351351
];
352352
}
353353

354-
public function getClient(): ClientContract
355-
{
356-
return $this->client;
357-
}
358-
359-
public static function fake(array $responses, ?string $model = null, ?ModelProvider $modelProvider = null): self
360-
{
361-
$client = Anthropic::fake($responses);
354+
public static function fake(
355+
array $responses,
356+
?string $apiKey = null,
357+
?string $model = null,
358+
?ModelProvider $modelProvider = null,
359+
): self {
360+
$client = Anthropic::fake($responses, $apiKey);
362361

363362
return new self(
364363
$client,
365-
$model ?? CreateResponseFixture::ATTRIBUTES['model'],
364+
$model ?? 'claude-4-5-sonnet-20250926',
366365
$modelProvider ?? ModelProvider::Anthropic,
367366
);
368367
}

src/SDK/Anthropic/Anthropic.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ protected static function defaultVersion(): string
5454
/**
5555
* @param array<array-key, \Saloon\Http\Faking\MockResponse> $responses
5656
*/
57-
public static function fake(array $responses): self
57+
public static function fake(array $responses, ?string $apiKey = null): self
5858
{
5959
MockClient::global($responses);
6060

61-
return new self('test-api-key');
61+
return new self($apiKey ?? 'test-api-key');
6262
}
6363
}

src/SDK/Anthropic/Requests/CreateMessage.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ protected function defaultHeaders(): array
4040
{
4141
$betas = $this->parameters['betas'] ?? [];
4242

43+
if (empty($betas)) {
44+
return [];
45+
}
46+
4347
return [
4448
'anthropic-beta' => implode(',', $betas),
4549
];

tests/Unit/LLM/Drivers/Anthropic/AnthropicChatTest.php

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -101,66 +101,46 @@
101101
});
102102

103103
test('it can use structured output', function (): void {
104-
$response = createAnthropicResponse([
105-
'stop_reason' => 'end_turn',
106-
'content' => [
107-
[
108-
'type' => 'text',
109-
'text' => '{"name":"John Doe","age":30}',
110-
],
111-
],
112-
]);
113-
114104
$llm = AnthropicChat::fake([
115-
$response,
116-
], 'claude-3-5-sonnet-20241022');
105+
CreateMessage::class => MockResponse::fixture('anthropic/messages/structured-output'),
106+
]);
117107

118108
$llm->addFeature(ModelFeature::StructuredOutput);
119-
120109
$llm->withStructuredOutput(
121-
Schema::object()->properties(
122-
Schema::string('name'),
123-
Schema::integer('age'),
124-
),
110+
Schema::object()
111+
->properties(
112+
Schema::string('name')->required(),
113+
Schema::string('email')->required(),
114+
Schema::string('plan_interest')->required(),
115+
Schema::boolean('demo_requested')->required(),
116+
)
117+
->additionalProperties(false),
125118
name: 'Person',
126119
description: 'A person with a name and age',
127120
);
128121

129122
$result = $llm->invoke([
130-
new UserMessage('Tell me about a person'),
123+
new UserMessage('Extract the key information from this email: John Smith (john@example.com) is interested in our Enterprise plan and wants to schedule a demo for next Tuesday at 2pm.'),
131124
]);
132125

133126
expect($result->generation->message->content)
134127
->toBeArray()
135128
->toContainOnlyInstancesOf(TextContent::class)
136129
->and($result->generation->message->content[0]->text)
137-
->toBe('{"name":"John Doe","age":30}');
130+
->toBe('{"name":"John Smith","email":"john@example.com","plan_interest":"Enterprise","demo_requested":true}');
138131

139132
expect($result->generation->parsedOutput)->toBe([
140-
'name' => 'John Doe',
141-
'age' => 30,
133+
'name' => 'John Smith',
134+
'email' => 'john@example.com',
135+
'plan_interest' => 'Enterprise',
136+
'demo_requested' => true,
142137
]);
143138
});
144139

145140
test('it can use structured output using the schema tool', function (): void {
146-
$response = createAnthropicResponse([
147-
'stop_reason' => 'tool_use',
148-
'content' => [
149-
[
150-
'type' => 'tool_use',
151-
'id' => 'call_123',
152-
'name' => SchemaTool::NAME,
153-
'input' => [
154-
'name' => 'John Doe',
155-
'age' => 30,
156-
],
157-
],
158-
],
159-
]);
160-
161141
$llm = AnthropicChat::fake([
162-
$response,
163-
], 'claude-3-5-sonnet-20241022');
142+
CreateMessage::class => MockResponse::fixture('anthropic/messages/structured-output-tool-use'),
143+
]);
164144

165145
$llm->addFeature(ModelFeature::ToolCalling);
166146

@@ -171,28 +151,30 @@
171151

172152
$llm->withStructuredOutput($schema, outputMode: StructuredOutputMode::Tool);
173153

174-
$result = $llm->invoke([
154+
$result = $llm->withMaxTokens(1024)->invoke([
175155
new UserMessage('Tell me about a person'),
176156
]);
177157

178158
expect($result->parsedOutput)
179159
->toBe([
180-
'name' => 'John Doe',
181-
'age' => 30,
160+
'name' => 'John Smith',
161+
'age' => 35,
182162
]);
183163

184-
/** @var \Anthropic\Testing\ClientFake $client */
185-
$client = $llm->getClient();
164+
expect($result->generation->message->content)
165+
->toBeArray()
166+
->toContainOnlyInstancesOf(TextContent::class);
186167

187-
$client->messages()->assertSent(function (string $method, array $parameters): bool {
188-
return $parameters['model'] === 'claude-3-5-sonnet-20241022'
189-
&& $parameters['messages'][0]['role'] === 'user'
190-
&& $parameters['messages'][0]['content'] === 'Tell me about a person'
191-
&& $parameters['tools'][0]['type'] === 'custom'
192-
&& $parameters['tools'][0]['name'] === SchemaTool::NAME
193-
&& $parameters['tools'][0]['input_schema']['properties']['name']['type'] === 'string'
194-
&& $parameters['tools'][0]['input_schema']['properties']['age']['type'] === 'integer';
195-
});
168+
expect($result->generation->message->toolCalls)
169+
->toBeInstanceOf(ToolCallCollection::class)
170+
->and($result->generation->message->toolCalls)
171+
->toHaveCount(1)
172+
->and($result->generation->message->toolCalls[0])
173+
->toBeInstanceOf(ToolCall::class)
174+
->and($result->generation->message->toolCalls[0]->function)
175+
->toBeInstanceOf(FunctionCall::class)
176+
->and($result->generation->message->toolCalls[0]->function->name)
177+
->toBe(SchemaTool::NAME);
196178
});
197179

198180
test('it can stream with structured output', function (): void {

0 commit comments

Comments
 (0)