Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions examples/messages_multi_turn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env php

<?php

/**
* Multi-Turn Conversation
*
* This example demonstrates how to maintain a multi-turn conversation
* with Claude by accumulating messages in a history array.
*
* Key concepts:
* - Messages alternate between 'user' and 'assistant' roles
* - The full conversation history is sent with each request
* - Claude uses the entire history for context when generating responses
* - System prompts can set persistent behavior across all turns
*/

require_once dirname(__DIR__).'/vendor/autoload.php';

use Anthropic\Client;
use Anthropic\Messages\TextBlock;

$client = new Client(
apiKey: getenv('ANTHROPIC_API_KEY') ?: 'my-anthropic-api-key'
);

// ── System prompt for persistent instructions ───────────────────

$system = 'You are a helpful math tutor. When solving problems, show your work step-by-step. Be concise but thorough.';

// ── Simulated conversation turns ────────────────────────────────

$userTurns = [
'What is the derivative of x^3 + 2x^2 - 5x + 3?',
'Now find the second derivative.',
'At what values of x is the original function concave up?',
];

$messages = [];

foreach ($userTurns as $turn) {
echo "User: {$turn}\n\n";

// Add the user message to history
$messages[] = ['role' => 'user', 'content' => $turn];

// Send the full conversation history
$response = $client->messages->create(
maxTokens: 1024,
messages: $messages,
model: 'claude-sonnet-4-5-20250929',
system: $system,
);

// Extract the text response
$assistantText = '';
foreach ($response->content as $block) {
if ($block instanceof TextBlock) {
$assistantText .= $block->text;
}
}

echo "Claude: {$assistantText}\n";
echo str_repeat('─', 60) . "\n\n";

// Add the assistant response to history for the next turn
$messages[] = ['role' => 'assistant', 'content' => $assistantText];
}

echo "[Conversation completed: " . count($messages) . " messages]\n";
echo "[Final token usage: {$response->usage->inputTokens} input, {$response->usage->outputTokens} output]\n";
113 changes: 113 additions & 0 deletions examples/messages_thinking.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env php

<?php

/**
* Extended Thinking
*
* This example demonstrates Claude's extended thinking capability, which
* allows the model to reason through complex problems before responding.
*
* Key concepts:
* - Enable thinking with ThinkingConfigEnabled or ThinkingConfigAdaptive
* - budget_tokens must be >= 1024 and less than max_tokens (for enabled mode)
* - The response contains ThinkingBlock(s) with the model's reasoning
* - Thinking blocks appear before the final text response
* - Adaptive thinking is recommended for claude-opus-4 and lets the model
* decide how much thinking budget to use
*
* @see https://docs.claude.com/en/docs/build-with-claude/extended-thinking
*/

require_once dirname(__DIR__).'/vendor/autoload.php';

use Anthropic\Client;
use Anthropic\Messages\RedactedThinkingBlock;
use Anthropic\Messages\TextBlock;
use Anthropic\Messages\ThinkingBlock;
use Anthropic\Messages\ThinkingConfigAdaptive;
use Anthropic\Messages\ThinkingConfigEnabled;

$client = new Client(
apiKey: getenv('ANTHROPIC_API_KEY') ?: 'my-anthropic-api-key'
);

// ── Example 1: Enabled thinking with explicit budget ────────────

echo "=== Enabled Thinking (Explicit Budget) ===\n\n";

$response = $client->messages->create(
maxTokens: 16000,
messages: [
[
'role' => 'user',
'content' => 'A farmer has a rectangular field. If he increases the length by 3 meters '
.'and decreases the width by 2 meters, the area stays the same. If he increases the '
.'length by 2 meters and increases the width by 3 meters, the area increases by 52 '
.'square meters. What are the original dimensions of the field?',
],
],
model: 'claude-sonnet-4-5-20250929',
thinking: ThinkingConfigEnabled::with(budgetTokens: 10000),
);

// ── Process response blocks ─────────────────────────────────────

foreach ($response->content as $block) {
if ($block instanceof ThinkingBlock) {
echo "── Thinking ──\n";
// Show a preview of the thinking process
$preview = substr($block->thinking, 0, 500);
echo $preview;
if (strlen($block->thinking) > 500) {
echo "\n... [" . strlen($block->thinking) . " chars total]\n";
}
echo "\n\n";
}

if ($block instanceof RedactedThinkingBlock) {
echo "── Redacted Thinking ──\n";
echo "[This thinking block was redacted for safety]\n\n";
}

if ($block instanceof TextBlock) {
echo "── Response ──\n";
echo $block->text . "\n\n";
}
}

echo "[Stop reason: {$response->stopReason}]\n";
echo "[Token usage: {$response->usage->inputTokens} input, {$response->usage->outputTokens} output]\n\n";

// ── Example 2: Adaptive thinking ────────────────────────────────

echo "=== Adaptive Thinking ===\n\n";
echo "Adaptive thinking lets the model decide how much thinking budget\n";
echo "to use. Recommended for claude-opus-4 models.\n\n";

$response = $client->messages->create(
maxTokens: 8000,
messages: [
[
'role' => 'user',
'content' => 'What is 27 * 453?',
],
],
model: 'claude-sonnet-4-5-20250929',
thinking: ThinkingConfigAdaptive::with(),
);

foreach ($response->content as $block) {
if ($block instanceof ThinkingBlock) {
echo "── Thinking ──\n";
echo $block->thinking . "\n\n";
}

if ($block instanceof TextBlock) {
echo "── Response ──\n";
echo $block->text . "\n\n";
}
}

echo "[Stop reason: {$response->stopReason}]\n";
echo "[Token usage: {$response->usage->inputTokens} input, {$response->usage->outputTokens} output]\n";
148 changes: 148 additions & 0 deletions examples/messages_tool_use.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/usr/bin/env php

<?php

/**
* Tool Use: Agentic Loop
*
* This example demonstrates the complete tool use flow with the Messages API:
* 1. Define tools with JSON schema for input validation
* 2. Send a request that may trigger tool use
* 3. Detect tool_use blocks in the response
* 4. Execute the tool locally and return tool_result
* 5. Continue the conversation until the model produces a final answer
*
* This pattern is the foundation for building AI agents that can
* interact with external systems (APIs, databases, file systems, etc.).
*/

require_once dirname(__DIR__).'/vendor/autoload.php';

use Anthropic\Client;
use Anthropic\Messages\TextBlock;
use Anthropic\Messages\ToolUseBlock;

$client = new Client(
apiKey: getenv('ANTHROPIC_API_KEY') ?: 'my-anthropic-api-key'
);

// ── Define tools ────────────────────────────────────────────────

$tools = [
[
'name' => 'get_weather',
'description' => 'Get the current weather in a given location. Returns temperature in Fahrenheit and a brief description of conditions.',
'input_schema' => [
'type' => 'object',
'properties' => [
'location' => [
'type' => 'string',
'description' => 'The city and state, e.g. "San Francisco, CA"',
],
'unit' => [
'type' => 'string',
'enum' => ['celsius', 'fahrenheit'],
'description' => 'Temperature unit (defaults to fahrenheit)',
],
],
'required' => ['location'],
],
],
[
'name' => 'get_time',
'description' => 'Get the current time in a given timezone.',
'input_schema' => [
'type' => 'object',
'properties' => [
'timezone' => [
'type' => 'string',
'description' => 'The IANA timezone name, e.g. "America/New_York"',
],
],
'required' => ['timezone'],
],
],
];

// ── Simulate tool execution ─────────────────────────────────────

/**
* Process a tool call and return the result string.
*
* In a real application, these would call actual APIs or services.
*/
function executeTool(string $name, array $input): string
{
return match ($name) {
'get_weather' => json_encode([
'location' => $input['location'],
'temperature' => 72,
'unit' => $input['unit'] ?? 'fahrenheit',
'conditions' => 'Sunny with light clouds',
'humidity' => '45%',
]),
'get_time' => json_encode([
'timezone' => $input['timezone'],
'time' => '2025-03-25T14:30:00',
'day_of_week' => 'Tuesday',
]),
default => json_encode(['error' => "Unknown tool: {$name}"]),
};
}

// ── Agentic loop ────────────────────────────────────────────────

$messages = [
['role' => 'user', 'content' => 'What\'s the weather like in San Francisco and what time is it in New York?'],
];

echo "User: {$messages[0]['content']}\n\n";

// The model may need multiple turns to call all necessary tools
while (true) {
$response = $client->messages->create(
maxTokens: 1024,
messages: $messages,
model: 'claude-sonnet-4-5-20250929',
tools: $tools,
);

// Collect tool results from this turn
$toolResults = [];

foreach ($response->content as $block) {
if ($block instanceof TextBlock) {
echo "Claude: {$block->text}\n";
}

if ($block instanceof ToolUseBlock) {
echo "[Tool call: {$block->name}(" . json_encode($block->input) . ")]\n";

// Execute the tool and collect the result
$result = executeTool($block->name, $block->input);
echo "[Tool result: {$result}]\n\n";

$toolResults[] = [
'type' => 'tool_result',
'tool_use_id' => $block->id,
'content' => $result,
];
}
}

// If the model stopped for tool use, feed results back and continue
if ($response->stopReason === 'tool_use') {
// Add the assistant's response (with tool_use blocks) to history
$messages[] = ['role' => 'assistant', 'content' => $response->content];
// Add all tool results in a single user message
$messages[] = ['role' => 'user', 'content' => $toolResults];

continue;
}

// Model produced a final answer — we're done
break;
}

echo "\n[Stop reason: {$response->stopReason}]\n";
echo "[Token usage: {$response->usage->inputTokens} input, {$response->usage->outputTokens} output]\n";
Loading