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

# RPC(Remote Procedure Call)

> 使用 Laravel Copilot SDK 的 ServerRpc 與 SessionRpc,呼叫模型、工具、權限等協定方法。

## RPC(Remote Procedure Call)

官方 SDK 最近的新功能是透過以 `api.schema.json` 為基礎的自動程式碼產生來對應。Laravel 版則參考產生後的其他語言版本,以相同方式實作。

## ServerRpc

與 Client 綁定的 RPC 類別。

```php theme={null}
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Types\Rpc\ModelList;

// 取得模型清單
// 回傳值為 ModelList
$result = Copilot::client()->rpc()->models()->list();
// models 為 ModelInfo 的陣列
$models = $result->models;

// 與最初就有的 listModels() 幾乎相同
// 回傳值為 ModelInfo 的陣列
Copilot::client()->listModels();
```

原本 SDK 中就存在的功能,也在自動程式碼產生版本中再度加入。

### 方法一覽

```php theme={null}
Copilot::client()->rpc()->ping();

// models
Copilot::client()->rpc()->models()->list();
// 以每個 Session 的 GitHub Token 取得
Copilot::client()->rpc()->models()->list(new ModelsListRequest(gitHubToken: $token));

// tools
Copilot::client()->rpc()->tools()->list();

// account
Copilot::client()->rpc()->account()->getQuota();
// 以每個 Session 的 GitHub Token 取得
Copilot::client()->rpc()->account()->getQuota(new AccountGetQuotaRequest(gitHubToken: $token));

// mcp config (MCP 伺服器設定管理)
Copilot::client()->rpc()->mcp()->list();
Copilot::client()->rpc()->mcp()->add(new McpConfigAddRequest(
    name: 'my-server',
    config: new McpServerValue(type: 'local', command: 'php', args: ['artisan', 'mcp']),
));
Copilot::client()->rpc()->mcp()->update(new McpConfigUpdateRequest(
    name: 'my-server',
    config: new McpServerValue(type: 'http', url: 'https://mcp.example.com'),
));
Copilot::client()->rpc()->mcp()->remove(new McpConfigRemoveRequest(name: 'my-server'));
// 啟用/停用 MCP 伺服器(全域設定)
Copilot::client()->rpc()->mcp()->enable(new McpConfigEnableRequest(names: ['my-server']));
Copilot::client()->rpc()->mcp()->disable(new McpConfigDisableRequest(names: ['my-server']));

// mcp discover (自動探索 MCP 伺服器)
Copilot::client()->rpc()->mcp()->discover(new McpDiscoverRequest(
    workingDirectory: '/path/to/project',
));
// 可以不帶參數執行
$result = Copilot::client()->rpc()->mcp()->discover();
// $result->servers is an array of DiscoveredMcpServer

// sessionFs (註冊 Session 檔案系統 Provider)
Copilot::client()->rpc()->sessionFs()->setProvider(new SessionFsSetProviderRequest(
    initialCwd: '/path/to/project',
    sessionStatePath: '.copilot/sessions',
    conventions: 'posix',
));

// sessions (experimental: Session 分叉)
Copilot::client()->rpc()->sessions()->fork(new SessionsForkRequest(
    sessionId: 'source-session-id',
    toEventId: 'evt-boundary', // 選用: 僅包含比此 ID 更早的事件
));

// skills (伺服器層級的 Skill 管理)
// 探索 Skill
$result = Copilot::client()->rpc()->skills()->discover();
// $result->skills 為 ServerSkill 的陣列
// 可選擇指定專案路徑
$result = Copilot::client()->rpc()->skills()->discover(new SkillsDiscoverRequest(
    projectPaths: ['/path/to/project'],
    skillDirectories: ['/custom/skills'],
));

// 設定要停用的 Skill
Copilot::client()->rpc()->skills()->config()->setDisabledSkills(
    new SkillsConfigSetDisabledSkillsRequest(disabledSkills: ['skill-name'])
);
```

## SessionRpc

與 Session 綁定的 RPC 類別。

也可以使用先前 SDK 無法使用的 plan 模式等。

```php theme={null}
use Revolution\Copilot\Contracts\CopilotSession;
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Types\Rpc\ModeSetRequest;
use Revolution\Copilot\Types\Rpc\PlanReadResult;

Copilot::start(function (CopilotSession $session) {
    $session->rpc()->mode()->set(new ModeSetRequest(mode: 'plan'));

    $response = $session->sendAndWait(prompt: '建立 XX 的計畫');

    $result = $session->rpc()->plan()->read();
    dump($result->content);

    $session->rpc()->mode()->set(new ModeSetRequest(mode: 'autopilot'));

    $response = $session->sendAndWait(prompt: '依照計畫實作');
    dump($response->content());
});
```

### 方法一覽

```php theme={null}
// model
$session->rpc()->model()->getCurrent();
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(modelId: 'gpt-4'));
// 指定 reasoningEffort 時(僅限支援的模型)
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(modelId: 'claude-opus-4.7', reasoningEffort: ReasoningEffort::HIGH));
// 覆寫 modelCapabilities 時
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(
    modelId: 'gpt-4',
    modelCapabilities: new ModelCapabilitiesOverride(
        supports: new ModelCapabilitiesOverrideSupports(vision: true),
    ),
));

// setModel() 輔助方法同樣可指定 reasoningEffort 或 modelCapabilities
$session->setModel('claude-opus-4.7', ReasoningEffort::HIGH);
$session->setModel('claude-opus-4.7', 'high'); // String is also supported
$session->setModel('gpt-4', modelCapabilities: ['supports' => ['vision' => true]]); // 也可用陣列指定

// mode
$session->rpc()->mode()->get();
$session->rpc()->mode()->set(new ModeSetRequest(mode: 'plan'));

// name
$session->rpc()->name()->get();
$session->rpc()->name()->set(new NameSetRequest(name: 'My Session'));

// plan
$session->rpc()->plan()->read();
$session->rpc()->plan()->update(new PlanUpdateRequest(content: '...'));
$session->rpc()->plan()->delete();

// workspaces
$session->rpc()->workspaces()->getWorkspace();
$session->rpc()->workspaces()->listFiles();
$session->rpc()->workspaces()->readFile(new WorkspacesReadFileRequest(path: 'file.txt'));
$session->rpc()->workspaces()->createFile(new WorkspacesCreateFileRequest(path: 'file.txt', content: '...'));

// instructions (取得 Session 的 instruction 來源)
$result = $session->rpc()->instructions()->getSources();
// $result->sources - InstructionsSources 的陣列

// fleet
$session->rpc()->fleet()->start(new FleetStartRequest(prompt: '...'));
// 詳細請參閱 Fleet Mode

// agent
$session->rpc()->agent()->list();
$session->rpc()->agent()->getCurrent();
$session->rpc()->agent()->select(new AgentSelectRequest(agentId: '...'));
$session->rpc()->agent()->deselect();
$session->rpc()->agent()->reload();

// skills (experimental: Skill 管理)
$session->rpc()->skills()->list();
$session->rpc()->skills()->enable(new SkillsEnableRequest(name: 'skill-name'));
$session->rpc()->skills()->disable(new SkillsDisableRequest(name: 'skill-name'));
$session->rpc()->skills()->reload();

// mcp (experimental: MCP 伺服器管理)
$session->rpc()->mcp()->list();
$session->rpc()->mcp()->enable(new McpEnableRequest(serverName: 'server-name'));
$session->rpc()->mcp()->disable(new McpDisableRequest(serverName: 'server-name'));
$session->rpc()->mcp()->reload();
// MCP OAuth 登入(適用於需驗證的 MCP 伺服器)
$result = $session->rpc()->mcp()->login(new McpOauthLoginRequest(serverName: 'my-server'));
// $result->authorizationUrl - OAuth 流程的 URL(若需驗證)

// plugins (experimental: 列出 Plugin)
$session->rpc()->plugins()->list();

// extensions (experimental: Extension 管理)
$session->rpc()->extensions()->list();
$session->rpc()->extensions()->enable(new ExtensionsEnableRequest(id: 'project:my-ext'));
$session->rpc()->extensions()->disable(new ExtensionsDisableRequest(id: 'project:my-ext'));
$session->rpc()->extensions()->reload();

// compaction → 更名為 history
$session->rpc()->history()->compact();
// 截斷特定事件之後的歷史紀錄
$session->rpc()->history()->truncate(new HistoryTruncateRequest(
    eventId: 'evt-123', // 此事件與其之後的所有事件會被刪除
));

// tools (Protocol v3+: 對 external_tool.requested 事件的回應)
$session->rpc()->tools()->handlePendingToolCall(new ToolsHandlePendingToolCallRequest(
    requestId: '...',
    result: '工具的執行結果',
));

// permissions (Protocol v3+: 對 permission.requested 事件的回應)
$session->rpc()->permissions()->handlePendingPermissionRequest(new PermissionDecisionRequest(
    requestId: '...',
    result: PermissionRequestResultKind::approveOnce(),
));
// 自動核准 Session 內所有權限請求
$session->rpc()->permissions()->setApproveAll(new PermissionsSetApproveAllRequest(enabled: true));
// 重設 Session 範圍的權限核准
$session->rpc()->permissions()->resetSessionApprovals();

// commands: 對指令呼叫事件的回應
$session->rpc()->commands()->handlePendingCommand(new CommandsHandlePendingCommandRequest(
    requestId: '...',
));

// ui: 對 UI Elicitation 請求的回應
$session->rpc()->ui()->elicitation(new UIElicitationRequest(
    message: '對使用者的提問',
    requestedSchema: ['type' => 'object', 'properties' => [...]],
));

// ui: 對待處理的 Elicitation 請求的回應(透過 elicitation.requested 事件)
$session->rpc()->ui()->handlePendingElicitation(new UIHandlePendingElicitationRequest(
    requestId: '...',
    result: ['action' => 'accept', 'content' => ['name' => 'John']],
));

// log: 對 Session 時間軸記錄訊息
$session->rpc()->log()->log(new LogRequest(message: '已開始處理'));
$session->rpc()->log()->log(new LogRequest(message: '磁碟使用量偏高', level: LogLevel::WARNING));
$session->rpc()->log()->log(new LogRequest(message: '發生錯誤', level: LogLevel::ERROR));
$session->rpc()->log()->log(new LogRequest(message: '除錯資訊', ephemeral: true));

// shell: 在 Session 內執行 shell 指令
$result = $session->rpc()->shell()->exec(new ShellExecRequest(command: 'ls -la'));
// 透過 $result->processId 取得 processId,可用於 kill 或追蹤輸出

$session->rpc()->shell()->exec(new ShellExecRequest(
    command: 'npm test',
    cwd: '/path/to/project',
    timeout: 60000, // 毫秒
));

// 停止執行中的 shell 程序
$session->rpc()->shell()->kill(new ShellKillRequest(
    processId: $result->processId,
    signal: 'SIGTERM', // SIGTERM(預設)、SIGKILL、SIGINT
));

// usage (experimental: Session 使用量 metrics)
$metrics = $session->rpc()->usage()->getMetrics();
// $metrics->totalPremiumRequestCost - Premium 請求的總成本
// $metrics->totalUserRequests - 使用者請求總數
// $metrics->codeChanges - 程式碼變更 metrics(新增行數、刪除行數、變更檔案數)
// $metrics->modelMetrics - 每個模型的 Token 使用量與請求數
// $metrics->currentModel - 目前的模型識別碼

// auth: 取得 Session 的驗證狀態
$status = $session->rpc()->auth()->getStatus();
// $status->isAuthenticated - 是否已驗證
// $status->authType - 驗證類型(AuthInfoType enum: gh-cli, token, env 等)
// $status->login - GitHub 登入名稱
// $status->host - GitHub Host
// $status->copilotPlan - Copilot 方案(individual, business 等)
// $status->statusMessage - 驗證狀態訊息
```

## SessionFS 回呼型別

為 Session 範圍的檔案系統操作定義的回呼型別(Request/Result)。這些是 Copilot CLI 對 Client 進行回呼時的請求/回應型別。

| 型別類別                                                                   | 用途            |
| ---------------------------------------------------------------------- | ------------- |
| `SessionFsReadFileRequest` / `SessionFsReadFileResult`                 | 讀取檔案          |
| `SessionFsWriteFileRequest`                                            | 寫入檔案          |
| `SessionFsAppendFileRequest`                                           | 附加檔案內容        |
| `SessionFsExistsRequest` / `SessionFsExistsResult`                     | 檔案是否存在        |
| `SessionFsStatRequest` / `SessionFsStatResult`                         | 取得檔案 metadata |
| `SessionFsMkdirRequest`                                                | 建立目錄          |
| `SessionFsReaddirRequest` / `SessionFsReaddirResult`                   | 列出目錄          |
| `SessionFsReaddirWithTypesRequest` / `SessionFsReaddirWithTypesResult` | 帶類型的目錄列表      |
| `SessionFsRmRequest`                                                   | 刪除檔案/目錄       |
| `SessionFsRenameRequest`                                               | 檔案/目錄改名       |

這些型別類別位於 `src/Types/Rpc/`。

## 以陣列指定參數

參數與回傳值都使用專用類別,但也可以用陣列指定參數。

```php theme={null}
$session->rpc()->mode()->set(['mode' => 'plan']);
```

## 測試

由於無法使用 `Copilot::fake()` 的 mock,請以 `Copilot::expects('client')` 或 `Copilot::expects('start')` 進行 mock。

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


## Related topics

- [Remote Sessions](/zh-TW/packages/laravel-copilot-sdk/remote-sessions.md)
- [工具](/zh-TW/packages/laravel-copilot-sdk/tools.md)
- [ForwardsCalls trait](/zh-TW/advanced/forwards-calls.md)
- [Streaming Events](/zh-TW/packages/laravel-copilot-sdk/streaming-events.md)
- [Skills](/zh-TW/packages/laravel-copilot-sdk/skills.md)
