neosoftware/anthropic-claude-sdk

PHP SDK для Claude Agent (Claude Code). Порт пакета @anthropic-ai/claude-agent-sdk (TypeScript).

Maintainers

Package info

github.com/NEOSoftWare/anthropic-claude-sdk

pkg:composer/neosoftware/anthropic-claude-sdk

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-06-05 10:52 UTC

This package is auto-updated.

Last update: 2026-06-05 11:14:28 UTC


README

A PHP 8.2 SDK for working with Claude Agent (Claude Code).
A port of the @anthropic-ai/claude-agent-sdk package (TypeScript).

Requirements

  • PHP 8.2+
  • Composer

Installation

composer require neosoftware/anthropic-claude-sdk

Claude binary

The SDK runs claude (Claude Code CLI) as a subprocess. Specify the path to it in one of the following ways:

Via QueryOptions — explicitly for a specific agent:

new QueryOptions(claudePathOverride: '/usr/local/bin/claude')

Via an environment variable — globally for the entire application:

CLAUDE_PATH=/usr/local/bin/claude php artisan ...

Installation into vendor/bin — convenient for containers and servers where Claude Code is not installed globally. The command downloads the binary for your platform from npm and adds the vendor/bin/claude symlink:

vendor/bin/install-claude

allow-plugins permissions are not required.

Quick start

<?php
require 'vendor/autoload.php';

use Anthropic\ClaudeAgent\ClaudeAgent;
use Anthropic\ClaudeAgent\Types\Options\QueryOptions;

$agent = new ClaudeAgent(new QueryOptions(
    apiKey: $_ENV['ANTHROPIC_API_KEY'],
));

$result = $agent->run('Explain what the array_chunk function does in PHP.');

echo $result->result;

Initialization

new ClaudeAgent(QueryOptions $options = new QueryOptions())

Creates the main SDK object. On the first query() / run() call, it automatically finds and starts the claude CLI.

$agent = new ClaudeAgent(new QueryOptions(
    apiKey:             'sk-ant-...',           // Anthropic API key (or ANTHROPIC_API_KEY env)
    model:              'claude-sonnet-4-6',     // model (optional)
    claudePathOverride: '/usr/local/bin/claude', // custom path to claude (optional)
));

QueryOptions

Property Type Default Description
apiKey ?string null Anthropic API key (passed as ANTHROPIC_API_KEY)
model ?string null Claude model (claude-sonnet-4-6, claude-opus-4-7, …)
cwd ?string null Process working directory
allowedTools ?string[] null Tools allowed without confirmation
disallowedTools ?string[] null Disallowed tools
tools ?string[] null Explicit list of available tools
permissionMode ?string null 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan' | 'dontAsk'
maxTurns ?int null Maximum number of turns
maxBudgetUsd ?float null Maximum budget in USD
resume ?string null Session ID for resuming a previous conversation
continue bool false Continue the last conversation in cwd
sessionId ?string null Use a specific session UUID
additionalDirectories ?string[] null Additional directories (--add-dir)
mcpServers ?array null MCP servers: name → configuration
persistSession bool true Save the session to disk
maxThinkingTokens ?int null Token limit for thinking; deprecated, use thinking
effort ?string null 'low' | 'medium' | 'high' | 'xhigh' | 'max'
thinking ?array null {type: 'adaptive'} / {type: 'enabled', budgetTokens: N} / {type: 'disabled'}
fallbackModel ?string null Fallback model
betas ?string[] null Beta features, for example 'context-1m-2025-08-07'
agent ?string null Agent name for the main thread
allowDangerouslySkipPermissions bool false Skip all permission checks
permissionPromptToolName ?string null MCP tool for permission prompts
forkSession bool false Fork the session when resuming
resumeSessionAt ?string null Message UUID to resume up to
includeHookEvents bool false Include hook events in the stream
includePartialMessages bool false Include partial streaming messages
verbose bool false Verbose output
outputFormat ?array null Structured output configuration
settings string|array|null null Settings: JSON path or object
taskBudget ?array null Task budget in tokens, ['total' => N]
plugins ?array null Plugins: [['type' => 'local', 'path' => '...']]
extraArgs ?array null Arbitrary additional CLI arguments
env ?array null Environment variables. If set, the subprocess receives only these variables
claudePathOverride ?string null Absolute path to a custom claude binary
clientApp ?string null Application identifier (→ CLAUDE_AGENT_SDK_CLIENT_APP)
timeoutSeconds ?int null Response timeout in seconds

Running queries

query() — streaming

Returns Query immediately. Messages are read as they arrive through a generator.

$query = $agent->query('Check all tests and fix the errors');

foreach ($query->messages() as $msg) {
    match (true) {
        $msg instanceof SDKSystemMessage  => printf("[init] Model: %s\n", $msg->model),
        $msg instanceof SDKAssistantMessage => printf("%s\n", $msg->getText()),
        $msg instanceof SDKResultSuccess  => printf("Tokens: %d\n", $msg->usage->outputTokens),
        default => null,
    };
}

query()->collect() — blocking collection

$result = $agent->query('Task')->collect();
echo $result->result;

run() — shortened blocking call

$result = $agent->run('Explain this code');
echo $result->result;

Query

$query = $agent->query('prompt');

// Streaming through a generator
foreach ($query->messages() as $msg) { ... }

// Blocking collection of the final response (throws ResultErrorException on error)
$result = $query->collect(); // QueryResult

QueryResult

Property Type Description
result string Final assistant text response
sessionId string Session UUID
resultMessage ?SDKResultSuccess Full object with tokens and cost

Message types (SDKMessage)

The Query::messages() generator returns objects of the following classes:

SDKSystemMessage (type: 'system', subtype: 'init')

The first message in the stream. Contains session information.

$msg->sessionId;         // string — session UUID
$msg->model;             // string — active model
$msg->permissionMode;    // string — permission mode
$msg->claudeCodeVersion; // string — Claude Code version
$msg->tools;             // string[] — available tools
$msg->cwd;               // string — working directory

SDKAssistantMessage (type: 'assistant')

A complete assistant response.

$msg->getText();          // string — text content (convenience method)
$msg->message;            // array  — full BetaMessage object
$msg->error;              // ?string — API error, if any
$msg->uuid;               // string
$msg->sessionId;          // string

SDKUserMessage (type: 'user')

A user message, including replay from history.

$msg->message;    // array
$msg->isReplay;   // bool
$msg->isSynthetic; // bool

SDKResultSuccess (type: 'result', subtype: 'success')

Final successful completion message.

$msg->result;         // string — final response text
$msg->usage;          // Usage — tokens
$msg->totalCostUsd;   // float — cost in USD
$msg->numTurns;       // int — number of turns
$msg->durationMs;     // int — execution time
$msg->sessionId;      // string
$msg->structuredOutput; // mixed — if outputFormat was used

SDKResultError (type: 'result', subtype: 'error_*')

Final error message.

$msg->subtype;  // 'error_during_execution'|'error_max_turns'|'error_max_budget_usd'|...
$msg->errors;   // string[]
$msg->usage;    // Usage

SDKAPIRetryMessage (type: 'system', subtype: 'api_retry')

Notification about retrying an API request.

$msg->attempt;      // int
$msg->maxRetries;   // int
$msg->retryDelayMs; // int
$msg->errorStatus;  // ?int — error HTTP status code

SDKPartialAssistantMessage (type: 'partial_assistant')

A partial streaming response. Only when includePartialMessages: true.

GenericMessage

A fallback for unknown types. Contains raw data in $msg->data.

Usage

$msg->usage->inputTokens;               // int
$msg->usage->outputTokens;              // int
$msg->usage->cacheCreationInputTokens;  // int
$msg->usage->cacheReadInputTokens;      // int

Structured output

$result = $agent->run(
    'Return project data',
    new QueryOptions(
        outputFormat: [
            'type'   => 'json_schema',
            'schema' => [
                'type'                 => 'object',
                'additionalProperties' => false,
                'properties' => [
                    'name'    => ['type' => 'string'],
                    'version' => ['type' => 'string'],
                ],
                'required' => ['name', 'version'],
            ],
        ],
    ),
);

// With json_schema, data is in structuredOutput; the result field remains empty
$data = $result->resultMessage?->structuredOutput;
echo $data['name'];

Resuming a session

// First query — save the sessionId
$result = $agent->run('First message.');
$sessionId = $result->sessionId;

// Resume the session later
$result2 = $agent->run('What did you say last time?', new QueryOptions(
    resume: $sessionId,
));
echo $result2->result;

// Or continue the last conversation in the current directory
$result3 = $agent->run('Continue.', new QueryOptions(
    continue: true,
));

MCP servers

$result = $agent->run('List files', new QueryOptions(
    mcpServers: [
        'my-server' => [
            'command' => 'node',
            'args'    => ['./my-mcp-server.js'],
        ],
    ],
));

Error handling

use Anthropic\ClaudeAgent\Exceptions\ClaudeException;
use Anthropic\ClaudeAgent\Exceptions\ParseException;
use Anthropic\ClaudeAgent\Exceptions\ResultErrorException;
use Anthropic\ClaudeAgent\Exceptions\SpawnException;

try {
    $result = $agent->run('...');
} catch (ResultErrorException $e) {
    // Claude returned an error result (max_turns, max_budget, etc.)
    echo "Error: {$e->result->subtype}\n";
    print_r($e->result->errors);
} catch (SpawnException $e) {
    // claude CLI was not found, did not start, or hung
    echo "Startup error: " . $e->getMessage();
} catch (ParseException $e) {
    // claude returned invalid JSON in the JSONL stream
    echo "Parse error: " . $e->getMessage();
} catch (ClaudeException $e) {
    // Base class for all SDK exceptions
    echo "SDK error: " . $e->getMessage();
}
Exception When
ResultErrorException Claude returned type=result, is_error=true
SpawnException claude was not found, did not start, hung, or exited with a non-zero code
ParseException claude returned invalid JSON in the JSONL stream
ClaudeException Base class for all SDK exceptions

Full example

<?php
require 'vendor/autoload.php';

use Anthropic\ClaudeAgent\ClaudeAgent;
use Anthropic\ClaudeAgent\Exceptions\ResultErrorException;
use Anthropic\ClaudeAgent\Exceptions\SpawnException;
use Anthropic\ClaudeAgent\Types\Messages\SDKAssistantMessage;
use Anthropic\ClaudeAgent\Types\Messages\SDKResultSuccess;
use Anthropic\ClaudeAgent\Types\Messages\SDKSystemMessage;
use Anthropic\ClaudeAgent\Types\Options\QueryOptions;

$agent = new ClaudeAgent(new QueryOptions(
    apiKey:        $_ENV['ANTHROPIC_API_KEY'],
    model:         'claude-sonnet-4-6',
    maxTurns:      10,
    permissionMode: 'acceptEdits',
    cwd:           '/path/to/project',
    effort:        'high',
));

try {
    // Streaming
    $query = $agent->query('Find and fix bugs in src/Payment.php');

    foreach ($query->messages() as $msg) {
        match (true) {
            $msg instanceof SDKSystemMessage    => printf("Session: %s\n", $msg->sessionId),
            $msg instanceof SDKAssistantMessage => print($msg->getText() . "\n"),
            $msg instanceof SDKResultSuccess    => printf(
                "Done in %dms | $%.4f\n",
                $msg->durationMs,
                $msg->totalCostUsd,
            ),
            default => null,
        };
    }

    // Continue the conversation
    $result = $agent->run('Now write a test for the fixed code.');
    echo $result->result;

} catch (ResultErrorException $e) {
    echo "Error: " . $e->getMessage() . PHP_EOL;
} catch (SpawnException $e) {
    echo "Startup error: " . $e->getMessage() . PHP_EOL;
}

License

MIT