Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build LLM-powered apps with the Anthropic Claude API or SDK across Python, TypeScript, Java, Go, Ruby, C#, and PHP.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
php/claude-api/tool-use.md
1# Tool Use — PHP23For conceptual overview (tool definitions, tool choice, tips), see [shared/tool-use-concepts.md](../../shared/tool-use-concepts.md).45## Tool Use67### Tool Runner (Beta)89**Beta:** The PHP SDK provides a tool runner via `$client->beta->messages->toolRunner()`. Define tools with `BetaRunnableTool` — a definition array plus a `run` closure:1011```php12use Anthropic\Lib\Tools\BetaRunnableTool;1314$weatherTool = new BetaRunnableTool(15definition: [16'name' => 'get_weather',17'description' => 'Get the current weather for a location.',18'inputSchema' => [19'type' => 'object',20'properties' => [21'location' => ['type' => 'string', 'description' => 'City and state'],22],23'required' => ['location'],24],25],26run: function (array $input): string {27return "The weather in {$input['location']} is sunny and 72°F.";28},29);3031$runner = $client->beta->messages->toolRunner(32maxTokens: 16000,33messages: [['role' => 'user', 'content' => 'What is the weather in Paris?']],34model: 'claude-opus-4-8',35tools: [$weatherTool],36);3738foreach ($runner as $message) {39foreach ($message->content as $block) {40if ($block->type === 'text') {41echo $block->text;42}43}44}45```4647### Manual Loop4849Tools are passed as arrays. **The SDK uses camelCase keys** (`inputSchema`, `toolUseID`, `stopReason`) and auto-maps to the API's snake_case on the wire — since v0.5.0. See [shared tool use concepts](../../shared/tool-use-concepts.md) for the loop pattern.5051```php52use Anthropic\Messages\ToolUseBlock;5354$tools = [55[56'name' => 'get_weather',57'description' => 'Get the current weather in a given location',58'inputSchema' => [ // camelCase, not input_schema59'type' => 'object',60'properties' => [61'location' => ['type' => 'string', 'description' => 'City and state'],62],63'required' => ['location'],64],65],66];6768$messages = [['role' => 'user', 'content' => 'What is the weather in SF?']];6970$response = $client->messages->create(71model: 'claude-opus-4-8',72maxTokens: 16000,73tools: $tools,74messages: $messages,75);7677while ($response->stopReason === 'tool_use') { // camelCase property78$toolResults = [];79foreach ($response->content as $block) {80if ($block instanceof ToolUseBlock) {81// $block->name : string — tool name to dispatch on82// $block->input : array<string,mixed> — parsed JSON input83// $block->id : string — pass back as toolUseID84$result = executeYourTool($block->name, $block->input);85$toolResults[] = [86'type' => 'tool_result',87'toolUseID' => $block->id, // camelCase, not tool_use_id88'content' => $result,89];90}91}9293// Append assistant turn + user turn with tool results94$messages[] = ['role' => 'assistant', 'content' => $response->content];95$messages[] = ['role' => 'user', 'content' => $toolResults];9697$response = $client->messages->create(98model: 'claude-opus-4-8',99maxTokens: 16000,100tools: $tools,101messages: $messages,102);103}104105// Final text response106foreach ($response->content as $block) {107if ($block->type === 'text') {108echo $block->text;109}110}111```112113`$block->type === 'tool_use'` also works; `instanceof ToolUseBlock` narrows for PHPStan.114115116---117118## Structured Outputs119120### Using StructuredOutputModel (Recommended)121122Define a PHP class implementing `StructuredOutputModel` and pass it as `outputConfig`:123124```php125use Anthropic\Lib\Contracts\StructuredOutputModel;126use Anthropic\Lib\Concerns\StructuredOutputModelTrait;127use Anthropic\Lib\Attributes\Constrained;128129class Person implements StructuredOutputModel130{131use StructuredOutputModelTrait;132133#[Constrained(description: 'Full name')]134public string $name;135136public int $age;137138public ?string $email = null; // nullable = optional field139}140141$message = $client->messages->create(142model: 'claude-opus-4-8',143maxTokens: 16000,144messages: [['role' => 'user', 'content' => 'Generate a profile for Alice, age 30']],145outputConfig: ['format' => Person::class],146);147148$person = $message->parsedOutput(); // Person instance149echo $person->name;150```151152Types are inferred from PHP type hints. Use `#[Constrained(description: '...')]` to add descriptions. Nullable properties (`?string`) become optional fields.153154### Raw Schema155156```php157$message = $client->messages->create(158model: 'claude-opus-4-8',159maxTokens: 16000,160messages: [['role' => 'user', 'content' => 'Extract: John ([email protected]), Enterprise plan']],161outputConfig: [162'format' => [163'type' => 'json_schema',164'schema' => [165'type' => 'object',166'properties' => [167'name' => ['type' => 'string'],168'email' => ['type' => 'string'],169'plan' => ['type' => 'string'],170],171'required' => ['name', 'email', 'plan'],172'additionalProperties' => false,173],174],175],176);177178// First text block contains valid JSON179foreach ($message->content as $block) {180if ($block->type === 'text') {181$data = json_decode($block->text, true);182break;183}184}185```186187---188189## Beta Features & Anthropic-Defined Tools190191**`betas:` is NOT a param on `$client->messages->create()`** — it only exists on the beta namespace. Use it for features that need an explicit opt-in header:192193```php194use Anthropic\Beta\Messages\BetaRequestMCPServerURLDefinition;195196$response = $client->beta->messages->create(197model: 'claude-opus-4-8',198maxTokens: 16000,199mcpServers: [200BetaRequestMCPServerURLDefinition::with(201name: 'my-server',202url: 'https://example.com/mcp',203),204],205betas: ['mcp-client-2025-11-20'], // only valid on ->beta->messages206messages: [['role' => 'user', 'content' => 'Use the MCP tools']],207);208```209210### Task budgets211212```php213$response = $client->beta->messages->create(214model: 'claude-opus-4-8',215maxTokens: 16000,216outputConfig: ['taskBudget' => ['type' => 'tokens', 'total' => 64000]],217tools: [...],218messages: [...],219betas: ['task-budgets-2026-03-13'],220);221```222223### Cache diagnostics224225Pass the previous response's `id` on the next request; print the `diagnostics` object on the response:226227```php228$r2 = $client->beta->messages->create(229model: 'claude-opus-4-8', maxTokens: 1024,230diagnostics: ['previousMessageId' => $r1->id],231betas: ['cache-diagnosis-2026-04-07'],232messages: [...],233);234```235236**Anthropic-defined tools** (bash, web_search, text_editor, code_execution) are GA and work on both paths. Of these, web_search and code_execution are server-executed; bash and text_editor are client-executed (you handle the `tool_use` locally) — `Anthropic\Messages\ToolBash20250124` / `WebSearchTool20260209` / `ToolTextEditor20250728` / `CodeExecutionTool20260120` for non-beta, `Anthropic\Beta\Messages\BetaToolBash20250124` / `BetaWebSearchTool20260209` / `BetaToolTextEditor20250728` / `BetaCodeExecutionTool20260120` for beta. No `betas:` header needed for these.237238### Tool search (non-beta, server-side)239240```php241tools: [242['type' => 'tool_search_tool_regex_20251119', 'name' => 'tool_search_tool_regex'],243['name' => 'get_weather', 'description' => '...', 'inputSchema' => [...], 'deferLoading' => true],244// ... other user tools with 'deferLoading' => true245],246```247248### Memory tool (non-beta, client-executed)249250Declare `['type' => 'memory_20250818', 'name' => 'memory']`. Handle the `tool_use` by reading/writing files under a fixed `/memories` directory. **Validate every model-supplied path**: resolve to its canonical form and verify it remains within the memory directory; reject traversal (`..`, symlinks) — see `shared/tool-use-concepts.md` § Client-Side Tools.251252---253254