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 설정의 목록·추가·업데이트·삭제, 활성화, 검출, 레지스트리 검색, 설치 계획과 적용을 제공합니다. connectors()에서는 커넥터 기능과 계정, 카탈로그를 확인할 수 있습니다. 서버 측 커넥터 조작은 계정 단위의 목록 취득·업데이트가 중심입니다.
Skills·Plugins·Agents·Instructions·Extensions
각 그룹에서 탐색, 사용 가능한 경로 취득, 설정 변경, 다시 불러오기를 할 수 있습니다.commands()는 내장 명령 목록, hooks()는 세션 시작 전 훅 탐색을 제공합니다. Skills와 Plugins는 활성화·비활성화와 설치 관리를 지원하며, Agents는 내장 에이전트 정보도 가져올 수 있습니다. Extensions는 영구 저장된 확장 기능을 탐색·활성화·비활성화합니다.
카탈로그와 설치
catalog()로 후보 검색·선택·피드 취득을 수행하고, 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() 는 기본적으로 타임아웃이 없다. 초 단위로 지정하려면 두 번째 인자로 전달한다
// 새 세션에서 사용 가능한 내장 슬래시 명령 목록(experimental)
Copilot::client()->rpc()->commands()->list();
// 세션 시작 전 훅 탐색(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 레지스트리 검색 (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 는 레지스트리의 서버 데이터(형태를 해석하지 않고 보존)
// 사용하지 않은 예약 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, 검색 쿼리, 핸들, 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()는 여러 메시지를 한 턴에서 실행하고, suspend()·shutdown()으로 세션을 중지합니다. interruptMainTurn()은 메인 턴을, cancelAllBackgroundAgents()는 백그라운드 에이전트를 개별적으로 제어합니다. remote()와 visibility()는 원격 공개·공유 상태, sandbox()는 세션의 샌드박스, managedSettings()는 세션 스코프의 관리 설정, contentExclusion()은 경로 판정, metadata()는 클라이언트 소유 메타데이터, canvas()는 Canvas 연동을 다룹니다.
debug (experimental)
debug()->collectLogs()로 세션의 이벤트 로그, 프로세스 로그, 셸 로그를 .tgz 아카이브 또는 디렉터리에 수집할 수 있습니다. 로그는 기본적으로 민감한 정보가 마스킹(redaction)됩니다. 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, // 훅을 다시 불러옴
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: 세션 내에서 셸 명령 실행
$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, // 밀리초
));
// 실행 중인 셸 프로세스 중지
$session->rpc()->shell()->kill(new ShellKillRequest(
processId: $result->processId,
signal: 'SIGTERM', // SIGTERM(기본값), SIGKILL, SIGINT
));
// 사용자가 요청한 셸 명령 취소
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 - 프로바이더 고유의 와이어 API(nullable)
// 특정 모델의 엔드포인트 가져오기
$endpoint = $session->rpc()->provider()->getEndpoint(
new ProviderGetEndpointRequest(model: 'gpt-5')
);
// provider: 호스트 관리 모델을 BYOK 레지스트리에서 철회 (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 의 배열
// 분리된 셸의 출력을 커서로 증분 읽기
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)
// 1회 읽기는 최대 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
// 분리된 셸의 상태를 갱신하고 백그라운드 작업 완료를 기다림
$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 를 동반하지 않았거나,
// 현재 관리 정책하에서 grant 가 무효한 경우에는 실패한다.
// 특정 경로만 허가하는 최소 권한 수단이며, 세션 전체를 비활성화하는 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 클로저를 워크플로로 등록·실행하는 고수준 API는 이번 동기화에서 추가하지 않았습니다. 이 새로운 RPC 그룹들은 CLI 버전에 의존하며 실험적이므로, 지원하는 CLI에서만 사용하세요.
SessionFS 콜백 타입
세션 스코프의 파일 시스템 조작을 위한 콜백 타입(Request/Result)이 정의되어 있습니다. 이는 Copilot CLI가 클라이언트에 콜백할 때의 요청/응답 타입입니다.| 타입 클래스 | 용도 |
|---|---|
SessionFsReadFileRequest / SessionFsReadFileResult | 파일 읽기 |
SessionFsWriteFileRequest | 파일 쓰기 |
SessionFsAppendFileRequest | 파일 추가 쓰기 |
SessionFsExistsRequest / SessionFsExistsResult | 파일 존재 확인 |
SessionFsStatRequest / SessionFsStatResult | 파일 메타데이터 취득 |
SessionFsMkdirRequest | 디렉터리 생성 |
SessionFsReaddirRequest / SessionFsReaddirResult | 디렉터리 목록 |
SessionFsReaddirWithTypesRequest / SessionFsReaddirWithTypesResult | 타입 포함 디렉터리 목록 |
SessionFsRmRequest | 파일/디렉터리 삭제 |
SessionFsRenameRequest | 파일/디렉터리 이름 변경 |
SessionFsStatResult / SessionFsReaddirResult / SessionFsReaddirWithTypesResult는 실패 시 사용하는 선택적 error(SessionFsError)를 가집니다.
SessionFs 핸들러
Client는sessionFs.readFile / readFileBytes / writeFile / writeFileBytes에 더해 appendFile, exists, stat, mkdir, readdir, readdirWithTypes, rm, rename, sqliteQuery, sqliteTransaction, sqliteExists의 각 요청을 Session의 프로바이더로 분배합니다. 파일 조작 실패는 ENOENT(ENOENT 또는 errno 2) / UNKNOWN의 error로 반환합니다. exists는 예외 시 false를, stat은 실패 시 0 값과 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()로의 목은 사용할 수 없으므로 Copilot::expects('client')나 Copilot::expects('start')로 목해 주세요.
최신 정보는 GitHub 저장소를 참고하세요.