定制 mohamed-ashraf-elsaed/claude-agent-sdk-laravel 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

mohamed-ashraf-elsaed/claude-agent-sdk-laravel

Composer 安装命令:

composer require mohamed-ashraf-elsaed/claude-agent-sdk-laravel

包简介

Anthropic Claude Agent SDK for PHP & Laravel — build AI agents with tool use, sandboxing, MCP servers, subagents, hooks, and structured output via the Claude Code CLI

README 文档

README

Tests Latest Version Total Downloads PHP Version Laravel License

Build AI agents with Claude Code as a library in your Laravel applications. This SDK wraps the Claude Code CLI to give your app access to file operations, bash commands, code editing, web search, subagents, and more.

Requirements

  • PHP 8.1+
  • Laravel 10, 11, or 12 and 13
  • Claude Code CLI (npm install -g @anthropic-ai/claude-code)
  • Anthropic API key

Installation

composer require mohamed-ashraf-elsaed/claude-agent-sdk-laravel

Publish the config:

php artisan vendor:publish --tag=claude-agent-config

Add your API key to .env:

ANTHROPIC_API_KEY=your-api-key

Quick Start

Simple Query

use ClaudeAgentSDK\Facades\ClaudeAgent;

$result = ClaudeAgent::query('What files are in this directory?');

echo $result->text();       // Final text result
echo $result->costUsd();    // Cost in USD
echo $result->sessionId;    // Session ID for resuming

With Options (Fluent API)

use ClaudeAgentSDK\Options\ClaudeAgentOptions;

$options = ClaudeAgentOptions::make()
    ->tools(['Read', 'Edit', 'Bash', 'Grep', 'Glob'])
    ->permission('acceptEdits')
    ->maxTurns(10)
    ->maxBudgetUsd(5.00)
    ->cwd('/path/to/project');

$result = ClaudeAgent::query('Find and fix the bug in auth.php', $options);

if ($result->isSuccess()) {
    echo $result->text();
}

Streaming Responses

use ClaudeAgentSDK\Messages\AssistantMessage;
use ClaudeAgentSDK\Messages\ResultMessage;

foreach (ClaudeAgent::stream('Refactor the User model') as $message) {
    if ($message instanceof AssistantMessage) {
        echo $message->text();
    }

    if ($message instanceof ResultMessage) {
        echo "\nDone! Cost: $" . $message->totalCostUsd;
    }
}

Stream with Callback

$result = ClaudeAgent::streamCollect(
    prompt: 'Create a REST API for products',
    onMessage: function ($message) {
        if ($message instanceof AssistantMessage) {
            Log::info($message->text());
        }
    },
    options: ClaudeAgentOptions::make()->tools(['Read', 'Write', 'Bash']),
);

echo $result->text();

Options Reference

Fluent Builder

$options = ClaudeAgentOptions::make()
    ->tools(['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob'])
    ->disallow(['WebFetch'])
    ->model('claude-sonnet-4-5-20250929')
    ->permission('acceptEdits')
    ->maxTurns(15)
    ->maxBudgetUsd(10.00)
    ->maxThinkingTokens(8000)
    ->fallbackModel('claude-haiku-4-5')
    ->cwd('/path/to/project')
    ->env('MY_VAR', 'value')
    ->settingSources(['project'])
    ->useClaudeCodePrompt('Also follow PSR-12.')
    ->betas(['context-1m-2025-08-07'])
    ->permissionPromptToolName('my_custom_tool')
    ->resumeSessionAt('2025-01-15T10:30:00Z')
    ->allowDangerouslySkipPermissions();

From Array

$options = ClaudeAgentOptions::fromArray([
    'allowed_tools' => ['Read', 'Bash'],
    'permission_mode' => 'bypassPermissions',
    'max_turns' => 5,
    'max_budget_usd' => 5.00,
    'max_thinking_tokens' => 10000,
]);

System Prompts

// Custom string
$options->systemPrompt('You are a Laravel expert. Always use Eloquent.');

// Claude Code preset (includes default agent behavior)
$options->useClaudeCodePrompt();

// Claude Code preset with additions
$options->useClaudeCodePrompt('Follow PSR-12 and use strict types.');

Permission Modes

Mode Behavior
default Ask for permission on each tool use
acceptEdits Auto-accept file edits, ask for others
dontAsk Don't ask but log decisions
bypassPermissions Skip all permission checks
plan Create a plan but don't execute

Custom Permission Handler

For fine-grained control over tool permissions, use canUseTool() to register a callback that approves, denies, or modifies each tool invocation:

use ClaudeAgentSDK\Permissions\PermissionResultAllow;
use ClaudeAgentSDK\Permissions\PermissionResultDeny;

$options = ClaudeAgentOptions::make()
    ->canUseTool(function (string $toolName, array $input) {
        if ($toolName === 'Bash' && str_contains($input['command'] ?? '', 'rm -rf')) {
            return new PermissionResultDeny('Destructive commands not allowed');
        }
        if ($toolName === 'Write') {
            return new PermissionResultAllow(
                updatedInput: array_merge($input, ['file_path' => '/sandbox' . $input['file_path']])
            );
        }
        return new PermissionResultAllow();
    });

Return PermissionResultAllow to approve (optionally with modified input), or PermissionResultDeny with a reason to block the tool call.

Hooks

Run shell commands before or after Claude uses tools. The SDK supports all 12 hook events:

PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, Notification, SessionStart, SessionEnd, Stop, SubagentStart, SubagentStop, PreCompact, PermissionRequest

use ClaudeAgentSDK\Hooks\HookEvent;
use ClaudeAgentSDK\Hooks\HookMatcher;

$options = ClaudeAgentOptions::make()
    ->tools(['Read', 'Edit', 'Bash'])
    // Shorthand methods
    ->preToolUse('php artisan lint:check', '/Edit|Write/', 30)
    ->postToolUse('php artisan test:affected')
    // Or use hook() directly for any event
    ->hook(HookEvent::Stop, HookMatcher::command('php /hooks/cleanup.php'))
    ->hook(HookEvent::SessionStart, HookMatcher::command('php /hooks/init.php'))
    ->hook(HookEvent::SubagentStop, HookMatcher::command('php /hooks/subagent-done.php'));

$result = ClaudeAgent::query('Refactor the User model', $options);

HookMatcher Factory Methods

// From a shell command
$matcher = HookMatcher::command('eslint --fix', '/Edit|Write/', 60);

// From a PHP script
$matcher = HookMatcher::phpScript('/hooks/validate.php', '/Bash/', 10);

// Full control
$matcher = new HookMatcher(
    matcher: '/Edit|Write/',
    hooks: ['php /hooks/lint.php', 'php /hooks/backup.php'],
    timeout: 30,
);

Subagents

Define specialized agents that Claude delegates tasks to:

use ClaudeAgentSDK\Agents\AgentDefinition;

$options = ClaudeAgentOptions::make()
    ->tools(['Read', 'Grep', 'Glob', 'Task'])
    ->agent('security-reviewer', new AgentDefinition(
        description: 'Security code review specialist',
        prompt: 'You are a security expert. Find vulnerabilities in PHP/Laravel code.',
        tools: ['Read', 'Grep', 'Glob'],
        model: 'sonnet',
    ))
    ->agent('test-writer', new AgentDefinition(
        description: 'PHPUnit test writer',
        prompt: 'Write comprehensive PHPUnit tests for Laravel applications.',
        tools: ['Read', 'Write', 'Bash'],
    ));

$result = ClaudeAgent::query('Review the auth module for security issues', $options);

Structured Output

Get validated JSON responses matching a schema:

$options = ClaudeAgentOptions::make()
    ->tools(['Read', 'Grep', 'Glob'])
    ->outputFormat([
        'type' => 'object',
        'properties' => [
            'issues' => [
                'type' => 'array',
                'items' => [
                    'type' => 'object',
                    'properties' => [
                        'file' => ['type' => 'string'],
                        'line' => ['type' => 'number'],
                        'severity' => ['type' => 'string', 'enum' => ['low', 'medium', 'high']],
                        'description' => ['type' => 'string'],
                    ],
                    'required' => ['file', 'severity', 'description'],
                ],
            ],
            'total' => ['type' => 'number'],
        ],
        'required' => ['issues', 'total'],
    ]);

$result = ClaudeAgent::query('Find all TODO comments in src/', $options);
$data = $result->structured(); // Validated array matching schema

Session Resumption

Continue conversations across multiple queries:

// First query
$result = ClaudeAgent::query('Read the auth module');
$sessionId = $result->sessionId;

// Resume later with full context
$result2 = ClaudeAgent::query(
    'Now find all places that call it',
    ClaudeAgentOptions::make()->resume($sessionId),
);

// Fork a session to try different approaches
$result3 = ClaudeAgent::query(
    'Try refactoring it with a different pattern',
    ClaudeAgentOptions::make()->resume($sessionId, fork: true),
);

MCP Servers

Connect external tools via Model Context Protocol:

use ClaudeAgentSDK\Tools\McpServerConfig;

// Stdio transport
$options = ClaudeAgentOptions::make()
    ->mcpServer('database', McpServerConfig::stdio(
        command: 'npx',
        args: ['@modelcontextprotocol/server-database'],
        env: ['DB_URL' => config('database.url')],
    ))
    ->tools(['mcp__database__query', 'Read']);

$result = ClaudeAgent::query('Show me the latest users', $options);

// SSE transport
$options = ClaudeAgentOptions::make()
    ->mcpServer('api', McpServerConfig::sse(
        url: 'http://localhost:3000/mcp',
        headers: ['Authorization' => 'Bearer ' . config('services.mcp.token')],
    ));

// HTTP transport
$options = ClaudeAgentOptions::make()
    ->mcpServer('api', McpServerConfig::http(
        url: 'http://localhost:3000/mcp',
        headers: ['Authorization' => 'Bearer ' . config('services.mcp.token')],
    ));

Working with Results

$result = ClaudeAgent::query('Analyze this codebase');

// Basic info
$result->text();              // Final text result
$result->isSuccess();         // bool — true if subtype is 'success'
$result->isError();           // bool — true if error or no result
$result->costUsd();           // float|null — total cost in USD
$result->turns();             // int — number of conversation turns
$result->durationMs();        // int — total duration in milliseconds
$result->sessionId;           // string|null — for session resumption

// Error types
$result->subtype();              // 'success', 'error_max_turns', 'error_max_budget_usd', etc.
$result->isMaxTurnsError();      // true if stopped at turn limit
$result->isBudgetError();        // true if budget exceeded
$result->permissionDenials();    // array of denied tool uses
$result->errors();               // array of execution errors

// Session introspection
$result->model();                // Model used
$result->availableTools();       // Tools available
$result->mcpServerStatus();      // MCP server statuses
$result->supportedCommands();    // Available slash commands

// Messages
$result->messages;            // All Message objects
$result->assistantMessages(); // AssistantMessage[] only
$result->fullText();          // Concatenated text from all assistant messages
$result->toolUses();          // All ToolUseBlock objects across messages
$result->structured();        // Structured output array (if outputFormat set)

// Per-model usage & cache metrics
$result->modelUsage();        // array<string, ModelUsage> — per-model breakdown
$result->cacheReadTokens();   // int — total cache-read tokens across all models
$result->cacheCreationTokens(); // int — total cache-creation tokens

foreach ($result->modelUsage() as $model => $usage) {
    echo "{$model}: {$usage->inputTokens} in, {$usage->outputTokens} out\n";
    echo "  Cache hit rate: " . round($usage->cacheHitRate() * 100) . "%\n";
    echo "  Cost: \${$usage->costUsd}\n";
}

Working with Messages

use ClaudeAgentSDK\Messages\AssistantMessage;
use ClaudeAgentSDK\Messages\SystemMessage;
use ClaudeAgentSDK\Messages\ResultMessage;

foreach (ClaudeAgent::stream('Do something') as $message) {
    match (true) {
        $message instanceof SystemMessage => handleSystem($message),
        $message instanceof AssistantMessage => handleAssistant($message),
        $message instanceof ResultMessage => handleResult($message),
        default => null,
    };
}

function handleAssistant(AssistantMessage $msg): void
{
    // Text content
    echo $msg->text();

    // Tool calls made by Claude
    foreach ($msg->toolUses() as $toolUse) {
        echo "Tool: {$toolUse->name}, Input: " . json_encode($toolUse->input);
    }

    // Metadata
    echo $msg->model;            // Model used
    echo $msg->id;               // Message ID
    echo $msg->parentToolUseId;  // If this is a subagent response
}

Default Options via Config

Set defaults in config/claude-agent.php or .env:

CLAUDE_AGENT_MODEL=claude-sonnet-4-5-20250929
CLAUDE_AGENT_PERMISSION_MODE=acceptEdits
CLAUDE_AGENT_MAX_TURNS=10
CLAUDE_AGENT_MAX_BUDGET_USD=10.00
CLAUDE_AGENT_MAX_THINKING_TOKENS=8000
CLAUDE_AGENT_CWD=/var/www/project
CLAUDE_AGENT_TIMEOUT=300
CLAUDE_AGENT_CLI_PATH=/usr/local/bin/claude

Options passed to query() override config defaults.

Advanced: Sandbox, Plugins & Betas

// Run in a sandboxed environment with command isolation
$options = ClaudeAgentOptions::make()
    ->sandbox([
        'enabled' => true,
        'autoAllowBashIfSandboxed' => true,
        'excludedCommands' => ['docker'],
        'network' => [
            'allowLocalBinding' => true,
            'allowUnixSockets' => ['/var/run/docker.sock'],
        ],
    ]);

// Load a local plugin
$options = ClaudeAgentOptions::make()
    ->plugin('/path/to/my-plugin');

// Enable beta features
$options = ClaudeAgentOptions::make()
    ->betas(['context-1m-2025-08-07']);

// Set a fallback model
$options = ClaudeAgentOptions::make()
    ->model('claude-sonnet-4-5-20250929')
    ->fallbackModel('claude-haiku-4-5');

Stderr Monitoring

Capture diagnostic output from the Claude CLI process:

$options = ClaudeAgentOptions::make()
    ->stderr(function (string $data) {
        Log::warning('Claude CLI stderr: ' . $data);
    });

Interrupt & Lifecycle

Control a running Claude process programmatically:

$manager = app('claude-agent');
$manager->interrupt();    // Graceful interrupt (sends SIGINT to the process)
$manager->isRunning();    // Check if a process is currently running

Error Handling

use ClaudeAgentSDK\Exceptions\CliNotFoundException;
use ClaudeAgentSDK\Exceptions\ProcessException;
use ClaudeAgentSDK\Exceptions\JsonParseException;
use ClaudeAgentSDK\Exceptions\ClaudeAgentException;

try {
    $result = ClaudeAgent::query('Do something');
} catch (CliNotFoundException $e) {
    // Claude Code CLI not installed
    // $e->getMessage() includes install instructions
} catch (ProcessException $e) {
    echo $e->exitCode;   // Process exit code
    echo $e->stderr;     // Standard error output
} catch (JsonParseException $e) {
    echo $e->rawLine;    // The malformed JSON line
    echo $e->originalError; // The underlying JsonException
} catch (ClaudeAgentException $e) {
    // General SDK error
}

Testing

composer test

To run with coverage:

vendor/bin/phpunit --coverage-html coverage/

Support

If you find this package useful, please consider giving it a star on GitHub. It helps others discover the package and motivates continued development.

GitHub stars

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

MIT — see LICENSE for details.

mohamed-ashraf-elsaed/claude-agent-sdk-laravel 适用场景与选型建议

mohamed-ashraf-elsaed/claude-agent-sdk-laravel 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.15k 次下载、GitHub Stars 达 15, 最近一次更新时间为 2026 年 02 月 22 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「sdk」 「laravel」 「automation」 「Agent」 「ai」 「php-sdk」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 mohamed-ashraf-elsaed/claude-agent-sdk-laravel 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 mohamed-ashraf-elsaed/claude-agent-sdk-laravel 我们能提供哪些服务?
定制开发 / 二次开发

基于 mohamed-ashraf-elsaed/claude-agent-sdk-laravel 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 1.15k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 15
  • 点击次数: 37
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 15
  • Watchers: 1
  • Forks: 4
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-22