> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 工具

> 使用 Laravel Copilot SDK 定義與處理自訂工具,並處理權限設定、呼叫 metadata 與 MCP 結果轉換。

## 工具

Copilot CLI 的內建工具預設為啟用。這裡可以指定的是自訂工具。

## 基本用法

在 SessionConfig 的 `tools` 中指定工具定義。

`Tool::define()` 是與其他語言版本的 `defineTool` 相同的輔助方法。
parameters 可以使用 Laravel 本身在 Laravel MCP 中使用的 JsonSchema。也可以不使用 JsonSchema 直接指定陣列。

```php theme={null}
use Illuminate\Support\Facades\Artisan;
use Illuminate\JsonSchema\JsonSchema;
use Revolution\Copilot\Contracts\CopilotSession;
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Types\SessionConfig;
use Revolution\Copilot\Types\Tool;
use Revolution\Copilot\Types\ToolResultObject;

use function Laravel\Prompts\{info, note, spin, warning};

Artisan::command('copilot:tools', function () {
    $facts = [
        'PHP' => 'A popular general-purpose scripting language that is especially suited to web development.',
        'Laravel' => 'A web application framework with expressive, elegant syntax.',
    ];

    $parameters = JsonSchema::object(
        properties: [
            'topic' => JsonSchema::string()
                ->description('Topic to look up (e.g., "PHP", "Laravel")')
                ->required(),
        ],
    )->toArray();

    $config = new SessionConfig(
        tools: [
            Tool::define(
                name: 'lookup_fact',
                description: 'Returns a fun fact about a given topic.',
                parameters: $parameters,
                handler: function (array $params, array $invocation) use ($facts): array {
                    $topic = $params['topic'] ?? '';

                    $fact = $facts[$topic] ?? null;

                    if (! $fact) {
                        return new ToolResultObject(
                            textResultForLlm: "No fact stored for {$topic}.",
                            resultType: 'failure',
                            sessionLog: "lookup_fact: missing topic {$topic}",
                            toolTelemetry: [],
                        );
                    }

                    return new ToolResultObject(
                        textResultForLlm: $fact,
                        resultType: 'success',
                        sessionLog: "lookup_fact: served {$topic}",
                        toolTelemetry: [],
                    );
                },
                overridesBuiltInTool: false,
                skipPermission: false, // 設為 true 可不出現權限提示直接執行
                defer: 'auto', // 控制是否延遲載入工具(透過工具搜尋延遲載入),而非始終預先載入。若為 `"auto"`,工具會延遲載入並透過工具搜尋顯示。若為 `"never"`,工具會始終預先載入。選填,預設為 `"auto"`。
            ),
        ],
    );

    Copilot::start(function (CopilotSession $session) {
        info('Starting Copilot with tools: '.$session->id());

        $prompt = 'You can call the lookup_fact tool. Use lookup_fact to tell me something about Laravel.';

        warning($prompt);

        $response = spin(
            callback: fn () => $session->sendAndWait($prompt),
            message: 'Copilot thinking...',
        );

        note($response->content());
    }, config: $config);
});
```

## skipPermission

指定 `skipPermission: true` 後,該工具可不經權限提示直接執行。

```php theme={null}
Tool::define(
    name: 'read_only_lookup',
    description: 'Read-only data lookup.',
    parameters: $parameters,
    handler: fn ($params) => ['result' => 'data'],
    skipPermission: true,
),
```

## \$invocation

工具處理器的第 2 個參數 `$invocation` 會傳入以下欄位。

```php theme={null}
[
    'sessionId'  => '...',
    'toolCallId' => '...',
    'toolName'   => 'lookup_fact',
    'arguments'  => [...], // 工具參數(與 $params 相同)
    // 僅在啟用 OpenTelemetry 時包含
    'traceparent' => '...', // W3C Trace Context traceparent
    'tracestate'  => '...', // W3C Trace Context tracestate
]
```

## 協定細節

在 Protocol v3(目前的預設)中,工具呼叫並非以 JSON-RPC 請求形式,而是以 Session Event(`external_tool.requested`)形式廣播。SDK 會在內部處理此事件,並透過 `session.tools.handlePendingToolCall` RPC 回應。

**`SessionConfig` 的使用方式並未改變。** 只要在 `tools` 傳入定義,協定差異即由 SDK 吸收處理。

## MCP CallToolResult 轉換

若要將 MCP 伺服器的工具結果(`CallToolResult`)轉換為 Copilot SDK 的 `ToolResultObject`,可使用 `McpCallToolResult::convert()`。
MCP 工具的結果是包含 text、image、resource 等的 `content` 區塊陣列,但 Copilot SDK 需要 `ToolResultObject` 格式,因此需要轉換。

```php theme={null}
use Revolution\Copilot\Support\McpCallToolResult;

// MCP CallToolResult 格式
$mcpResult = [
    'content' => [
        ['type' => 'text', 'text' => 'File contents here'],
        ['type' => 'image', 'data' => 'base64...', 'mimeType' => 'image/png'],
    ],
    'isError' => false,
];

// 轉換為 Copilot SDK ToolResultObject 格式
$toolResult = McpCallToolResult::convert($mcpResult);
// $toolResult->textResultForLlm => 'File contents here'
// $toolResult->resultType => 'success'
// $toolResult->binaryResultsForLlm => [['data' => 'base64...', 'mimeType' => 'image/png', 'type' => 'image']]
```

<Info>
  最新資訊請參閱 [GitHub 儲存庫](https://github.com/invokable/laravel-copilot-sdk)。
</Info>


## Related topics

- [Laravel MCP](/zh-TW/mcp.md)
- [BlueskyManager 與 HasShortHand](/zh-TW/packages/laravel-bluesky/bluesky-manager.md)
- [Laravel Doctor — 應用診斷工具](/zh-TW/blog/laravel-doctor-introduction.md)
- [Laravel PAO — 針對 AI Agent 的輸出最佳化工具](/zh-TW/blog/pao-introduction.md)
- [Laravel AI SDK](/zh-TW/ai-sdk.md)
