Skip to main content

github-copilot-sdk

Authoritative reference for working on MultiTable's GitHub Copilot SDK integration (`@github/copilot-sdk`). Trigger when the user mentions the Copilot SDK, `CopilotClient`, `CopilotSession`, `session.send`, `sendAndWait`, `session.idle`, `assistant.message_delta`, `onPermissionRequest`, `onUserInputRequest`, `onElicitationRequest`, plan / autopilot / chat mode for Copilot, session.abort, `~/.copilot/session-state`, or adding/modifying a Copilot provider under `packages/daemon/src/agent/providers/`.

소스 정보

저장소
erickalfaro/multitable
최근 소스 활동
2026년 7월 16일 04:02
감지된 SKILL.md 언어
영어
스타
33
포크
3

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
15 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
github-copilot-sdk
description
Authoritative reference for working on MultiTable's GitHub Copilot SDK integration (`@github/copilot-sdk`). Trigger when the user mentions the Copilot SDK, `CopilotClient`, `CopilotSession`, `session.send`, `sendAndWait`, `session.idle`, `assistant.message_delta`, `onPermissionRequest`, `onUserInputRequest`, `onElicitationRequest`, plan / autopilot / chat mode for Copilot, session.abort, `~/.copilot/session-state`, or adding/modifying a Copilot provider under `packages/daemon/src/agent/providers/`.
allowed-tools
Read, Grep, Glob, Bash, Edit, Write
# GitHub Copilot SDK reference for MultiTable Pinned SDK package: **`@github/copilot-sdk`** (Node ≥ 20.0.0 per `nodejs/package.json` `engines`; the README says 18+ but the engines field is the real floor). Repo: <https://github.com/github/copilot-sdk>, TypeScript source under `nodejs/`. The SDK is in **public preview**. Type signatures and behavior in this skill are quoted from the upstream `nodejs/src/*` source — **re-verify against the locally installed `node_modules/@github/copilot-sdk/dist/*.d.ts` after any version bump.** This skill is **strictly Copilot-only**. Do **not** import Claude Agent SDK names (`query`, `canUseTool`, `permissionMode: 'plan'`, `Query.interrupt`, `forkSession`) or Codex SDK names (`Thread`, `runStreamed`, `approvalPolicy`, `sandboxMode`, `additionalDirectories`) into Copilot code or reasoning. Each SDK has its own primitives — see [`multitable/claude-codex-comparison.md`](multitable/claude-codex-comparison.md) for the side-by-side. ## The two facts that shape everything 1. **The SDK is a JSON-RPC client driving a long-lived `copilot` CLI child process.** `new CopilotClient()` + `client.start()` spawns the bundled CLI in server mode and opens a `vscode-jsonrpc` `MessageConnection` over stdio (or TCP). Multiple `CopilotSession`s multiplex inside that one child. This is **architecturally different** from Codex (per-turn `codex exec` spawn) and Claude (in-process `query()` async-iterable). One client = one CLI child = many sessions. 2. **`session.send()` returns immediately with a `messageId`. All progress is push-only via `session.on(eventType, handler)`.** There is no AsyncIterable, no Web ReadableStream, no Node `EventEmitter`. Subscribing returns an `unsubscribe` function — there is no `off()`. Drop the unsubscribe and you've leaked a handler for the session's lifetime. ## Quick task → file map | What you want to do | Read | |---|---| | Understand `CopilotClient` / `CopilotSession` / `SessionConfig` | [`reference/api-surface.md`](reference/api-surface.md) | | Add or fix streaming display, decide when a turn is "done" | [`reference/streaming-and-lifecycle.md`](reference/streaming-and-lifecycle.md) | | Intercept `AskUserQuestion`-equivalents (3 channels!) | [`reference/prompts-and-interception.md`](reference/prompts-and-interception.md) | | Stop a turn mid-stream, or resume a prior session | [`reference/abort-and-resume.md`](reference/abort-and-resume.md) | | Implement plan / chat / auto mode behavior | [`reference/modes-and-permissions.md`](reference/modes-and-permissions.md) | | Wire auth (GitHub OAuth, BYOK, env vars) and config | [`reference/auth-and-config.md`](reference/auth-and-config.md) | | Find where sessions live on disk; wire MCP servers | [`reference/persistence-and-mcp.md`](reference/persistence-and-mcp.md) | | Add lifecycle hooks (PreToolUse, PostToolUse, etc.) | [`reference/hooks.md`](reference/hooks.md) | | Display cost / token usage | [`reference/cost-and-usage.md`](reference/cost-and-usage.md) | | Surface usage / rate limits (premium-request quota) in the per-session indicator | [`reference/usage-limits.md`](reference/usage-limits.md) | | Plan the MultiTable adapter (not yet built) | [`multitable/integration-plan.md`](multitable/integration-plan.md) | | Map Copilot concepts to existing Claude/Codex adapters | [`multitable/adapter-architecture.md`](multitable/adapter-architecture.md) | | Translate a Claude or Codex idea into Copilot terms | [`multitable/claude-codex-comparison.md`](multitable/claude-codex-comparison.md) | | Diagnose a known footgun before changing code | [`pitfalls.md`](pitfalls.md) | ## Decision tree: which lever to pull? ``` Need to BLOCK a tool call? ├── Always block, no UI? ─── hooks.onPreToolUse → { permissionDecision: 'deny' } ├── Allow without prompting? ─── defineTool({ ..., skipPermission: true }) OR onPreToolUse → 'allow' ├── Ask the user every time? ─── onPreToolUse → { permissionDecision: 'ask' } → falls through to onPermissionRequest └── Approve everything (dev)? ─── onPermissionRequest: approveAll (built-in) Need the agent to ASK the user something? ├── Free-text / multiple choice? ─── onUserInputRequest (UserInputRequest) ├── Structured form / URL? ─── onElicitationRequest (ElicitationContext) └── Permission for a side effect? ─── onPermissionRequest (PermissionRequest) ALL THREE are mandatory to wire (or the agent hangs). Need to RUN code on a lifecycle event? └── SessionConfig.hooks.onSessionStart / onUserPromptSubmitted / onPreToolUse / onPostToolUse / onSessionEnd / onErrorOccurred Need to STOP a turn mid-stream? └── await session.abort() (separate method; NO AbortSignal on send()) The session is still usable — call send() again. Need to KILL the session entirely? └── await session.disconnect() (RPC session.destroy; the object is dead) Need to RESUME a prior conversation? └── await client.resumeSession(sessionId, config) REQUIRES the same sessionId you supplied on createSession. BYOK keys must be re-supplied; not persisted. Need PLAN mode / AUTOPILOT / interactive? └── NATIVE since 1.0.5: send({ prompt, agentMode: 'interactive'|'plan'|'autopilot' }) per send. Plan's execute gate = SessionConfig.onExitPlanModeRequest. (Pre-1.0.5 recipes in reference/modes-and-permissions.md are superseded — see pitfalls #12.) ``` ## Five rules that get violated most 1. **`session.idle` — and ONLY `session.idle` — means the agent loop is fully done.** `assistant.turn_end` is the end of *one* LLM call; the agent loop typically chains many turns (tool → model → tool → model → final). Do not unlock the composer or send the next user message on `assistant.turn_end`. This was bug #1 in Claude/Codex too — the symptom in Copilot is "user message disappears" because it was steered into a turn that wasn't actually finished. 2. **Streaming deltas are ADDITIVE, not cumulative.** `assistant.message_delta.deltaContent` is the chunk to **append** to your buffer. This is the **opposite** of Codex (`item.updated.item.text` is the cumulative body). Mixing the two strategies corrupts the live preview. Always replace your live buffer with `assistant.message.content` when the canonical message arrives, to absorb any whitespace drift. 3. **There are THREE separate "ask the user" channels** — `onPermissionRequest`, `onUserInputRequest`, `onElicitationRequest`. Each is a distinct callback on `SessionConfig`. The agent **blocks indefinitely** waiting on whichever one you forgot to wire (no host-side timeout). `onPermissionRequest` is the only one that's *mandatory at construction* — but if you skip the other two, the agent silently hangs the first time it tries to use them. Wire all three for production. 4. **`onPermissionRequest` is mandatory.** Omitting it doesn't disable permission gating — it crashes when the agent first tries to use a tool. Use the exported `approveAll` for daemon/headless use, or thread it through MultiTable's `PermissionManager`. 5. **Abort is a method, not a signal.** `send()` does **not** accept an `AbortSignal`. Cancel via `await session.abort()`, which fires `agent.abort` and *still* fires `session.idle` afterwards. The session remains valid — you can `send()` again on the same instance. ## Three things to NOT confuse with each other - **`session.ui.{confirm,select,input,elicitation}`** is **host → agent** (you push a UI request *into* the agent's context). - **`onUserInputRequest` / `onElicitationRequest`** is **agent → host** (the agent asks *you* something). - **`onPermissionRequest`** is also agent → host but for tool gating specifically (`shell`, `write`, `read`, `mcp`, `url`, `custom-tool`, `memory`, `hook`). Mixing them up is a recipe for a hung session and a confused chat UI. ## Ground-truth files When in doubt about behavior, these are authoritative (in this order): 1. **The locally installed types**, once we install the SDK: `node_modules/@github/copilot-sdk/dist/index.d.ts` (and `dist/types.d.ts`, `dist/session.d.ts`). 2. **Generated event taxonomy** (currently upstream-only): `nodejs/src/generated/session-events.ts` — ~60 typed event variants. 3. **Generated RPC method list** (upstream): `nodejs/src/generated/rpc.ts`. 4. **Upstream sources** when the local types are vague: `nodejs/src/client.ts`, `nodejs/src/session.ts`, `nodejs/src/types.ts`. Use `gh api -H "Accept: application/vnd.github.raw" repos/github/copilot-sdk/contents/nodejs/src/<file>` for raw reads — GitHub's blob view truncates files >1000 lines. 5. **Official docs**: `https://github.com/github/copilot-sdk/tree/main/docs` and `https://docs.github.com/en/copilot/how-tos/copilot-sdk/sdk-getting-started`. 6. **Public-preview blog post** (concept overview, not API surface): `https://github.blog/news-insights/company-news/build-an-agent-into-any-app-with-the-github-copilot-sdk/`. ## Where this SDK lives in our codebase **The integration is LIVE** (SDK 1.0.5, exact-pinned in `packages/daemon/package.json`; shipped 2026-07): ``` packages/daemon/src/ ├── agent/providers/copilot.ts ← CopilotAdapter: singleton CopilotClient (lazy start()), │ per-MT-session CopilotSession cache, native agentMode │ per send, all three ask channels + onExitPlanModeRequest └── transcripts/copilotParser.ts ← parses ~/.copilot/session-state/<id>/events.jsonl → Message[] (NOT checkpoints — see pitfalls #19) ``` Plus registration in `agent/manager.ts` (`copilot: new CopilotAdapter(permManager, elicitManager)`), hydration branches in `manager.ts` / `api/sessions.ts`, catalog wiring (`providers/baselines.ts` COPILOT_BASELINE + `discovery.ts` discoverCopilot via a short-lived `client.listModels()` probe), and the AddAgentModal entry. **Read [`pitfalls.md`](pitfalls.md) #31 first** — the live-verified 1.0.5 gotchas (effort hard-fail + retry, `workingDirectory` naming, missing re-exports, reasoningText duplication, rich PermissionRequest union, no `autoStart`). The big architectural difference vs. Codex: Copilot has a **long-lived child** shared across sessions, so the adapter owns the client lifecycle (one `start()` on first use, `stop()` on daemon shutdown), not fresh per turn. [`multitable/integration-plan.md`](multitable/integration-plan.md) is the historical plan (kept for rationale; the shipped adapter deviates where 1.0.5 made things native — see its status header).
GitHub에서 보기