💬

GitHub Copilotの補完候補をNode.jsプログラムで取得する

2023/12/19に公開

CopilotForXcodeを読んでいたらやり方が分かったのでメモ

実行方法

$ git clone https://github.com/github/copilot.vim
$ echo "console.lo" > sample.ts
$ node getCompletionsCycling.mjs ./sample.ts

Completions: {
  completions: [
    {
      uuid: '3dcce22b-5656-46a3-bbe8-d204ad1c5259',
      text: 'console.log("Hello World");\n',
      range: [Object],
      displayText: 'g("Hello World");\n',
      position: [Object],
      docVersion: 0
    },
    {
      uuid: '94015891-20a7-4e84-a3b7-6ce0a44b5285',
      text: 'console.log("hello world");\n',
      range: [Object],
      displayText: 'g("hello world");\n',
      position: [Object],
      docVersion: 0
    }
  ]
}

実装

getCompletionsCycling.mjs

解説

親プログラムからnode copilot.vim/dist/agent.jsで実行した子プロセスの標準入出力にJSON-RPC形式のデータを送ることで補完情報を取得する

const params = {
  jsonrpc: "2.0",
  id: 4,
  method: "getCompletions",
  params: {
    doc: {
      uri: "file:///hoge/sample.ts",
      version: 1,
      position: { line: 2, character: 2 },
    },
  },
}
const dataString = JSON.stringify(params);
const contentLength = Buffer.byteLength(dataString, "utf8");
server.stdin.write(`Content-Length: ${contentLength}\r\n\r\n${dataString}`);

標準出力を読み取り呼び出し元のプロセスで結果を受け取る

server.stdout.on("data", (data) => {
  console.log(`stdout: ${data}`);
});

copilot.vimでGitHubアカウントの認証を終えている必要がある(~/.config/github-copilot/hosts.jsonにアクセストークンが保存されている)

Language Server Protocolの仕様とGitHub Copilot独自の仕様がある

この実装では、以下の順に呼んでいる

  1. LSP: initialize
  2. LSP: textDocument/didOpen
  3. Copilot: getCompletionsCycling

他にCopilotで使えるmethodはここで分かる。内部通信の認証やエディタから使うmethodが用意されてる

https://github.com/intitni/CopilotForXcode/blob/948449daa789f6f7b25ccabd4ab8ff34d39cc9d6/Tool/Sources/GitHubCopilotService/GitHubCopilotRequest.swift

sendRequest()await sendRequest()の違いはプロセス間通信の応答待ちを必要とするかどうか

参考

python - How to invoke Github Copilot programmatically? - Stack Overflowに参考コードをあげている人がいたので真似した

Discussion