RPC(Remote Procedure Call)
官方 SDK 最近的新功能是透過以api.schema.json 為基礎的自動程式碼產生來對應。Laravel 版則參考產生後的其他語言版本,以相同方式實作。
ServerRpc
與 Client 綁定的 RPC 類別。連線、模型、工具、帳戶
使用ping() 與 connect() 確認並開始連線,使用 registerExtensionLaunchProvider() 註冊擴充功能的啟動提供者。模型列表、價格單位與內建目錄可從 models() 取得,可用的工具列表則可從 tools() 取得。account() 處理配額、驗證狀態、已登入使用者列表以及登入/登出,accounts() 則用於取得 Microsoft Entra ID 的權杖。
MCP、連接器
mcp() 提供 MCP 設定的列出、新增、更新、刪除,以及啟用、偵測、registry 搜尋、安裝計畫與套用。connectors() 可確認連接器功能、帳戶與目錄。伺服器端的連接器操作主要是以帳戶為單位的列表取得與更新。
Skills、Plugins、Agents、Instructions、Extensions
可從各群組進行探索、取得可用路徑、變更設定與重新載入。commands() 提供內建指令列表,hooks() 提供工作階段開始前的 hook 探索。Skills 與 Plugins 支援啟用/停用與安裝管理,Agents 也可取得內建代理程式資訊。Extensions 用於探索、啟用、停用已持久化的擴充功能。
目錄與安裝
使用catalog() 進行候選搜尋、選擇與 feed 取得,並透過 Skills、Plugins、MCP 各 API 確認安裝計畫、套用、查詢狀態或取消。計畫與套用是不同的操作。實際的安裝範例請參閱後半部的各個項目。
工作階段、主機、執行環境
sessions() 處理已持久化工作階段的搜尋、事件讀取、大小確認、刪除與整理,以及 fork。也可以建立、載入 Workspace 以及進行遠端控制。host() 負責主機的啟動、工作階段的發布、列出、取消發布與銷毀,runtime() 則處理執行環境的生命週期。
Git、環境、沙箱、政策
可從git() 取得分支、工作目錄與 Git remote 的資訊,並從 gitHubRepository() 與 gitHubOwners() 探索 GitHub 儲存庫與擁有者。environments() 處理 Mission Control 環境,sandbox() 與 sandboxProxyCa() 處理沙箱支援狀況與 Proxy CA,contentExclusion() 處理排除政策的驗證,managedSettings() 與 userSettings() 則處理設定。
本機模型、HTTP 推論、檔案系統
azureMl() 提供本機模型的目錄、解析與下載,以及其狀態確認、取消與刪除。llmInference() 是將模型層的 HTTP 請求轉送至用戶端的實驗性 API。sessionFs() 用於註冊工作階段的檔案系統/SQLite 回呼提供者。
基本呼叫範例
use Revolution\Copilot\Facades\Copilot;
use Revolution\Copilot\Enums\TokenPriceUnit;
use Revolution\Copilot\Types\Rpc\ModelsListTokenPriceUnitsRequest;
use Revolution\Copilot\Types\Rpc\ModelList;
// 取得模型列表
// 回傳值為 ModelList
$result = Copilot::client()->rpc()->models()->list();
// models 為 ModelInfo 的陣列
$models = $result->models;
// 與最初就有的 listModels() 幾乎相同
// 回傳值為 ModelInfo 的陣列
Copilot::client()->listModels();
各功能的使用範例
以下彙整上述功能的代表性呼叫範例。use Illuminate\Http\Client\Response;
use Revolution\Copilot\Enums\CatalogCandidateKind;
use Revolution\Copilot\Enums\CatalogCapability;
use Revolution\Copilot\Enums\CatalogSelectionDecision;
use Revolution\Copilot\Enums\CatalogTrustTier;
use Revolution\Copilot\Enums\EventsReadDirection;
use Revolution\Copilot\Enums\McpInstallationSecretStorage;
use Revolution\Copilot\Enums\OptionsUpdateToolFilterPrecedence;
use Revolution\Copilot\Enums\SkillInstallationManagementOutcomeKind;
use Revolution\Copilot\Enums\SkillInstallationManagementResultKind;
use Revolution\Copilot\Enums\AzureMlRegistry;
use Revolution\Copilot\Types\Rpc\AzureMlAcquireFamilyRequest;
use Revolution\Copilot\Types\Rpc\AzureMlCancelRequest;
use Revolution\Copilot\Types\Rpc\AzureMlCatalogRequest;
use Revolution\Copilot\Types\Rpc\AzureMlDiscardRequest;
use Revolution\Copilot\Types\Rpc\AzureMlDownloadRequest;
use Revolution\Copilot\Types\Rpc\AzureMlLatestRequest;
use Revolution\Copilot\Types\Rpc\AzureMlReleaseFamilyRequest;
use Revolution\Copilot\Types\Rpc\AzureMlResolveRequest;
use Revolution\Copilot\Types\Rpc\AzureMlStatusRequest;
use Revolution\Copilot\Types\Rpc\AgentsDiscoverRequest;
use Revolution\Copilot\Types\Rpc\AgentsGetDiscoveryPathsRequest;
use Revolution\Copilot\Types\Rpc\CatalogClientContract;
use Revolution\Copilot\Types\Rpc\CatalogGetGeneratedFeedRequest;
use Revolution\Copilot\Types\Rpc\CatalogGetSavedFeedRequest;
use Revolution\Copilot\Types\Rpc\CatalogMaterializationReference;
use Revolution\Copilot\Types\Rpc\CatalogSearchRequest;
use Revolution\Copilot\Types\Rpc\CatalogSelectionRequest;
use Revolution\Copilot\Types\Rpc\ExtensionLaunchProfile;
use Revolution\Copilot\Types\Rpc\ExtensionLaunchProviderResolveRequest;
use Revolution\Copilot\Types\Rpc\ExtensionLaunchProviderResolveResult;
use Revolution\Copilot\Types\Rpc\HooksDiscoverRequest;
use Revolution\Copilot\Types\Rpc\InstructionsDiscoverRequest;
use Revolution\Copilot\Types\Rpc\InstructionsGetDiscoveryPathsRequest;
use Revolution\Copilot\Types\Rpc\McpApplyInstallRequest;
use Revolution\Copilot\Types\Rpc\McpApplyUninstallRequest;
use Revolution\Copilot\Types\Rpc\McpInstallationOperationRequest;
use Revolution\Copilot\Types\Rpc\McpInstallationsRequest;
use Revolution\Copilot\Types\Rpc\McpPlanUninstallRequest;
use Revolution\Copilot\Types\Rpc\McpPrepareInstallRequest;
use Revolution\Copilot\Types\Rpc\McpRegistryCancelRequest;
use Revolution\Copilot\Types\Rpc\McpRegistrySearchRequest;
use Revolution\Copilot\Types\Rpc\McpServerCardReference;
use Revolution\Copilot\Types\Rpc\McpShouldExcludeGitHubToolsRequest;
use Revolution\Copilot\Types\Rpc\PluginsBuiltinSetRequest;
use Revolution\Copilot\Types\Rpc\PluginsDisableRequest;
use Revolution\Copilot\Types\Rpc\PluginsEnableRequest;
use Revolution\Copilot\Types\Rpc\PluginsInstallRequest;
use Revolution\Copilot\Types\Rpc\PluginsMarketplacesAddRequest;
use Revolution\Copilot\Types\Rpc\PluginsMarketplacesBrowseRequest;
use Revolution\Copilot\Types\Rpc\PluginsMarketplacesRefreshRequest;
use Revolution\Copilot\Types\Rpc\PluginsMarketplacesRemoveRequest;
use Revolution\Copilot\Types\Rpc\PluginsUninstallRequest;
use Revolution\Copilot\Types\Rpc\PluginsUpdateRequest;
use Revolution\Copilot\Types\Rpc\SessionsListRequest;
use Revolution\Copilot\Types\Rpc\SessionsPruneOldRequest;
use Revolution\Copilot\Types\Rpc\SessionsReadPersistedEventsRequest;
use Revolution\Copilot\Types\Rpc\SkillApplyInstallRequest;
use Revolution\Copilot\Types\Rpc\SkillApplyUninstallRequest;
use Revolution\Copilot\Types\Rpc\SkillInstallationOperationRequest;
use Revolution\Copilot\Types\Rpc\SkillInstallationsRequest;
use Revolution\Copilot\Types\Rpc\SkillPlanInstallRequest;
use Revolution\Copilot\Types\Rpc\SkillPlanInstallFromReferenceRequest;
use Revolution\Copilot\Types\Rpc\SkillPlanUninstallRequest;
use Revolution\Copilot\Types\Rpc\SkillSetEnabledRequest;
use Revolution\Copilot\Types\Rpc\SkillsGetDiscoveryPathsRequest;
use Revolution\Copilot\Types\Rpc\UIEphemeralQueryRequest;
use Revolution\Copilot\Types\SessionListFilter;
use Revolution\Copilot\Support\CopilotRequestContext;
use Revolution\Copilot\Support\CopilotRequestHandler;
Copilot::client()->rpc()->ping();
// models
Copilot::client()->rpc()->models()->list();
// 使用每個工作階段的 GitHub 權杖取得
Copilot::client()->rpc()->models()->list(new ModelsListRequest(gitHubToken: $token));
// 取得模型權杖價格的單位。傳入與 models.list 相同的帳戶選擇資訊
$priceUnits = Copilot::client()->rpc()->models()->listTokenPriceUnits(
new ModelsListTokenPriceUnitsRequest(gitHubToken: $token),
);
// $priceUnits->units 包含 modelId 與 TokenPriceUnit|string 的 unit
foreach ($priceUnits->units as $priceUnit) {
if ($priceUnit->unit === TokenPriceUnit::NanoAiu) {
// 換算 nano-AIU 為 AI Credits 時除以 1,000,000,000
}
}
// 內建模型目錄
Copilot::client()->rpc()->models()->getBuiltInCatalog();
// Azure ML 本機模型管理(experimental)
$azureMl = Copilot::client()->rpc()->azureMl();
$catalog = $azureMl->catalog(new AzureMlCatalogRequest(includeDev: false));
$latest = $azureMl->latest(new AzureMlLatestRequest(
registry: AzureMlRegistry::AzureMl,
name: 'phi',
));
$resolved = $azureMl->resolve(new AzureMlResolveRequest(
registry: AzureMlRegistry::AzureMl,
name: $latest->name,
version: $latest->version,
));
// requestId 與 leaseId 綁定於此 SDK 連線,因此不要在其他 Client 中重複使用
$lease = $azureMl->acquireFamily(new AzureMlAcquireFamilyRequest(
registry: AzureMlRegistry::AzureMl,
name: $latest->name,
));
try {
$download = $azureMl->download(new AzureMlDownloadRequest(
requestId: 'download-1',
registry: AzureMlRegistry::AzureMl,
name: $latest->name,
version: $latest->version,
destination: 'models/phi/'.$latest->version,
leaseId: $lease->leaseId,
));
} finally {
$azureMl->releaseFamily(new AzureMlReleaseFamilyRequest(
leaseId: $lease->leaseId,
registry: AzureMlRegistry::AzureMl,
name: $latest->name,
));
}
// download() 會等待至完成。處理中的進度確認與取消,
// 請從使用同一連線之 $azureMl 的其他 Fiber 等執行
// $status = $azureMl->status(new AzureMlStatusRequest(requestId: 'download-1'));
// $cancelled = $azureMl->cancel(new AzureMlCancelRequest(requestId: 'download-1'));
// cancel() 的 bool 表示取消請求已被接受,清理是否完成請透過 download() 確認
// 刪除非作用中的版本
$azureMl->discard(new AzureMlDiscardRequest(destination: 'models/phi/previous-version'));
// resolve() 與 download() 的型別中沒有已簽署 URL 的專用欄位
// download() 預設沒有逾時。若要指定秒數,請傳入第 2 個引數
// 新工作階段可用的內建斜線指令列表(experimental)
Copilot::client()->rpc()->commands()->list();
// 工作階段開始前的 hook 探索(experimental)
Copilot::client()->rpc()->hooks()->discover(new HooksDiscoverRequest(
projectPaths: ['/path/to/project'],
));
// 主機的沙箱支援狀況(experimental)
$hostSupport = Copilot::client()->rpc()->sandbox()->getHostSupport();
// $hostSupport->supported, $hostSupport->reason, $hostSupport->capabilities
// tools
Copilot::client()->rpc()->tools()->list();
// account
Copilot::client()->rpc()->account()->getQuota();
// 使用每個工作階段的 GitHub 權杖取得
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']),
));
// args 可省略
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']));
// 清除記憶體內快取(下次載入時從磁碟重新取得)
Copilot::client()->rpc()->mcp()->reload();
// MCP registry 搜尋 (experimental/internal)
// $authInfo 是主機端準備的 JSON 驗證資訊。SDK 不會解讀其內容。
$registry = Copilot::client()->rpc()->mcp()->registry();
$requestId = $registry->allocateRequestId()->requestId;
$servers = $registry->search(new McpRegistrySearchRequest(
requestId: $requestId,
authInfo: $authInfo, // 由主機傳入的驗證資訊。SDK 不會解讀其內容。
query: 'database',
limit: 20,
));
// $servers->servers 為 registry 的伺服器資料(不解讀其形狀而直接保留)
// 未使用的保留 ID 可以釋放。處理中的搜尋可從其他處理呼叫 cancel() 來取消。
$unusedRequestId = $registry->allocateRequestId()->requestId;
$cancelResult = $registry->cancel(new McpRegistryCancelRequest(requestId: $unusedRequestId));
// 釋放未使用 ID 時 canceled 為 false。只有停止執行中的搜尋時才為 true。
// 透過 MCP 目錄安裝 / 解除安裝 (experimental)
// 結果是具有 kind 的判別聯集關聯陣列。請先確認 kind 再參照各欄位。
$mcp = Copilot::client()->rpc()->mcp();
$contract = new CatalogClientContract(
protocolVersion: 1,
requiredCapabilities: ['mcp-server-card', 'mcp-install-planning'],
);
// $candidateHandle、$searchId、$cardReference 從目錄搜尋結果取得。
// $sessionId 是已連線至此 Client 的工作階段 ID。
$planned = $mcp->planInstall([
'contract' => $contract->toArray(),
'source' => ['kind' => 'candidate', 'candidateHandle' => $candidateHandle, 'searchId' => $searchId],
]);
if (($planned['kind'] ?? null) === 'planned') {
$plan = $planned['plan'];
$prepared = $mcp->prepareInstall(new McpPrepareInstallRequest(
contract: $contract,
planHandle: $plan['planHandle'],
choiceId: $plan['transportChoices'][0]['choiceId'],
inputs: [],
policySessionId: $sessionId,
secrets: [],
secretStorage: McpInstallationSecretStorage::Keychain,
source: McpServerCardReference::fromArray($cardReference),
));
// applyInstall 期間,會呼叫建立用戶端時設定的 installation_confirmation_handler。
if (($prepared['kind'] ?? null) === 'outcome'
&& ($prepared['outcome']['kind'] ?? null) === 'install-prepared') {
$applied = $mcp->applyInstall(new McpApplyInstallRequest(
contract: $contract,
operationId: $prepared['outcome']['operation']['operationId'],
policySessionId: $sessionId,
));
}
}
// 列出擁有的安裝並復原未完成的操作
$installations = $mcp->installations();
$installations->list(new McpInstallationsRequest(contract: $contract, policySessionId: $sessionId));
$installations->recover(new McpInstallationsRequest(contract: $contract, policySessionId: $sessionId));
$installations->status(new McpInstallationOperationRequest($contract, $operationId));
$installations->cancel(new McpInstallationOperationRequest($contract, $operationId));
// 解除安裝時指定擁有所有權的 installationId 進行計畫,並套用回傳的 planHandle。
$uninstallPlan = $mcp->planUninstall(new McpPlanUninstallRequest(
contract: $contract,
installationId: $installationId,
policySessionId: $sessionId,
));
if (($uninstallPlan['kind'] ?? null) === 'outcome'
&& ($uninstallPlan['outcome']['kind'] ?? null) === 'uninstall-planned') {
$mcp->applyUninstall(new McpApplyUninstallRequest(
contract: $contract,
planHandle: $uninstallPlan['outcome']['plan']['planHandle'],
policySessionId: $sessionId,
));
}
// 判斷是否可排除 GitHub MCP 工具 (experimental/internal)
$exclude = Copilot::client()->rpc()->mcp()->shouldExcludeGitHubTools(
new McpShouldExcludeGitHubToolsRequest(
availableTools: ['builtin:bash'],
excludedTools: [],
toolFilterPrecedence: OptionsUpdateToolFilterPrecedence::Available,
),
)->excludeGhReplaceableTools;
// user settings (使用者設定)
// 目前的 CLI 沒有 user.settings.reload RPC。get() 的對象是 settings.json。
Copilot::client()->rpc()->userSettings()->set(['settings' => ['theme' => 'dark']]); // 無回傳值
// mcp discover (自動偵測 MCP 伺服器)
Copilot::client()->rpc()->mcp()->discover(new McpDiscoverRequest(
workingDirectory: '/path/to/project',
));
// 可不帶引數執行
$result = Copilot::client()->rpc()->mcp()->discover();
// $result->servers 為 DiscoveredMcpServer 的陣列
// llmInference(experimental:攔截模型層的 HTTP 請求)
$client = Copilot::client([
'request_handler' => new class extends CopilotRequestHandler
{
public function sendRequest(CopilotRequestContext $context, string $method, string $body): Response
{
$context->url = 'https://proxy.example.com/v1/chat/completions';
$context->headers['X-Request-Source'] = ['laravel'];
return parent::sendRequest($context, $method, $body);
}
},
]);
// 啟動時會送出 llmInference.setProvider,並接收 httpRequestStart / httpRequestChunk。
// 未覆寫 sendRequest 的處理器會透過 Laravel HTTP Client 透明轉送 HTTP/SSE。
// 指定 Closure 時,請以 fn (CopilotRequestContext $context, string $method, string $body): Response 的形式回傳 Response。
// request_handler 為 experimental。不支援 WebSocket transport,會回傳相當於 501 的錯誤回應。
// sessionFs (註冊工作階段檔案系統提供者)
Copilot::client()->rpc()->sessionFs()->setProvider(new SessionFsSetProviderRequest(
initialCwd: '/path/to/project',
sessionStatePath: '.copilot/sessions',
conventions: 'posix',
));
// 解析擴充功能啟動方式的用戶端選項(需在 15 秒內回應)
$client = Copilot::client([
'extensionLaunchProvider' => fn (ExtensionLaunchProviderResolveRequest $request) => new ExtensionLaunchProviderResolveResult(
launch: new ExtensionLaunchProfile(
executable: '/usr/bin/node',
args: [$request->modulePath],
),
),
]);
// 沒有對應的啟動方式時回傳 null。
// fn (ExtensionLaunchProviderResolveRequest $request) => null
$sessions = Copilot::client()->rpc()->sessions();
// sessions (experimental:查詢與管理已持久化的工作階段)
$listed = $sessions->list(new SessionsListRequest(
source: 'local',
metadataLimit: 50,
filter: new SessionListFilter(cwd: '/path/to/project'),
));
// 透過各 SessionMetadata 的 isRemote 判別 local / remote 工作階段
foreach ($listed->sessions as $session) {
echo $session->sessionId;
}
$sessions->findByTaskId(['taskId' => 'task-id']);
$sessions->findByPrefix(['prefix' => 'session-id-prefix']);
$sessions->getLastForContext(['context' => ['cwd' => '/path/to/project']]);
$sizes = $sessions->getSizes(); // $sizes->sizes 為 session ID => byte 數
$inUse = $sessions->checkInUse(['sessionIds' => ['session-id']]);
$deleted = $sessions->bulkDelete(['sessionIds' => ['session-id']]);
// 關閉作用中的工作階段(不刪除歷史記錄)
$sessions->close(['sessionId' => 'session-id']);
// 將待處理事件儲存至磁碟
$sessions->save(['sessionId' => 'session-id']);
// 明確釋放此程序持有之工作階段的 in-use lock
$sessions->releaseLock(['sessionId' => 'session-id']);
// reloadPluginHooks 會重新載入 user/plugin hooks。
// 在確認 folder trust 之前延遲 repo hooks,確認信任後再接著載入。
$sessions->reloadPluginHooks([
'sessionId' => 'session-id',
'deferRepoHooks' => true,
]);
$loadedHooks = $sessions->loadDeferredRepoHooks(['sessionId' => 'session-id']);
// $loadedHooks->startupPrompts 與 $loadedHooks->hookCount
// 取代 Manager-wide 的額外 plugin 設定(以空陣列清除)
$sessions->setAdditionalPlugins(['plugins' => []]);
// 補全 local session metadata 的 summary / context
$enriched = $sessions->enrichMetadata([
'sessions' => [[
'sessionId' => 'session-id',
'startTime' => '2026-10-17T09:00:00Z',
'modifiedTime' => '2026-10-17T09:00:00Z',
'isRemote' => false,
]],
]);
// close() 會執行 shutdown、事件儲存、鎖定釋放並捨棄 active session,
// 但不會刪除 persisted history。$session->disconnect() 會透過 session.detach 釋放與此 SDK 的
// 連線及 PHP 端的 in-memory resources。若要刪除持久化資料,請使用 bulkDelete()。
// 不開啟工作階段,使用 cursor 分頁讀取已持久化的事件
$cursor = null;
do {
$page = $sessions->readPersistedEvents(new SessionsReadPersistedEventsRequest(
sessionId: 'session-id',
cursor: $cursor,
max: 100,
direction: EventsReadDirection::FORWARD,
));
foreach ($page->events as $event) {
// 處理事件
}
$cursor = $page->cursor;
} while ($page->hasMore);
// dryRun 不會刪除,而是回傳候選項目與估計值。實際刪除時請指定 dryRun: false
$preview = $sessions->pruneOld(new SessionsPruneOldRequest(
olderThanDays: 30,
dryRun: true,
));
// sessions.fork
$sessions->fork(new SessionsForkRequest(
sessionId: 'source-session-id',
toEventId: 'evt-boundary', // 選用:僅包含此 ID 之前的事件
));
// skills (伺服器層級的技能管理)
// 探索技能
$result = Copilot::client()->rpc()->skills()->discover();
// $result->skills 為 ServerSkill 的陣列
// 可選擇指定專案路徑
$result = Copilot::client()->rpc()->skills()->discover(new SkillsDiscoverRequest(
projectPaths: ['/path/to/project'],
skillDirectories: ['/custom/skills'],
));
// 設定要停用的技能
Copilot::client()->rpc()->skills()->config()->setDisabledSkills(
new SkillsConfigSetDisabledSkillsRequest(disabledSkills: ['skill-name'])
);
// 個別啟用或停用技能
Copilot::client()->rpc()->skills()->config()->setSkillDisabled(
new SkillsConfigSetSkillDisabledRequest(name: 'skill-name', disabled: true)
);
// 以 catalog.search → catalog.select 選擇技能候選 (experimental)
$contract = new CatalogClientContract(1, ['catalog-selection', 'ai-skill-installation']);
$catalog = Copilot::client()->rpc()->catalog();
$search = $catalog->search(new CatalogSearchRequest(
contract: $contract,
query: 'code review skill',
kinds: [CatalogCandidateKind::AiSkill],
));
$selection = $catalog->select(new CatalogSelectionRequest(
contract: $contract,
sessionId: $sessionId,
selectionRef: $search['candidates'][0]['selectionRef'],
outcome: CatalogSelectionDecision::Selected,
));
// category filter 需要要求 catalog-search-categories
$categoryContract = new CatalogClientContract(3, [
CatalogCapability::CatalogSearchCategories->value,
]);
$categorySearch = $catalog->search(new CatalogSearchRequest(
contract: $categoryContract,
query: 'design tools',
categories: ['design', 'test'],
));
// 指定 policySessionId 時,也要在 contract 中要求 credential-required 與 session-bound,
// 且只會綁定至既有的 attached session。不會新建或恢復 session。
// 已儲存、已產生的 catalog feed (credential required)
$feedContract = new CatalogClientContract(3, [
CatalogCapability::CatalogFeeds->value,
CatalogCapability::CatalogSearchCredentialRequired->value,
]);
$savedFeed = $catalog->getSavedFeed(new CatalogGetSavedFeedRequest(
contract: $feedContract,
feedId: 'opaque-feed-id',
trustTiers: [CatalogTrustTier::T1],
));
// 綁定至既有的 attached session 時,也要要求 session-bound capability
$sessionFeedContract = new CatalogClientContract(3, [
CatalogCapability::CatalogFeeds->value,
CatalogCapability::CatalogSearchCredentialRequired->value,
CatalogCapability::CatalogSearchSessionBound->value,
]);
$generatedFeed = $catalog->getGeneratedFeed(new CatalogGetGeneratedFeedRequest(
contract: $sessionFeedContract,
strategy: 'telemetry',
key: 'popular',
policySessionId: $sessionId,
trustTiers: [CatalogTrustTier::T1, CatalogTrustTier::T2],
));
// entries 會保留 feed 順序。不符合 trust tier 的項目也會以 filtered 保留其位置,
// 無法顯示的 entry 會以 unavailable 與 reason 回傳。
// 沒有 feed 時為 kind=unavailable、reason=feed-not-found。驗證、協商、政策拒絕也
// 都會以各自的型別化結果回傳,catalog feed RPC 不會進行安裝或設定。
// 技能的安裝計畫與套用
$skills = Copilot::client()->rpc()->skills();
if ($selection['kind'] === 'selected') {
$planned = $skills->planInstall(new SkillPlanInstallRequest(
contract: $contract,
candidateHandle: $selection['candidateHandle'],
policySessionId: $sessionId,
));
if ($planned->kind === SkillInstallationManagementResultKind::Outcome
&& $planned->outcome?->kind === SkillInstallationManagementOutcomeKind::InstallPlanned) {
// applyInstall() 在透過 installations.confirm 確認後套用
$result = $skills->applyInstall(new SkillApplyInstallRequest(
contract: $contract,
planHandle: $planned->outcome->plan['planHandle'],
policySessionId: $sessionId,
));
}
}
// 從 Agent Finder 的 materialisation reference 計畫技能安裝
$referenceContract = new CatalogClientContract(3, [
'skill-confirmed-installation',
'skill-reference-installation',
]);
$referencePlan = $skills->planInstallFromReference(new SkillPlanInstallFromReferenceRequest(
contract: $referenceContract,
reference: new CatalogMaterializationReference(
resourceId: '12345',
revisionId: '67890',
schemaVersion: '1.0.0',
descriptorDigest: 'sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
bundleDigest: 'sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
),
policySessionId: $sessionId,
));
// 成功時為 $referencePlan->kind === SkillInstallationManagementResultKind::Outcome、
// $referencePlan->outcome->kind === SkillInstallationManagementOutcomeKind::InstallPlanned。
// 計畫本身不會產生副作用,會從固定的 Agent Finder authority 取得 descriptor,
// 並比對 descriptor 與 bundle 的 digest。確認內容並完成既有的確認流程後再 applyInstall()。
// invalid-reference、descriptor-not-found、descriptor-withdrawn、digest-mismatch、
// unsupported-resource 會作為計畫結果的拒絕理由回傳。
// GitHub 的拒絕理由 source-rate-limited、no-credential、credential-rejected
// 以 SkillInstallationFailureReason 區分,retryAfterSeconds 只在 source-rate-limited 時回傳。
// network-failure 的 message 是不包含 URL、搜尋查詢、handle、secret 的安全說明。
// 已安裝的技能與進行中的操作
$installations = $skills->installations();
$owned = $installations->list(new SkillInstallationsRequest($contract, $sessionId));
$pending = $installations->recover(new SkillInstallationsRequest($contract, $sessionId));
$status = $installations->status(new SkillInstallationOperationRequest($contract, 'operation-id'));
$cancelled = $installations->cancel(new SkillInstallationOperationRequest($contract, 'operation-id'));
$enabled = $installations->setEnabled(new SkillSetEnabledRequest(
contract: $contract,
installationId: 'installation-id',
enabled: true,
policySessionId: $sessionId,
));
// 解除安裝同樣先確認計畫再套用
$removalPlan = $skills->planUninstall(new SkillPlanUninstallRequest(
contract: $contract,
installationId: 'installation-id',
policySessionId: $sessionId,
));
$removed = $skills->applyUninstall(new SkillApplyUninstallRequest(
contract: $contract,
planHandle: $removalPlan['planHandle'],
policySessionId: $sessionId,
));
// skills:取得可建立技能的目錄 (experimental)
// 放置技能後執行環境會辨識的目錄列表
$result = Copilot::client()->rpc()->skills()->getDiscoveryPaths();
// $result->paths 為 SkillDiscoveryPath 的陣列
// $result->paths[0]->path - 目錄路徑
// $result->paths[0]->scope - 範圍(user, project, plugin)
// $result->paths[0]->preferredForCreation - 是否為新建時的建議目錄
// 可選擇縮小範圍
$result = Copilot::client()->rpc()->skills()->getDiscoveryPaths(
new SkillsGetDiscoveryPathsRequest(scope: 'project')
);
// plugins (伺服器範圍的外掛程式管理)
$plugins = Copilot::client()->rpc()->plugins();
$result = $plugins->list(); // 回傳值為 PluginList
$installed = $plugins->install(new PluginsInstallRequest(source: 'eslint@official'));
$plugins->uninstall(new PluginsUninstallRequest(name: 'eslint@official'));
$plugins->update(new PluginsUpdateRequest(name: 'eslint@official'));
$plugins->updateAll();
$plugins->enable(new PluginsEnableRequest(names: ['eslint@official']));
$plugins->disable(new PluginsDisableRequest(names: ['eslint@official']));
// 內建外掛程式的目錄設定
$plugins->builtin()->set(new PluginsBuiltinSetRequest(paths: ['/opt/copilot/plugins']));
// 所有工作階段都會使用的目錄,若在用戶端設定中指定,
// Client::start() 會在建立第一個工作階段前自動註冊
// config/copilot.php: 'builtin_plugin_directories' => ['/opt/copilot/plugins']
// 市集管理
$marketplaces = $plugins->marketplaces();
$marketplaces->list();
$marketplaces->add(new PluginsMarketplacesAddRequest(source: 'github/copilot-plugins'));
$marketplaces->remove(new PluginsMarketplacesRemoveRequest(name: 'official', force: true));
$marketplaces->browse(new PluginsMarketplacesBrowseRequest(name: 'official'));
$marketplaces->refresh(new PluginsMarketplacesRefreshRequest(name: 'official'));
// agents (experimental:自訂代理程式管理)
// 探索自訂代理程式
$result = Copilot::client()->rpc()->agents()->discover();
// $result->agents 為 AgentInfo 的陣列
$result = Copilot::client()->rpc()->agents()->discover(new AgentsDiscoverRequest(
projectPaths: ['/path/to/project'],
excludeHostAgents: true,
));
// 取得可建立代理程式的目錄 (experimental)
$result = Copilot::client()->rpc()->agents()->getDiscoveryPaths();
// $result->paths 為 AgentDiscoveryPath 的陣列
// $result->paths[0]->path - 目錄路徑
// $result->paths[0]->scope - 範圍(user, project, plugin)
// $result->paths[0]->preferredForCreation - 是否為新建時的建議目錄
$result = Copilot::client()->rpc()->agents()->getDiscoveryPaths(
new AgentsGetDiscoveryPathsRequest(scope: 'user')
);
// instructions (experimental:指示管理)
// 探索指示
$result = Copilot::client()->rpc()->instructions()->discover();
// $result->sources 為 InstructionSource 的陣列
$result = Copilot::client()->rpc()->instructions()->discover(
new InstructionsDiscoverRequest(projectPaths: ['/path/to/project'])
);
// 取得可建立指示的檔案/目錄 (experimental)
$result = Copilot::client()->rpc()->instructions()->getDiscoveryPaths();
// $result->paths 為 InstructionDiscoveryPath 的陣列
// $result->paths[0]->path - 檔案/目錄路徑
// $result->paths[0]->location - 位置(user, repository, working-directory, plugin)
// $result->paths[0]->kind - 種類(file, directory)
// $result->paths[0]->preferredForCreation - 是否為新建時的建議項目
$result = Copilot::client()->rpc()->instructions()->getDiscoveryPaths(
new InstructionsGetDiscoveryPathsRequest(location: 'repository')
);
// extensions (experimental:已持久化擴充功能的管理)
$result = Copilot::client()->rpc()->extensions()->discover();
Copilot::client()->rpc()->extensions()->enable(['ids' => ['user:demo']]);
Copilot::client()->rpc()->extensions()->disable(['ids' => ['plugin:demo']]);
// environments (experimental:GitHub Mission Control 環境的搜尋、取得、刪除)
$result = Copilot::client()->rpc()->environments()->list(['kind' => 'user-local']);
// $result->environments 為 GitHubEnvironment 的陣列
$env = Copilot::client()->rpc()->environments()->get(['environmentId' => 'env-id']);
Copilot::client()->rpc()->environments()->delete(['environmentId' => 'env-id']);
Agent Plugin catalog 候選
在catalog.search 中要求 agent-plugin-discovery,並在搜尋對象的 kinds 中指定 plugin,即可取得 Agent Plugin 候選。若要接收標準格式 application/vnd.github.copilot-plugin 以外的 application/vnd.anthropic.claude-plugin+json 與 application/agent-plugin+json,除了 agent-plugin-discovery 之外,還需要要求 agent-plugin-formats。
agent-plugin-confirmed-installation 是回傳是否可安裝以及供審查用之計畫的 capability,同樣需與 agent-plugin-discovery 一併要求。允許後,候選中會包含 installability,其值為 installable、install-data-unavailable、feature-disabled、not-installable-kind 其中之一。installPlan 只會在 installability 為 installable 時包含。計畫是供確認用的資料,此 catalog RPC 不會執行安裝。
計畫的 sources 依優先順序包含 materialization、marketplace、repository 的候選。Marketplace 會記錄名稱與儲存庫,直接的 Repository 則記錄儲存庫與選用的路徑。僅有 materialization 的計畫會省略 pluginName,且 components 為空。名稱與實際導入的內容請透過 plugins.planInstall() 回傳的審查內容確認。
已選擇的候選可透過 plugins.planInstall() 建立不具副作用、經過驗證的計畫。plugins.applyInstall() 會要求使用者明確確認,並在獲得允許時套用計畫。套用後的外掛程式會以停用狀態註冊。
審查內容中的 mcpServers 會顯示已驗證檔案所宣告的伺服器名稱、transport,以及遠端時的 host。這並非安全性保證,因此請讓使用者確認內容後再進行明確確認。已安裝外掛程式的 description 來自 manifest。verifiedSource 表示 GitHub 儲存庫與固定的 commit,僅存在於固定至 commit 的直接安裝。iconUrl 是外部的不受信任內容,取得時請勿傳送驗證資訊或 GitHub 認證。認證本身不會作為拒絕理由回傳。
在安裝結果的 network-failure 中,可確認 CatalogNetworkFailureReason、HTTP statusCode、選用的 retryAfterSeconds,以及可安全顯示的 message。
use Revolution\Copilot\Enums\CatalogReferenceInstallationResultKind;
use Revolution\Copilot\Enums\PluginInstallationManagementOutcomeKind;
use Revolution\Copilot\Types\Rpc\CatalogClientContract;
use Revolution\Copilot\Types\Rpc\PluginApplyInstallRequest;
use Revolution\Copilot\Types\Rpc\PluginPlanInstallRequest;
$contract = new CatalogClientContract(3, [
'agent-plugin-confirmed-installation',
]);
$plugins = Copilot::client()->rpc()->plugins();
$planned = $plugins->planInstall(new PluginPlanInstallRequest(
candidateHandle: $candidateHandle,
contract: $contract,
policySessionId: $sessionId,
));
if ($planned->kind === CatalogReferenceInstallationResultKind::Outcome
&& $planned->outcome?->kind === PluginInstallationManagementOutcomeKind::InstallPlanned) {
$applied = $plugins->applyInstall(new PluginApplyInstallRequest(
contract: $contract,
planHandle: $planned->outcome->plan->planHandle,
policySessionId: $sessionId,
));
}
catalog.planInstallFromReference()。結果的 outcome->kind 為 plugin-install-planned、skill-install-planned、refused 其中之一。外掛程式的計畫請傳給 plugins.applyInstall(),技能的計畫請傳給 skills.applyInstall()。
use Revolution\Copilot\Enums\CatalogCapability;
use Revolution\Copilot\Enums\CatalogReferenceInstallationOutcomeKind;
use Revolution\Copilot\Enums\CatalogReferenceInstallationResultKind;
use Revolution\Copilot\Types\Rpc\CatalogClientContract;
use Revolution\Copilot\Types\Rpc\CatalogPlanInstallFromReferenceRequest;
use Revolution\Copilot\Types\Rpc\PluginApplyInstallRequest;
$referenceContract = new CatalogClientContract(3, [
CatalogCapability::CatalogReferenceInstallation->value,
CatalogCapability::AgentPluginConfirmedInstallation->value,
]);
$planned = Copilot::client()->rpc()->catalog()->planInstallFromReference(
new CatalogPlanInstallFromReferenceRequest(
contract: $referenceContract,
policySessionId: $sessionId,
reference: $reference,
),
);
$plugins = Copilot::client()->rpc()->plugins();
if ($planned->kind === CatalogReferenceInstallationResultKind::Outcome
&& $planned->outcome?->kind === CatalogReferenceInstallationOutcomeKind::PluginInstallPlanned) {
$plugins->applyInstall(new PluginApplyInstallRequest(
contract: $referenceContract,
planHandle: $planned->outcome->plan->planHandle,
policySessionId: $sessionId,
));
}
contentExclusion
可在建立工作階段前驗證內容排除政策的 JSON。use Revolution\Copilot\Types\Rpc\ContentExclusionValidatePoliciesRequest;
$result = Copilot::client()->rpc()->contentExclusion()->validatePolicies(
new ContentExclusionValidatePoliciesRequest(policiesJson: $policiesJson),
);
// $result->policies 為經過驗證並正規化的政策
policiesJson 會以未解析的 JSON 字串原樣傳給 CLI。若 JSON 解析或結構描述驗證失敗,會發生來自 CLI 的 RPC 錯誤(JsonRpcException)。
這是驗證政策本身的伺服器範圍 RPC。若要依實際的排除政策確認工作階段工作目錄內的路徑,請使用工作階段範圍的 contentExclusion()->checkPaths()。
managedSettings (experimental:管理設定)
進行管理設定的讀取、政策解析、結構描述取得、驗證、合成預覽與快取清除。$managedSettings = $client->rpc()->managedSettings()->read();
$effective = $client->rpc()->managedSettings()->resolve([
'selectionId' => 'selection-id',
'workingDirectory' => '/path/to/project',
]);
$schema = $client->rpc()->managedSettings()->schema();
$validation = $client->rpc()->managedSettings()->validate(['content' => ['permissions' => []]]);
$preview = $client->rpc()->managedSettings()->compose(['layers' => [
['source' => 'device', 'settings' => ['permissions' => []]],
]]);
$client->rpc()->managedSettings()->clearCache();
Runtime、Host 的生命週期(experimental)
host.unpublishSession() 會從擁有的執行中主機撤回 application publication。即使撤回發布,原本的工作階段歷史記錄、worktree 與執行中的工作也不會被刪除或停止。若已經未發布,unpublished 會是 false,而 application 以外的 publication 會產生錯誤。
$result = Copilot::client()->rpc()->host()->unpublishSession([
'hostId' => 'host-1',
'sessionId' => 'session-1',
]);
// $result->unpublished
host.dispose() 會指定 hostId 來銷毀主機監聽器。
Copilot::client()->rpc()->host()->dispose(['hostId' => 'host-1']);
Client::stop() 會在中斷工作階段之後、關閉 JSON-RPC 連線與程序之前呼叫 runtime.shutdown。最多等待 10 秒讓執行環境完成清理,失敗時會將錯誤包含在回傳值中,並繼續其餘的停止處理。對於 cli_url 等外部執行環境的連線,為避免終止共用的執行環境,不會呼叫此 RPC。
SessionRpc
與 Session 綁定的 RPC 類別。 也可以使用以前的 SDK 無法使用的計畫模式等功能。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: '建立〇〇的計畫');
$result = $session->rpc()->plan()->read();
dump($result->content);
$session->rpc()->mode()->set(new ModeSetRequest(mode: 'autopilot'));
$response = $session->sendAndWait(prompt: '依照計畫實作');
dump($response->content());
});
模型、模式、名稱、計畫
可使用model() 確認或切換目前的模型,並設定 reasoning effort、Auto tier 與允許的模型。mode() 處理模式,name() 處理工作階段名稱,plan() 處理計畫本文與 SQLite todo 的讀寫。
工作區、指示、LSP
workspaces() 提供檔案的列出、讀取、寫入、移動、刪除以及目錄操作。可使用 instructions() 取得、重新載入與探索指示,使用 lsp() 初始化語言伺服器設定。
代理程式、Fleet、背景工作
使用agent() 列出、選擇與重新載入代理程式,使用 fleet() 啟動 Fleet。tasks() 處理背景代理程式與用戶端擁有之工作的註冊、進度取得與更新、移轉、訊息傳送、取消與刪除。
MCP、Plugins、Extensions、Workflow
mcp() 處理伺服器的列出、啟動、停止、重新載入,以及工具、提示、資源、OAuth、sampling 與動態標頭的更新。plugins() 與 extensions() 管理工作階段內的狀態,customizations() 用於重新載入自訂項目。可使用 workflow() 執行與查詢工作流程,並透過 diagnostics() 與 connectors() 取得診斷資訊與連接器。
Tools、Permissions、Commands、UI
tools() 與 permissions() 處理對透過事件送達之待處理請求的回應與設定。commands() 提供指令列表、執行與事件回應,ui() 提供對使用者輸入、elicitation、計畫核准等請求的回應。completions() 用於取得輸入候選。
Accounts、驗證、Providers
accounts() 處理透過 enumerate() 列舉帳戶/提供者/登入帳戶、get() 與 set(),以及透過 begin()、advance()、cancel() 進行的互動式登入。gitHubAuth() 處理工作階段的驗證狀態與認證,provider() 與 providers() 處理模型連線目標與提供者介面卡,connectors() 則處理工作階段的連接器連線。
歷史記錄、佇列、記錄、用量
history() 提供對話的壓縮、中斷、交接摘要與截斷,queue() 提供待處理項目的插入、移動、編輯、刪除與立即傳送。可使用 log()、eventLog()、usage()、quota()、limitPrediction() 處理記錄、事件、用量與上限資訊。schedule() 可確認或停止已排程的提示。
生命週期、遠端、主機整合
sendMessages() 會在 1 個回合中執行多則訊息,suspend() 與 shutdown() 用於停止工作階段。interruptMainTurn() 個別控制主回合,cancelAllBackgroundAgents() 個別控制背景代理程式。remote() 與 visibility() 處理遠端發布與共用狀態,sandbox() 處理工作階段的沙箱,managedSettings() 處理工作階段範圍的管理設定,contentExclusion() 處理路徑判定,metadata() 處理用戶端擁有的中繼資料,canvas() 則處理 Canvas 整合。
debug (experimental)
可使用debug()->collectLogs() 將工作階段的事件記錄、程序記錄與 shell 記錄收集到 .tgz 封存檔或目錄。記錄預設會遮蔽機密資訊。可透過 additionalEntries 新增檔案或目錄,redaction 可指定 plain-text、events-jsonl、none。指定 none 時不會進行遮蔽,請注意新增的內容。
use Revolution\Copilot\Enums\DebugCollectLogsEntryKind;
use Revolution\Copilot\Enums\DebugCollectLogsRedaction;
use Revolution\Copilot\Types\Rpc\DebugCollectLogsDestination;
use Revolution\Copilot\Types\Rpc\DebugCollectLogsEntry;
use Revolution\Copilot\Types\Rpc\DebugCollectLogsRequest;
$result = $session->rpc()->debug()->collectLogs(new DebugCollectLogsRequest(
destination: DebugCollectLogsDestination::archive('/tmp/copilot-debug.tgz', noOverwrite: true),
additionalEntries: [
new DebugCollectLogsEntry(
kind: DebugCollectLogsEntryKind::File,
path: '/var/log/my-app.log',
bundlePath: 'application/my-app.log',
redaction: DebugCollectLogsRedaction::PlainText,
required: true,
),
],
));
DebugCollectLogsDestination::directory('/tmp/copilot-debug') 即可輸出到暫存目錄。可在 include 中個別指定要收集的記錄與參照路徑,並從結果的 entries 與 skippedEntries 確認收集內容。目的地與額外項目的路徑是 CLI 伺服器端的路徑。在以 stdio 啟動 CLI 的標準設定中,它與應用程式位於同一主機;但若透過 TCP 連線至其他主機上的 CLI 伺服器,請指定伺服器端而非呼叫端機器的路徑。
contentExclusion (experimental)
可確認工作階段工作目錄內的本機絕對路徑是否為內容排除政策的對象。請在讀取或附加檔案內容之前呼叫。use Revolution\Copilot\Types\Rpc\ContentExclusionCheckPathsRequest;
$result = $session->rpc()->contentExclusion()->checkPaths(
new ContentExclusionCheckPathsRequest(paths: [
'/workspace/private.txt',
'/workspace/public.txt',
]),
);
if ($result->isExcluded('/workspace/private.txt')) {
// 屬於排除對象,或無法安全判定。
}
checkPaths() 只接受絕對路徑,且路徑必須位於工作階段的工作目錄內。checks 會以與輸入相同的順序回傳,重複的路徑也會原樣保留。當不支援的路徑、檔案系統或政策評估無法使用時,會回傳 available: false 與空的 checks。此時 isExcluded() 一律回傳 true,請將所有路徑視為排除對象。即使 available: true,結果中沒有的路徑也會以安全為優先判定為排除對象。
MCP Apps (experimental)
可從$session->rpc()->mcp()->apps() 呼叫 MCP Apps 用的 RPC。listTools() 與 callTool() 必須指定呼叫來源的 MCP 伺服器名稱 originServerName。callTool() 的結果會以自由格式的 MCP 結果回傳。
use Revolution\Copilot\Types\Rpc\MCPAppsDiagnoseRequest;
use Revolution\Copilot\Types\Rpc\MCPAppsListToolsRequest;
use Revolution\Copilot\Types\Rpc\McpAppsCallToolRequest;
use Revolution\Copilot\Types\Rpc\McpAppsReadResourceRequest;
use Revolution\Copilot\Types\Rpc\McpAppsSetHostContextDetails;
use Revolution\Copilot\Types\Rpc\McpAppsSetHostContextRequest;
$apps = $session->rpc()->mcp()->apps();
$tools = $apps->listTools(new MCPAppsListToolsRequest(
serverName: 'my-server',
originServerName: 'my-server',
));
$result = $apps->callTool(new McpAppsCallToolRequest(
serverName: 'my-server',
toolName: 'lookup',
originServerName: 'my-server',
arguments: ['query' => 'hello'],
));
$resource = $apps->readResource(new McpAppsReadResourceRequest(
serverName: 'my-server',
uri: 'ui://my-app/index.html',
));
$context = $apps->getHostContext();
$apps->setHostContext(new McpAppsSetHostContextRequest(
context: new McpAppsSetHostContextDetails(theme: 'dark', locale: 'ja-JP'),
));
$diagnostics = $apps->diagnose(new MCPAppsDiagnoseRequest(serverName: 'my-server'));
readResource() 會回傳 HTML 等資源資料。SDK 不會進行瀏覽器繪製或 iframe 操作,因此繪製取得的內容是呼叫端應用程式的責任。
各功能的使用範例
以下彙整上述功能的代表性呼叫範例。// model
$session->rpc()->model()->getCurrent();
// 取得目前模型的 reasoning summary 顯示政策(experimental)
$policy = $session->rpc()->model()->getReasoningSummaries(new ModelGetReasoningSummariesRequest(
persistedShowReasoning: true, // 未設定時省略
summariesVisible: true, // 主機 UI 目前是否正在顯示
));
// $policy->ready、$policy->sessionShowsSummaries、$policy->visibility 等
// 不變更選取的模型,只變更 reasoning effort(experimental)
$effort = $session->rpc()->model()->setReasoningEffort(
new ModelSetReasoningEffortRequest(reasoningEffort: ReasoningEffort::HIGH),
);
// $effort->reasoningEffort
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(modelId: 'gpt-4'));
// 指定 reasoningEffort 時(僅限支援的模型)
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(modelId: 'claude-opus-4.7', reasoningEffort: ReasoningEffort::HIGH));
// 指定 reasoningSummary 時
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(modelId: 'claude-opus-4.7', reasoningSummary: 'concise'));
// 指定 contextTier 時(僅限支援的模型)
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(modelId: 'gpt-4o', contextTier: 'long_context'));
// 覆寫 modelCapabilities 時
$session->rpc()->model()->switchTo(new ModelSwitchToRequest(
modelId: 'gpt-4',
modelCapabilities: new ModelCapabilitiesOverride(
supports: new ModelCapabilitiesOverrideSupports(vision: true),
),
));
// 取得工作階段可用的模型列表(experimental)
$models = $session->rpc()->model()->list();
$models->auto?->tiers; // 帳戶可用的 Auto routing preference
$session->rpc()->model()->list(new ModelListRequest(skipCache: true)); // 略過快取
// 變更 Auto routing preference(不變更 selected model,experimental)
$session->rpc()->model()->switchAutoTier(new ModelSwitchAutoTierRequest(autoTier: AutoTier::BALANCE));
$session->rpc()->model()->switchAutoTier(new ModelSwitchAutoTierRequest(autoTier: null)); // 回到 provider-default 的 Auto routing
// 在主機端設定或解除工作階段的模型允許清單(experimental)
$session->rpc()->model()->setAllowedModels(new ModelSetAllowedModelsRequest(allowedModels: ['gpt-5']));
$session->rpc()->model()->setAllowedModels(new ModelSetAllowedModelsRequest(allowedModels: null)); // 解除限制
// setModel() 輔助方法也同樣可以指定 reasoningEffort 或 modelCapabilities
$session->setModel('claude-opus-4.7', ReasoningEffort::HIGH);
$session->setModel('claude-opus-4.7', 'high'); // 也可以用字串指定
$session->setModel('gpt-4', modelCapabilities: ['supports' => ['vision' => true]]); // 也可以用陣列指定
// 指定 autoTier 時(僅在 modelId 為 'auto' 時有效)
$session->setModel('auto', autoTier: AutoTier::INTELLIGENCE);
// 使用 setAutoTier() 輔助方法,不變更 model 而只變更 Auto routing preference(experimental)
$session->setAutoTier(AutoTier::EFFICIENCY);
// mode
$session->rpc()->mode()->get();
$modeResult = $session->rpc()->mode()->set(new ModeSetRequest(mode: 'plan'));
// $modeResult->modeApplied、$modeResult->modelChanged、$modeResult->confirmation 等
// name
$session->rpc()->name()->get();
$session->rpc()->name()->set(new NameSetRequest(name: 'My Session'));
// 使用者未設定名稱時,將摘要套用為工作階段名稱(experimental)
$autoName = $session->rpc()->name()->setAuto(new NameSetAutoRequest(summary: 'Summary of the session'));
// $autoName->applied
// plan
$session->rpc()->plan()->read();
$session->rpc()->plan()->update(new PlanUpdateRequest(content: '...'));
$session->rpc()->plan()->delete();
// 讀取 SQLite todo 清單(計畫模式)
$result = $session->rpc()->plan()->readSqlTodos();
// $result->rows - PlanSqlTodosRow 的陣列(id, title, description, status)
// 讀取 SQLite todo 清單與相依關係(experimental)
$result = $session->rpc()->plan()->readSqlTodosWithDependencies();
// $result->rows - PlanSqlTodosRow 的陣列
// $result->dependencies - PlanSqlTodoDependency 的陣列(todo_id, depends_on)
// 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: '...'));
$session->rpc()->workspaces()->statFile(new WorkspacesStatFileRequest(path: 'file.txt'));
$session->rpc()->workspaces()->createDirectory(new WorkspacesCreateDirectoryRequest(path: 'new/dir', recursive: true));
$session->rpc()->workspaces()->removePath(new WorkspacesRemovePathRequest(path: 'old/dir', recursive: true, force: true));
$session->rpc()->workspaces()->renamePath(new WorkspacesRenamePathRequest(source: 'old.txt', destination: 'new.txt'));
// instructions (取得工作階段的指示來源)
$result = $session->rpc()->instructions()->getSources();
// $result->sources - InstructionsSources 的陣列
$session->rpc()->instructions()->reload();
// 明確重新載入 LSP 設定(experimental)
$session->rpc()->lsp()->initialize([
'workingDirectory' => base_path(),
'gitRoot' => base_path(),
'force' => true,
]);
// instructions discover (偵測指示檔案)
use Revolution\Copilot\Types\Rpc\InstructionsDiscoverRequest;
$result = $session->rpc()->instructions()->discover();
// $result->sources - InstructionSource 的陣列
$result = $session->rpc()->instructions()->discover(new InstructionsDiscoverRequest(
projectPaths: ['/path/to/project'],
excludeHostInstructions: true, // 排除主機層級的指示
));
// fleet
$session->rpc()->fleet()->start(new FleetStartRequest(prompt: '...'));
// 詳情請參閱 fleet-mode.md
// 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:技能管理)
$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();
$session->rpc()->skills()->ensureLoaded(); // 載入尚未載入的技能(不會重新載入)
$invoked = $session->rpc()->skills()->getInvoked();
// $invoked->skills - 工作階段中呼叫過之技能的歷史記錄
// mcp (experimental:MCP 伺服器管理)
$servers = $session->rpc()->mcp()->list();
// HTTP/SSE 伺服器的設定 URL: $servers->servers[0]->url
$session->rpc()->mcp()->enable(new McpEnableRequest(serverName: 'server-name'));
$session->rpc()->mcp()->disable(new McpDisableRequest(serverName: 'server-name'));
$session->rpc()->mcp()->reload();
// 將進行中的 MCP 載入移至背景(釋放等待中的回合)
$session->rpc()->mcp()->moveLoadingToBackground();
// 啟動或重新啟動工作階段內的 MCP 伺服器(不變更永續設定)
use Revolution\Copilot\Types\Rpc\McpRestartServerRequest;
use Revolution\Copilot\Types\Rpc\McpStartServerRequest;
$session->rpc()->mcp()->startServer(new McpStartServerRequest(
serverName: 'server-name',
config: ['type' => 'http', 'url' => 'https://mcp.example.com'],
));
$session->rpc()->mcp()->restartServer(new McpRestartServerRequest(
serverName: 'server-name',
expectedInstallationId: 'installation-id',
));
// 刪除自動管理的 GitHub MCP 伺服器,以及環境變數值的解析方式
$removed = $session->rpc()->mcp()->removeGitHub();
$mode = $session->rpc()->mcp()->setEnvValueMode(['mode' => 'indirect']);
// $removed->removed、$mode->mode
// MCP sampling 的執行與取消
use Revolution\Copilot\Types\Rpc\McpCancelSamplingExecutionParams;
use Revolution\Copilot\Types\Rpc\McpExecuteSamplingParams;
$sampling = $session->rpc()->mcp()->executeSampling(new McpExecuteSamplingParams(
requestId: 'sampling-1',
serverName: 'server-name',
mcpRequestId: 'mcp-request-1',
request: ['messages' => [], 'maxTokens' => 256],
));
$cancelled = $session->rpc()->mcp()->cancelSamplingExecution(
new McpCancelSamplingExecutionParams(requestId: 'sampling-1'),
);
// 確認 MCP 伺服器是否正在執行
use Revolution\Copilot\Types\Rpc\McpIsServerRunningRequest;
$result = $session->rpc()->mcp()->isServerRunning(new McpIsServerRunningRequest(serverName: 'my-server'));
// $result->running - 伺服器是否正在執行
// 取得 MCP 伺服器的工具列表
use Revolution\Copilot\Types\Rpc\McpListToolsRequest;
$result = $session->rpc()->mcp()->listTools(new McpListToolsRequest(serverName: 'my-server'));
// $result->tools - McpTools 的陣列(name, description)
// MCP 提示的列出與取得(experimental)
use Revolution\Copilot\Types\Rpc\McpPromptsGetRequest;
use Revolution\Copilot\Types\Rpc\McpPromptsListRequest;
$prompts = $session->rpc()->mcp()->listPrompts(new McpPromptsListRequest(serverName: 'my-server'));
$rendered = $session->rpc()->mcp()->getPrompt(new McpPromptsGetRequest(
serverName: 'my-server',
promptName: 'summarize',
arguments: ['document' => 'README.md'],
));
// $prompts->prompts - MCP 提示定義
// $rendered->messages - 已轉譯的提示(不會傳送給模型)
// 停止 MCP 伺服器
use Revolution\Copilot\Types\Rpc\McpStopServerRequest;
$session->rpc()->mcp()->stopServer(new McpStopServerRequest(serverName: 'my-server'));
// 取得 MCP 資源列表(experimental)
use Revolution\Copilot\Types\Rpc\McpResourcesListRequest;
$result = $session->rpc()->mcp()->resources()->list(new McpResourcesListRequest(serverName: 'my-server'));
// $result->resources - McpResource 的陣列(uri, name, title, mimeType 等)
// $result->nextCursor - 下一頁的游標(若存在)
// 取得 MCP 資源(experimental)
use Revolution\Copilot\Types\Rpc\McpResourcesReadRequest;
$result = $session->rpc()->mcp()->resources()->read(new McpResourcesReadRequest(serverName: 'my-server', uri: 'ui://example'));
// $result->contents - McpResourceContent 的陣列
// 取得 MCP 資源範本列表(experimental)
use Revolution\Copilot\Types\Rpc\McpResourcesListTemplatesRequest;
$result = $session->rpc()->mcp()->resources()->listTemplates(new McpResourcesListTemplatesRequest(serverName: 'my-server'));
// MCP OAuth 登入(適用於需要驗證的 MCP 伺服器)
use Revolution\Copilot\Types\Rpc\McpOauthCompleteRequest;
use Revolution\Copilot\Types\Rpc\McpOauthLoginRequest;
use Revolution\Copilot\Types\Rpc\McpOauthProbeRequest;
use Revolution\Copilot\Types\Rpc\SessionMcpOauthCancelLoginRequest;
use Revolution\Copilot\Types\Rpc\SessionMcpOauthPrepareLoginRequest;
$result = $session->rpc()->mcp()->login(new McpOauthLoginRequest(serverName: 'my-server'));
// $result->authorizationUrl - OAuth 流程的 URL(需要驗證時)
// 在主機管理的 OAuth 重新導向流程中指定 redirectUri,並在 callback 後呼叫 complete()
$result = $session->rpc()->mcp()->login(new McpOauthLoginRequest(
serverName: 'my-server',
redirectUri: 'http://localhost:3000/oauth/callback',
));
$session->rpc()->mcp()->complete(new McpOauthCompleteRequest(
authorizationId: $result->authorizationId,
callbackUrl: $callbackUrl,
));
// 確認 OAuth 狀態,並準備或取消與擁有之安裝綁定的登入
$probe = $session->rpc()->mcp()->oauth()->probe(new McpOauthProbeRequest(serverName: 'my-server'));
$prepared = $session->rpc()->mcp()->oauth()->prepareLogin(new SessionMcpOauthPrepareLoginRequest(
serverName: 'my-server',
expectedInstallationId: 'installation-id',
));
$cancelled = $session->rpc()->mcp()->oauth()->cancelLogin(new SessionMcpOauthCancelLoginRequest(
expectedInstallationId: 'installation-id',
loginId: $prepared->loginId,
));
// plugins (experimental:外掛程式列表)
$session->rpc()->plugins()->list();
// 重新載入外掛程式
$session->rpc()->plugins()->reload();
// 指定選項重新載入
use Revolution\Copilot\Types\Rpc\PluginsReloadRequest;
$session->rpc()->plugins()->reload(new PluginsReloadRequest(
reloadMcp: true, // 重新載入 MCP 伺服器設定
reloadHooks: true, // 重新載入 hook
reloadCustomAgents: false, // 不重新載入自訂代理程式
));
// extensions (experimental:擴充功能管理)
$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()->reconcile(); // host-only:重新同步實際 membership,並回傳 settled list
$session->rpc()->extensions()->reload();
// compaction → 更名為 history
$session->rpc()->history()->compact();
// 中斷手動壓縮 / 取消背景壓縮
$session->rpc()->history()->abortManualCompaction();
$session->rpc()->history()->cancelBackgroundCompaction();
// 取得交接給其他工作階段用的摘要
$summary = $session->rpc()->history()->summarizeForHandoff()->summary;
// 截斷特定事件之後的歷史記錄
$session->rpc()->history()->truncate(new HistoryTruncateRequest(
eventId: 'evt-123', // 此事件及其後的所有事件都會被刪除
));
// tools (協定 v3+:回應 external_tool.requested 事件)
// 以原生呼叫管線執行目前公開給工作階段的工具(experimental)
use Revolution\Copilot\Types\Rpc\ToolsExecuteRequest;
$result = $session->rpc()->tools()->execute(new ToolsExecuteRequest(
name: 'search',
arguments: ['query' => 'Laravel'],
toolCallId: 'call-123', // 選用。用於與呼叫建立關聯
));
if (is_string($result)) {
// 簡單的文字結果
echo $result;
} else {
// ToolResultExpanded:textResultForLlm、resultType、newMessages、
// mcpMeta、structuredContent、taskCompletionDecision 等
echo $result->textResultForLlm;
// resultType 是 ToolResultType,或保留未知值的 string
}
// 也可以用陣列指定。toolCallId 可省略,sessionId 會被此工作階段的值覆寫
$session->rpc()->tools()->execute([
'name' => 'search',
'arguments' => ['query' => 'Copilot'],
]);
// arguments: [] 會以 JSON 物件 {} 送出,scalar/null/非空陣列則保持其 JSON 值
// execute() 會經過一般的原生工具呼叫管線,因此不會繞過權限確認。
// 工具需要核准時,會如常由 SessionConfig 的 onPermissionRequest 處理器處理。
$session->rpc()->tools()->handlePendingToolCall(new HandlePendingToolCallRequest(
requestId: '...',
result: '工具的執行結果',
));
// 取得工作階段目前的工具中繼資料(experimental)
$session->rpc()->tools()->getCurrentMetadata();
// 完全取代此連線提供的外部工具(experimental)
$session->rpc()->tools()->set(['tools' => [
['name' => 'search', 'description' => 'Search documents', 'parameters' => ['type' => 'object']],
]]);
// 更新子代理程式的設定(experimental)
use Revolution\Copilot\Types\Rpc\SubagentSettings;
use Revolution\Copilot\Types\Rpc\SubagentSettingsEntry;
use Revolution\Copilot\Types\Rpc\UpdateSubagentSettingsRequest;
$result = $session->rpc()->tools()->updateSubagentSettings(new UpdateSubagentSettingsRequest(
settings: new SubagentSettings(entries: [
new SubagentSettingsEntry(agentName: 'my-agent', contextTier: 'medium', enabled: true),
]),
));
// $result->settings - 更新後的 SubagentSettings
// permissions (協定 v3+:回應 permission.requested 事件)
use Revolution\Copilot\Types\Rpc\FolderTrustAddParams;
use Revolution\Copilot\Types\Rpc\PermissionLocationAddToolApprovalParams;
use Revolution\Copilot\Types\Rpc\PermissionLocationApplyParams;
use Revolution\Copilot\Types\Rpc\PermissionLocationResolveParams;
use Revolution\Copilot\Types\Rpc\PermissionsLocationsAddToolApprovalDetailsCommands;
$session->rpc()->permissions()->handlePendingPermissionRequest(new PermissionDecisionRequest(
requestId: '...',
result: PermissionDecision::approveOnce(),
));
// 自動核准工作階段內的所有權限請求
$session->rpc()->permissions()->setApproveAll(new PermissionsSetApproveAllRequest(enabled: true));
// 設定權限模式 (manual / assisted / allow-all)
$session->rpc()->permissions()->setMode(new PermissionsSetModeRequest(mode: PermissionMode::AllowAll));
// 取得目前的權限模式
$mode = $session->rpc()->permissions()->getMode();
// 重設工作階段範圍的權限核准
$session->rpc()->permissions()->resetSessionApprovals();
// 取得目前 pending 中的權限請求列表
$pending = $session->rpc()->permissions()->pendingRequests();
// 啟用/停用權限請求的事件橋接
$session->rpc()->permissions()->setRequired(new PermissionsSetRequiredRequest(required: true));
// 新增/刪除權限規則
$session->rpc()->permissions()->modifyRules(new PermissionsModifyRulesParams(
scope: PermissionsModifyRulesScope::SESSION,
add: [['tool' => 'bash', 'decision' => 'allow']],
));
// 通知已顯示權限提示
$session->rpc()->permissions()->notifyPromptShown(new PermissionPromptShownNotification(message: 'tool permission prompt'));
// 路徑權限
$paths = $session->rpc()->permissions()->paths()->list();
$session->rpc()->permissions()->paths()->add(new PermissionPathsAddParams(path: '/path/to/allow'));
$session->rpc()->permissions()->paths()->updatePrimary(new PermissionPathsUpdatePrimaryParams(path: '/path/to/allow'));
$session->rpc()->permissions()->paths()->isPathWithinAllowedDirectories(new PermissionPathsAllowedCheckParams(path: '/path/to/allow/file.txt'));
$session->rpc()->permissions()->paths()->isPathWithinWorkspace(new PermissionPathsWorkspaceCheckParams(path: '/path/to/allow/file.txt'));
// URL 權限
$session->rpc()->permissions()->urls()->setUnrestrictedMode(
new PermissionUrlsSetUnrestrictedModeParams(enabled: true)
);
// 解析工作目錄的權限位置,並套用已儲存的規則
$location = $session->rpc()->permissions()->locations()->resolve(
new PermissionLocationResolveParams(workingDirectory: '/path/to/repo')
);
$session->rpc()->permissions()->locations()->apply(
new PermissionLocationApplyParams(workingDirectory: '/path/to/repo')
);
// 將工具核准永久保存至權限位置
$session->rpc()->permissions()->locations()->addToolApproval(
new PermissionLocationAddToolApprovalParams(
approval: new PermissionsLocationsAddToolApprovalDetailsCommands(commandIdentifiers: ['bash']),
locationKey: $location->locationKey,
)
);
// 確認與新增資料夾信任狀態
$trusted = $session->rpc()->permissions()->folderTrust()->isTrusted(['path' => '/path/to/repo']);
$session->rpc()->permissions()->folderTrust()->addTrusted(new FolderTrustAddParams(path: '/path/to/repo'));
// commands:取得工作階段可用的斜線指令列表
use Revolution\Copilot\Types\Rpc\CommandsListRequest;
$list = $session->rpc()->commands()->list();
// $list->commands - SlashCommandInfo 的陣列
// $list->commands[0]->name - 指令名稱(不含斜線)
// $list->commands[0]->description - 指令說明
// $list->commands[0]->kind - 指令類別(builtin, skill, client)
// $list->commands[0]->allowDuringAgentExecution - 是否可在代理程式執行中使用
// 指定篩選條件取得列表
$list = $session->rpc()->commands()->list(new CommandsListRequest(
includeBuiltins: true,
includeSkills: false,
));
// commands:呼叫斜線指令
use Revolution\Copilot\Types\Rpc\CommandsInvokeRequest;
$result = $session->rpc()->commands()->invoke(new CommandsInvokeRequest(
name: 'help',
input: 'optional input text',
));
// commands:回應指令呼叫事件
$session->rpc()->commands()->handlePendingCommand(new CommandsHandlePendingCommandRequest(
requestId: '...',
));
// commands:同步執行斜線指令
use Revolution\Copilot\Types\Rpc\ExecuteCommandParams;
$result = $session->rpc()->commands()->execute(new ExecuteCommandParams(
commandName: 'review',
args: 'src/',
), timeout: 120.0); // 等待 CLI 回應的時間(秒)。省略時為 30 秒
// $result->error - 執行失敗時的錯誤訊息(成功時為 null)
// commands:回應已加入佇列的指令
$session->rpc()->commands()->respondToQueuedCommand(new CommandsRespondToQueuedCommandRequest(
requestId: '...',
result: new QueuedCommandResult(handled: true),
));
// ui:回應 UI elicitation 請求
$session->rpc()->ui()->elicitation(new UIElicitationRequest(
message: '詢問使用者的問題',
requestedSchema: ['type' => 'object', 'properties' => [...]],
));
// ui:不加入對話歷史記錄的暫時性詢問
$result = $session->rpc()->ui()->ephemeralQuery(new UIEphemeralQueryRequest(
question: '請告訴我到目前為止對話的重點。',
));
// $result->answer
// ui:回應待處理的 elicitation 請求(經由 elicitation.requested 事件)
$session->rpc()->ui()->handlePendingElicitation(new UIHandlePendingElicitationRequest(
requestId: '...',
result: ['action' => 'accept', 'content' => ['name' => 'John']],
));
// ui:經由廣播事件回應待處理的請求
use Revolution\Copilot\Enums\UIAutoModeSwitchResponse;
use Revolution\Copilot\Types\Rpc\UIExitPlanModeResponse;
use Revolution\Copilot\Types\Rpc\UIHandlePendingAutoModeSwitchRequest;
use Revolution\Copilot\Types\Rpc\UIHandlePendingExitPlanModeRequest;
use Revolution\Copilot\Types\Rpc\UIHandlePendingSamplingRequest;
use Revolution\Copilot\Types\Rpc\UIHandlePendingUserInputRequest;
use Revolution\Copilot\Types\Rpc\UIUserInputResponse;
$result = $session->rpc()->ui()->handlePendingUserInput(new UIHandlePendingUserInputRequest(
requestId: '...',
response: new UIUserInputResponse(answer: 'blue', wasFreeform: false),
));
$result = $session->rpc()->ui()->handlePendingExitPlanMode(new UIHandlePendingExitPlanModeRequest(
requestId: '...',
response: new UIExitPlanModeResponse(approved: true, selectedAction: 'autopilot_fleet'),
));
$result = $session->rpc()->ui()->handlePendingAutoModeSwitch(new UIHandlePendingAutoModeSwitchRequest(
requestId: '...',
response: UIAutoModeSwitchResponse::Yes,
));
$result = $session->rpc()->ui()->handlePendingSampling(new UIHandlePendingSamplingRequest(
requestId: '...',
response: ['result' => '...'],
));
// 各方法會回傳 UIHandlePendingResult。可透過 $result->success 確認回應是否已被接受。
// SessionConfig 的 onExitPlanModeRequest / onAutoModeSwitchRequest 會透過 reverse-RPC 自動回應。
// 若要經由事件手動回應相同的請求,請勿同時使用兩種途徑。
// log:將訊息記錄到工作階段時間軸
$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:在工作階段內執行 shell 指令
$result = $session->rpc()->shell()->exec(new ShellExecRequest(command: 'ls -la'));
// 透過 $result->processId 取得程序 ID,用於 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
));
// 取消使用者請求的 shell 指令
use Revolution\Copilot\Types\Rpc\ShellExecuteUserRequestedRequest;
use Revolution\Copilot\Types\Rpc\ShellCancelUserRequestedRequest;
$execution = $session->rpc()->shell()->executeUserRequested(new ShellExecuteUserRequestedRequest(
requestId: 'req-123',
command: 'pwd',
), timeout: 120.0); // 等待 CLI 回應的時間(秒)。省略時為 30 秒
// $execution->toolCallId / success / output / exitCode / error
// 若要在執行中從其他處理取消,請指定相同的 requestId
$cancelled = $session->rpc()->shell()->cancelUserRequested(
new ShellCancelUserRequestedRequest(requestId: 'req-123')
);
// $cancelled->cancelled - 是否成功取消
// usage (experimental:工作階段用量指標)
$metrics = $session->rpc()->usage()->getMetrics();
// $metrics->totalPremiumRequestCost - 進階請求的總成本
// $metrics->totalUserRequests - 使用者請求的總數
// $metrics->codeChanges - 程式碼變更指標(新增行數、刪除行數、變更檔案數)
// $metrics->modelMetrics - 各模型的權杖用量與請求數
// $metrics->currentModel - 目前的模型識別碼
// auth:取得工作階段的驗證狀態
$status = $session->rpc()->auth()->getStatus();
// $status->isAuthenticated - 是否已驗證
// $status->authType - 驗證類型(AuthInfoType enum: gh-cli, token, env 等)
// $status->login - GitHub 登入名稱
// $status->host - GitHub 主機
// $status->copilotPlan - Copilot 方案(individual, business 等)
// $status->statusMessage - 驗證狀態的訊息
// provider:取得工作階段所使用之提供者的端點資訊 (experimental)
// 用於在 BYOK(Bring Your Own Key)設定中直接呼叫 LLM 後端時
use Revolution\Copilot\Types\Rpc\ProviderGetEndpointRequest;
$endpoint = $session->rpc()->provider()->getEndpoint();
// $endpoint->baseUrl - 傳給 LLM 用戶端程式庫的基礎 URL
// $endpoint->type - 提供者種類(openai, anthropic 等)
// $endpoint->headers - 請求中要包含的 HTTP 標頭
// $endpoint->apiKey - 驗證資訊(nullable)
// $endpoint->sessionToken - 短期的工作階段驗證資訊(nullable)
// $endpoint->wireApi - 提供者特有的 wire API(nullable)
// 取得特定模型的端點
$endpoint = $session->rpc()->provider()->getEndpoint(
new ProviderGetEndpointRequest(model: 'gpt-5')
);
// provider:從 BYOK registry 撤下主機管理的模型 (experimental)
$result = $session->rpc()->provider()->withdraw(['models' => ['provider/model']]);
// $result->withdrawn, $result->providersRemoved, $result->modelDeselected
// queue:確認與管理佇列中的使用者項目
$pending = $session->rpc()->queue()->pendingItems();
// $pending->items - QueuePendingItems 的陣列
// $pending->items[0]->kind - QueuePendingItemsKind(Command / Message)
$removed = $session->rpc()->queue()->removeMostRecent();
// $removed->removed - 是否已刪除最近的項目
$session->rpc()->queue()->clear();
// 在指定位置插入項目(position 從 0 開始)
use Revolution\Copilot\Types\Rpc\QueueInsertAtRequest;
use Revolution\Copilot\Types\Rpc\QueueInsertMessage;
$queue = $session->rpc()->queue();
$inserted = $queue->insertAt(new QueueInsertAtRequest(
position: 0,
message: new QueueInsertMessage(prompt: 'Review the changes'),
));
// $inserted->id - 插入項目的 ID
$queue->moveItem(['id' => $inserted->id, 'toPosition' => 1]);
$duplicated = $queue->duplicateAt(['id' => $inserted->id]);
$queue->updateText(['id' => $duplicated->id, 'prompt' => 'Review and test the changes']);
$removedAt = $queue->removeAt(['id' => $duplicated->id]);
// $removedAt->removed - 是否已刪除項目
$sent = $queue->sendNow(['id' => $inserted->id]);
// $sent->steered - 是否已送至執行中的回合
// 暫停清空佇列。暫停不會自動解除,因此務必以 false 恢復
$queue->setDrainPaused(['paused' => true]);
$queue->setDrainPaused(['paused' => false]);
// schedule (experimental:已排程提示的管理)
$schedule = $session->rpc()->schedule()->list();
// $schedule->entries - ScheduleEntry 的陣列
use Revolution\Copilot\Types\Rpc\ScheduleStopRequest;
$stopped = $session->rpc()->schedule()->stop(new ScheduleStopRequest(id: 1));
// $stopped->stopped - 是否成功停止
// tasks (experimental:背景工作管理)
// 啟動代理程式工作並取得 ID
use Revolution\Copilot\Types\Rpc\TasksStartAgentRequest;
$result = $session->rpc()->tasks()->startAgent(new TasksStartAgentRequest(
agentType: 'explore',
prompt: 'Search for all TODO comments in the codebase',
name: 'todo-search',
description: 'Find TODO items', // 選用
model: 'gpt-4o', // 選用
));
// $result->agentId - 背景工作的 ID
// 取得目前的工作列表
$list = $session->rpc()->tasks()->list();
// $list->tasks - TaskAgentInfo、TaskShellInfo、TaskClientInfo 的陣列
// 使用游標增量讀取已分離之 shell 的輸出
use Revolution\Copilot\Types\Rpc\TasksReadOutputRequest;
$cursor = null;
do {
$output = $session->rpc()->tasks()->readOutput(new TasksReadOutputRequest(
id: 'shell-1',
cursor: $cursor,
waitMs: 1000,
));
echo $output->text;
$cursor = $output->cursor;
} while ($output->exit === null);
// $output->exit->status - 工作的結束狀態
// $output->exit->exitCode - 程序的結束代碼(nullable)
// 單次讀取最多 64 KiB。waitMs 預設值為 0,最大 30000ms。
// stdout 與 stderr 會合併。游標失效時,請不帶游標重新讀取。
// 將應用程式擁有的作業註冊為工作
use Revolution\Copilot\Types\Rpc\TasksRegisterRequest;
$registered = $session->rpc()->tasks()->register(new TasksRegisterRequest(
clientTaskId: 'import-123',
description: '匯入客戶資料',
cancellable: true,
displayName: '客戶匯入', // 選用
));
// $registered->task->id - CLI 指派的工作 ID
// $registered->created / $registered->reclaimed - 新建立、孤立工作的重新取得狀態
// 更新用戶端擁有之工作的進度
use Revolution\Copilot\Enums\TaskClientActiveStatus;
use Revolution\Copilot\Enums\TaskClientUpdateKind;
use Revolution\Copilot\Types\Rpc\TaskClientUpdate;
use Revolution\Copilot\Types\Rpc\TasksUpdateRequest;
$updated = $session->rpc()->tasks()->update(new TasksUpdateRequest(
id: $registered->task->id,
sequence: 1,
update: new TaskClientUpdate(
kind: TaskClientUpdateKind::Progress,
status: TaskClientActiveStatus::Running,
phase: 'importing',
percentage: 25,
),
));
// 每次更新都要遞增 sequence
// 回報完成
$completed = $session->rpc()->tasks()->update(new TasksUpdateRequest(
id: $registered->task->id,
sequence: 2,
update: new TaskClientUpdate(
kind: TaskClientUpdateKind::Completed,
result: ['imported' => 100],
),
));
// 取得工作的進度(未追蹤時為 null)
$progress = $session->rpc()->tasks()->getProgress(['id' => $registered->task->id])->progress;
// TaskAgentProgress、TaskClientProgress、TaskShellProgress 或 null
// 更新已分離 shell 的狀態,並等待背景作業完成
$session->rpc()->tasks()->refresh();
$session->rpc()->tasks()->waitForPending();
// 取得目前可移至背景的工作,或立即將該工作移至背景
$promotable = $session->rpc()->tasks()->getCurrentPromotable()->task;
$promotedCurrent = $session->rpc()->tasks()->promoteCurrentToBackground()->task;
// 將工作移轉至背景模式(解除同步等待)
use Revolution\Copilot\Types\Rpc\TasksPromoteToBackgroundRequest;
$promoted = $session->rpc()->tasks()->promoteToBackground(
new TasksPromoteToBackgroundRequest(id: $result->agentId)
);
// $promoted->promoted - 是否成功移轉
// 取消工作
use Revolution\Copilot\Types\Rpc\TasksCancelRequest;
$cancelled = $session->rpc()->tasks()->cancel(
new TasksCancelRequest(id: $result->agentId)
);
// $cancelled->cancelled - 是否成功取消
// 刪除已完成或已取消的工作
use Revolution\Copilot\Types\Rpc\TasksRemoveRequest;
$removed = $session->rpc()->tasks()->remove(
new TasksRemoveRequest(id: $result->agentId)
);
// $removed->removed - 是否成功刪除
// 傳送訊息給執行中的代理程式工作(引導)
use Revolution\Copilot\Types\Rpc\TasksSendMessageRequest;
$sent = $session->rpc()->tasks()->sendMessage(
new TasksSendMessageRequest(id: $result->agentId, message: '請也搜尋其他目錄')
);
// $sent->sent - 訊息是否已成功傳送
// $sent->error - 傳送失敗時的錯誤訊息(nullable)
// 只中斷主回合,佇列中的提示保留至下一個回合
use Revolution\Copilot\Types\Rpc\InterruptMainTurnRequest;
$interrupted = $session->rpc()->interruptMainTurn(
new InterruptMainTurnRequest(flushQueued: true)
);
// $interrupted->interrupted - 是否已中斷執行中的主回合
// 不中斷主回合,取消所有執行中的背景代理程式
$cancelledCount = $session->rpc()->cancelAllBackgroundAgents();
// 已取消的代理程式數量
remote (experimental:遠端工作階段支援)
use Revolution\Copilot\Enums\RemoteSessionMode;
use Revolution\Copilot\Types\Rpc\RemoteEnableRequest;
use Revolution\Copilot\Types\Rpc\RemoteEnableResult;
// 啟用遠端工作階段
// 在 GitHub 儲存庫的工作目錄中執行時,
// 會回傳可從 GitHub Web 或行動裝置存取工作階段的 URL
$result = $session->rpc()->remote()->enable();
// $result->remoteSteerable - 遠端引導是否已啟用
// $result->url - GitHub 前端 URL(可能為 null)
// 指定模式啟用
// RemoteSessionMode::Off - 僅限本機(預設)
// RemoteSessionMode::Export - 將工作階段事件匯出至 GitHub(無遠端引導)
// RemoteSessionMode::On - 同時啟用匯出與遠端引導
$result = $session->rpc()->remote()->enable(new RemoteEnableRequest(
mode: RemoteSessionMode::Export,
));
// 停用遠端工作階段
$session->rpc()->remote()->disable();
// 連線至遠端工作階段(experimental)
use Revolution\Copilot\Types\Rpc\ConnectRemoteSessionParams;
$connected = $session->rpc()->remote()->connectRemoteSession(new ConnectRemoteSessionParams(
sessionId: 'remote-session-id',
));
// $connected->sessionId - 已連線工作階段的 ID
// $connected->metadata - ConnectedRemoteSessionMetadata 物件
sandbox (experimental:沙箱控制)
// 在建立工作階段前確認主機的沙箱支援狀況
$hostSupport = $client->rpc()->sandbox()->getHostSupport();
// $hostSupport->supported, $hostSupport->reason, $hostSupport->capabilities
// 確認是否需要 Proxy CA 以及安裝支援狀況
$proxyCa = $client->rpc()->sandboxProxyCa();
$relevant = $proxyCa->checkRelevance(['enabled' => true]);
$installable = $proxyCa->checkInstallationSupport();
use Revolution\Copilot\Types\Rpc\SandboxDisableForSessionRequest;
use Revolution\Copilot\Types\Rpc\SandboxGrantPathForRequestRequest;
// 取得沙箱強制狀態
$status = $session->rpc()->sandbox()->getEnforcementStatus();
// 在沙箱的新 shell 中可能可用的驗證資訊(不會回傳值)
$credentials = $session->rpc()->sandbox()->getCredentialSuggestions();
// $credentials->suggestions 為 SandboxCredentialSuggestion 的陣列
// sandbox 停用時或沒有候選時為空陣列。不會變更設定或網路權限。
// 核准待處理的沙箱略過許可請求,並在整個工作階段停用沙箱
$result = $session->rpc()->sandbox()->disableForSession(new SandboxDisableForSessionRequest(requestId: $requestId));
// $result->success, $result->enabled
// 核准待處理的沙箱提權許可請求所提出的路徑許可(sandboxPathGrant),
// 將該路徑加入工作階段的沙箱政策,並讓被封鎖的操作
// 在沙箱內重新執行
$result = $session->rpc()->sandbox()->grantPathForRequest(new SandboxGrantPathForRequestRequest(requestId: $requestId));
// 也可使用陣列輸入: ->grantPathForRequest(['requestId' => $requestId])
// $result->success
// 若目標請求已不再處於待處理狀態、未附帶 sandboxPathGrant,
// 或在目前的管理政策下授權無效,則會失敗。
// 這是只允許特定路徑的最小權限手段,比停用整個工作階段的 disableForSession() 更為建議。
// 此路徑不會被永久保存(僅限此工作階段,不會延續到之後的工作階段)。
// 儲存沙箱設定的主機,如有需要請自行保存路徑。
$request['sandboxPathGrant'],請以目標待處理請求的 requestId 呼叫。由於此 RPC 本身會回應許可請求,成功時請回傳 PermissionDecision::noResult(),以免送出一般的回應。
if (isset($request['sandboxPathGrant'])) {
$result = $session->rpc()->sandbox()->grantPathForRequest([
'requestId' => $requestId,
]);
return $result->success
? PermissionDecision::noResult()
: PermissionDecision::reject();
}
metadata (experimental:用戶端擁有的中繼資料)
use Revolution\Copilot\Types\Rpc\MetadataUpdateClientMetadataRequest;
// 取得與此本機工作階段綁定的用戶端擁有中繼資料
$metadata = $session->rpc()->metadata()->getClientMetadata();
// 以不可分割的方式更新中繼資料(依 clear → remove → set 的順序套用)
$metadata = $session->rpc()->metadata()->updateClientMetadata(new MetadataUpdateClientMetadataRequest(
set: ['my-app/key' => 'value'],
));
Session canvas
Canvas RPC 從$session->rpc()->canvas() 呼叫。list() 會在
CanvasList 的 canvases、listOpen() 會在 CanvasListOpenResult 的
openCanvases 中回傳列表。open() 回傳 OpenCanvasInstance,
action 呼叫回傳 CanvasActionInvokeResult。close()
沒有回傳值。
$canvases = $session->rpc()->canvas();
$available = $canvases->list()->canvases;
$openInstances = $canvases->listOpen()->openCanvases;
$instance = $canvases->open([
'canvasId' => 'editor',
'instanceId' => 'editor-1',
'input' => ['file' => 'README.md'],
]);
$result = $canvases->action()->invoke([
'instanceId' => $instance->instanceId,
'actionName' => 'format',
'input' => ['style' => 'compact'],
]);
$canvases->close(['instanceId' => $instance->instanceId]);
canvas.open / canvas.close /
canvas.action.invoke) 由 SessionConfig / ResumeSessionConfig 的
canvasHandler 處理。Canvas 的繪製是主機 UI 的責任。
workflow
Copilot CLI 1.0.89 系列新增的工作流程、連接器、診斷等實驗性 RPC API,也可以從SessionRpc 使用。這些可變的協定 payload 以 JSON 相容的陣列傳入,回應也以陣列回傳。每次呼叫都會自動加入目前的 sessionId。
// 執行在 CLI 端註冊的工作流程,並確認執行狀況
$run = $session->rpc()->workflow()->run([
'name' => 'weekly-summary',
'args' => ['team' => 'platform'],
]);
$current = $session->rpc()->workflow()->getRun(['runId' => $run['runId']]);
// 診斷資訊與連接器列表
$diagnostics = $session->rpc()->diagnostics()->read(['sources' => ['mcp']]);
$connectors = $session->rpc()->connectors()->list();
$account = $session->rpc()->connectors()->getAccount(); // 若有選取中的帳戶則為 ConnectorSessionAccount
// 外掛程式市集
$marketplaces = $session->rpc()->plugins()->marketplaces()->list();
// 結束作用中的工作階段,並在背景處理 sessionEnd hook
$session->rpc()->shutdown(['detachSessionEndHooks' => true]);
workflow() 會呼叫 CLI 提供的低階 RPC。像 Node.js SDK 那樣將 PHP closure 註冊並執行為工作流程的高階 API,在此次同步中並未加入。這些新的 RPC 群組依賴 CLI 的版本且屬於實驗性質,請僅在支援的 CLI 中使用。
SessionFS 回呼型別
為 Session 範圍的檔案系統操作定義的回呼型別(Request/Result)。這些是 Copilot CLI 對 Client 進行回呼時的請求/回應型別。| 型別類別 | 用途 |
|---|---|
SessionFsReadFileRequest / SessionFsReadFileResult | 讀取檔案 |
SessionFsWriteFileRequest | 寫入檔案 |
SessionFsAppendFileRequest | 附加檔案內容 |
SessionFsExistsRequest / SessionFsExistsResult | 檔案是否存在 |
SessionFsStatRequest / SessionFsStatResult | 取得檔案 metadata |
SessionFsMkdirRequest | 建立目錄 |
SessionFsReaddirRequest / SessionFsReaddirResult | 列出目錄 |
SessionFsReaddirWithTypesRequest / SessionFsReaddirWithTypesResult | 帶類型的目錄列表 |
SessionFsRmRequest | 刪除檔案/目錄 |
SessionFsRenameRequest | 檔案/目錄改名 |
SessionFsStatResult / SessionFsReaddirResult / SessionFsReaddirWithTypesResult 具有失敗時使用的選用 error(SessionFsError)。
SessionFs 處理器
除了sessionFs.readFile / readFileBytes / writeFile / writeFileBytes 之外,Client 還會將 appendFile、exists、stat、mkdir、readdir、readdirWithTypes、rm、rename、sqliteQuery、sqliteTransaction、sqliteExists 等各請求分派給 Session 的提供者。檔案操作失敗時會以 ENOENT(ENOENT 或 errno 2)/ UNKNOWN 的 error 回傳。exists 發生例外時回傳 false,stat 失敗時回傳零值加上 error。提供者不支援的操作會成為 UNKNOWN 錯誤(SQLite 類則為 JSON-RPC 錯誤)。sqliteQuery/sqliteExists 的例外為 JSON-RPC 錯誤,sqliteTransaction 的失敗則以結果的 error(附帶 errorClass)回傳。
提供者端的介面(SessionFsFilesystemProvider、SessionFsSqliteCapableProvider、SessionFsSqliteProvider、SessionFsSqliteTransactionProvider)是為了不破壞既有的 SessionFsProvider(2 個方法)而以獨立介面新增的。
SQLite 回呼型別
| 型別類別 | 用途 |
|---|---|
SessionFsSetProviderCapabilities | 宣告提供者支援的功能(SQLite 支援等) |
SessionFsSqliteExistsRequest / SessionFsSqliteExistsResult | 確認 SQLite 資料庫是否存在 |
SessionFsSqliteQueryRequest / SessionFsSqliteQueryResult | 執行 SQLite 查詢 |
SessionFsSqliteTransactionRequest / SessionFsSqliteTransactionStatement / SessionFsSqliteTransactionResult | SQLite 交易(以不可分割的方式執行多個陳述式) |
SessionFsSqliteTransactionError | 交易失敗的分類(errorClass: busyOrLocked / fatal / postCommitAmbiguous。enum SessionFSSqliteTransactionErrorClass) |
SessionFsSetProviderRequest 的 capabilities 中傳入 SessionFsSetProviderCapabilities(sqlite: true)。
use Revolution\Copilot\Types\Rpc\SessionFsSetProviderCapabilities;
use Revolution\Copilot\Types\Rpc\SessionFsSetProviderRequest;
$client->rpc()->sessionFs()->setProvider(new SessionFsSetProviderRequest(
initialCwd: '/app',
sessionStatePath: '.copilot/sessions',
capabilities: new SessionFsSetProviderCapabilities(sqlite: true),
));
sessionFs(或 config/copilot.php 的 session_fs),Client::start() 就會只送出一次 sessionFs.setProvider。工作階段需要 createSessionFsProvider(請參閱 SessionConfig)。
SessionFsSqliteQueryType enum(src/Enums/)表示查詢種類:
Exec: DDL/多個陳述式(無結果)Query: SELECT(回傳資料列)Run: INSERT/UPDATE/DELETE(回傳 rowsAffected)
src/Types/Rpc/。
以陣列指定參數
參數與回傳值都使用專用類別,但也可以用陣列指定參數。$session->rpc()->mode()->set(['mode' => 'plan']);
測試
由於無法使用Copilot::fake() 的 mock,請以 Copilot::expects('client') 或 Copilot::expects('start') 進行 mock。
最新資訊請參閱 GitHub 儲存庫。