Skip to content

Commit 6412385

Browse files
committed
wip
1 parent 0edf180 commit 6412385

File tree

6 files changed

+25
-48
lines changed

6 files changed

+25
-48
lines changed

docs/core-concepts/structured-output.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ $response = Prism::structured()
8080
->using(Provider::Anthropic, 'claude-3-5-sonnet-latest')
8181
->withSchema($schema)
8282
->withPrompt('天氣怎麼樣?應該穿什麼?') // Chinese text with potential quotes
83-
->withProviderOptions(['useToolCalling' => true])
83+
->withProviderOptions(['use_tool_calling' => true])
8484
->asStructured();
8585
```
8686

docs/providers/anthropic.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ $response = Prism::structured()
321321
))
322322
->using(Provider::Anthropic, 'claude-3-5-sonnet-latest')
323323
->withPrompt('What\'s the weather like and what should I wear?')
324-
->withProviderOptions(['useToolCalling' => true])
324+
->withProviderOptions(['use_tool_calling' => true])
325325
->asStructured();
326326
```
327327

src/Providers/Anthropic/Handlers/Structured.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,14 @@ public static function buildHttpRequestPayload(PrismRequest $request): array
104104
}
105105

106106
// Validate options
107-
if ($request->providerOptions('citations') === true && $request->providerOptions('useToolCalling') === true) {
107+
if ($request->providerOptions('citations') === true && $request->providerOptions('use_tool_calling') === true) {
108108
throw new InvalidArgumentException(
109109
'Citations are not supported with tool calling mode. '.
110-
'Please set useToolCalling to false in provider options to use citations.'
110+
'Please set use_tool_calling to false in provider options to use citations.'
111111
);
112112
}
113113

114-
if ($request->providerOptions('useToolCalling') === true) {
114+
if ($request->providerOptions('use_tool_calling') === true) {
115115
return static::buildToolCallingPayload($request);
116116
}
117117

@@ -294,15 +294,15 @@ protected function appendMessageForJsonMode(): void
294294

295295
protected function shouldUseToolCalling(): bool
296296
{
297-
return $this->request->providerOptions('useToolCalling') === true;
297+
return $this->request->providerOptions('use_tool_calling') === true;
298298
}
299299

300300
protected function validateProviderOptions(): void
301301
{
302302
if ($this->request->providerOptions('citations') === true && $this->shouldUseToolCalling()) {
303303
throw new InvalidArgumentException(
304304
'Citations are not supported with tool calling mode. '.
305-
'Please set useToolCalling to false in provider options to use citations.'
305+
'Please set use_tool_calling to false in provider options to use citations.'
306306
);
307307
}
308308
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"id":"msg_01JPJ5MQFAzwGVKYEdXNrbuj","type":"message","role":"assistant","model":"claude-3-5-sonnet-20241022","content":[{"type":"text","text":"{\"answer\":\"4\"}"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":133,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":8,"service_tier":"standard"}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"id":"msg_01C18DoP6GQnCr5MeFMmb5Ct","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[{"type":"thinking","thinking":"The user is asking about the meaning of life, the universe and everything in popular fiction, and has requested that I use the output_structured_data tool to provide my response. The tool requires two parameters:\n\n1. __thinking: My step-by-step thinking process before the final answer\n2. answer: The answer to the question\n\nI'll use this tool to provide a structured response with my thinking and the actual answer about the meaning of life, the universe and everything in popular fiction.","signature":"ErUBCkYIBBgCIkCte3T9EOqQs/ZYVb3vbKahSgsGiqDVAptqxBpF025YvLk7dxcrC1IV1JUN7RsbKu5vSkCG5hz0XVfz/jWeUWF/EgyrhDKOyC/L8KLZ/vUaDGXEN87A7YR0iumwnyIw3o7kmucxsBqNEES99F9RHvl57/JrazWos+iGi/H1rZlOTGsU1rUOgHIvdvpzluGbKh1Yj+IcRJdNaFnwnpBRxBixs8Czm/d2l7wjXn77tBgC"},{"type":"tool_use","id":"toolu_01TbLD6zV81QMsm92766kXHh","name":"output_structured_data","input":{"__thinking":"The question about \"the meaning of life, the universe and everything\" is a direct reference to Douglas Adams' science fiction series \"The Hitchhiker's Guide to the Galaxy,\" where this exact phrase is used. In the story, a supercomputer named Deep Thought is built to calculate the answer to this ultimate question. After 7.5 million years of computation, it provides the famous answer: 42. However, the computer explains that the answer seems meaningless because the beings who asked didn't actually understand the question itself. This has become one of the most recognized references in science fiction and popular culture. Beyond Adams' work, the meaning of life has been explored in many other fictional works, often with humorous, philosophical, or existential perspectives.","answer":"In popular fiction, the most famous answer to \"the meaning of life, the universe and everything\" is \"42,\" as established in Douglas Adams' \"The Hitchhiker's Guide to the Galaxy.\" In this comedic science fiction series, a supercomputer called Deep Thought calculates this seemingly nonsensical answer after 7.5 million years, only to explain that the beings who asked didn't properly understand their own question. This answer has become a cultural touchstone, representing both the absurdity of seeking simple answers to profound questions and the often humorous futility of such cosmic inquiries. Beyond Adams' work, fiction has explored this question in countless ways—from Kurt Vonnegut's fatalistic \"so it goes\" in Slaughterhouse-Five to more optimistic perspectives in works like \"The Good Place\" that suggest meaning comes from human connections and moral growth."}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":603,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":524,"service_tier":"standard"}}

tests/Providers/Anthropic/StructuredTest.php

Lines changed: 16 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,17 @@
218218
->withSchema($schema)
219219
->using(Provider::Anthropic, 'claude-3-5-sonnet-latest')
220220
->withPrompt('What is the answer?')
221-
->withProviderOptions(['citations' => true, 'useToolCalling' => true])
221+
->withProviderOptions(['citations' => true, 'use_tool_calling' => true])
222222
->asStructured()
223223
)->toThrow(InvalidArgumentException::class, 'Citations are not supported with tool calling mode');
224224
});
225225

226226
it('returns structured output with default JSON mode', function (): void {
227+
FixtureResponse::fakeResponseSequence(
228+
'v1/messages',
229+
'anthropic/structured-with-default-json'
230+
);
231+
227232
$schema = new ObjectSchema('output', 'the output object', [
228233
new StringSchema('answer', 'A simple answer'),
229234
], ['answer']);
@@ -237,9 +242,14 @@
237242
expect($response->structured)->toBeArray();
238243
expect($response->structured)->toHaveKey('answer');
239244
expect($response->structured['answer'])->toBeString();
240-
})->skip(fn (): bool => ! env('ANTHROPIC_API_KEY'), 'Skipping live test - ANTHROPIC_API_KEY environment variable is not configured. Set your API key to run this test.');
245+
});
246+
247+
it('works with thinking mode when use_tool_calling is true', function (): void {
248+
FixtureResponse::fakeResponseSequence(
249+
'v1/messages',
250+
'anthropic/structured-with-use-tool-calling'
251+
);
241252

242-
it('works with thinking mode when useToolCalling is true', function (): void {
243253
$schema = new ObjectSchema('output', 'the output object', [
244254
new StringSchema('answer', 'The answer about life, universe and everything'),
245255
], ['answer']);
@@ -249,7 +259,7 @@
249259
->using(Provider::Anthropic, 'claude-3-7-sonnet-latest')
250260
->withSystemPrompt('You are a helpful assistant.')
251261
->withPrompt('What is the meaning of life, the universe and everything in popular fiction?')
252-
->withProviderOptions(['thinking' => ['enabled' => true], 'useToolCalling' => true])
262+
->withProviderOptions(['thinking' => ['enabled' => true], 'use_tool_calling' => true])
253263
->asStructured();
254264

255265
expect($response->structured)->toBeArray();
@@ -262,7 +272,7 @@
262272

263273
// Check that __thinking is not in structured data (it should be moved to additionalContent)
264274
expect($response->structured)->not->toHaveKey('__thinking');
265-
})->skip(fn (): bool => ! env('ANTHROPIC_API_KEY'), 'Skipping live test - ANTHROPIC_API_KEY environment variable is not configured. Set your API key to run this test.');
275+
});
266276

267277
it('handles Chinese output with double quotes using tool calling', function (): void {
268278
FixtureResponse::fakeResponseSequence('v1/messages', 'anthropic/structured-chinese-tool-calling');
@@ -283,7 +293,7 @@
283293
->using(Provider::Anthropic, 'claude-3-5-sonnet-latest')
284294
->withSystemPrompt('Respond in Chinese. Use double quotes around temperature values and clothing items.')
285295
->withPrompt('What is the weather like today and what should I wear? The temperature is 15°C.')
286-
->withProviderOptions(['useToolCalling' => true])
296+
->withProviderOptions(['use_tool_calling' => true])
287297
->asStructured();
288298

289299
expect($response->structured)->toBeArray();
@@ -302,38 +312,3 @@
302312
expect($response->structured['recommendation'])->toContain('建議');
303313
expect($response->structured['coat_required'])->toBe(true);
304314
});
305-
306-
it('handles Chinese output with double quotes using tool calling (live test)', function (): void {
307-
$schema = new ObjectSchema(
308-
'output',
309-
'the output object',
310-
[
311-
new StringSchema('weather', 'The weather forecast in Chinese with double quotes for temperature'),
312-
new StringSchema('recommendation', 'Clothing recommendation in Chinese with quoted items'),
313-
new BooleanSchema('coat_required', 'whether a coat is required'),
314-
],
315-
['weather', 'recommendation', 'coat_required']
316-
);
317-
318-
$response = Prism::structured()
319-
->withSchema($schema)
320-
->using(Provider::Anthropic, 'claude-3-5-sonnet-latest')
321-
->withSystemPrompt('Respond in Chinese. Use double quotes around temperature values and clothing items.')
322-
->withPrompt('What is the weather like today and what should I wear? The temperature is 15°C.')
323-
->withProviderOptions(['useToolCalling' => true])
324-
->asStructured();
325-
326-
expect($response->structured)->toBeArray();
327-
expect($response->structured)->toHaveKeys([
328-
'weather',
329-
'recommendation',
330-
'coat_required',
331-
]);
332-
expect($response->structured['weather'])->toBeString();
333-
expect($response->structured['recommendation'])->toBeString();
334-
expect($response->structured['coat_required'])->toBeBool();
335-
336-
// Verify that Chinese text with quotes is properly handled
337-
expect($response->structured['weather'])->toContain('°C');
338-
expect($response->structured['recommendation'])->toBeString();
339-
})->skip(fn (): bool => ! env('ANTHROPIC_API_KEY'), 'Skipping live test - ANTHROPIC_API_KEY environment variable is not configured. Set your API key to run this test.');

0 commit comments

Comments
 (0)