nikkie-ftnextの日記

イベントレポートや読書メモを発信

GitHub Copilot ExtensionsでGitHubのログインハンドルを取得し、メンションするようプロンプトに記載する(Python・FastAPIを使ったBlackbeard実装、完全版!)

はじめに

アニメ アオのハコ 9話急展開!(キャー!) nikkieです

ここのところ、GitHub Copilot ExtensionsをPythonで実装することに夢中です。
今回はHello worldにあたるBlackbeardを完全版にします

目次

GitHub Copilot ExtensionsのBlackbeard

Copilot Chatの@の相手を、独自に実装できるのがGitHub Copilot Extensions!
BlackbeardはHello world的な実装例です。
海賊として質問に答えてくれます。

Blackbeard自体はNode.jsで実装されています。
独自に実装できるという点に魅力を感じた私は、手に馴染むPythonの実装に取り組んでいます(すべては自分のアイデアを実現しやすい環境のためなのです。くふふ)

さて、このPython版Blackbeardには、削り落とした機能がありました。

GitHubのログインハンドルにメンションする

削り落とした機能とは、プロンプトのうちGitHubのログインハンドルにメンションする部分です。
[feat] Minimum pirate · ftnext/blackbeard-copilot-extension@cb4637a · GitHub

import { Octokit } from "@octokit/core";

const octokit = new Octokit({ auth: tokenForUser });
const user = await octokit.request("GET /user");

messages.unshift({
  role: "system",
  content: `Start every response with the user's name, which is @${user.data.login}`,
});

ユーザのログインハンドルをOctokitを使って取得し、システムプロンプトに追加しています。
@ftnextのように始めて、(GitHubがホストする)LLMに回答させたいわけですね。

実装に使っているOctokitJavaScriptRubyなどで提供されています。
しかしながら、Python版は現時点でありません1
Python版Blackbeardにあたっては、streamの処理だけでも当時の私には難易度が高めだった2ので、ユーザのログインハンドルへのメンションをスコープから落としました。

しかしこのたび、OctokitがラップしているGitHub APIを簡単に直接叩けることに気づいたのです!

ドキュメント「GitHub API からのリソースのフェッチ」

ドキュメントの中に、Node.jsでOctokitを使わない実装例を見つけます。

その中の「GitHub API からのリソースのフェッチ

Copilot agent への要求は、X-Github-Token ヘッダーを受け取ります。
このヘッダーには、エージェントと対話するユーザーの代わりに GitHub API からリソースをフェッチするために使用できる API トークンが含まれています。

Copilot Chatから(自作している)GitHub Copilot Extensionsに送られるリクエストのヘッダーのX-Github-Tokenを使って、GitHub APIからログインハンドルを取得できるのです!

ドキュメントで続くNode.jsのコード(抜粋)

  const response = await fetch(
    "https://api.github.com/user",
    {
      headers: {
        "Authorization": `Bearer ${req.headers.get("x-github-token")}`
      }
    }
  )

Pythonで実装した例(抜粋)

client = httpx.AsyncClient()


async def whoami(headers) -> str:
    response = await client.get("https://api.github.com/user", headers=headers)
    json_ = response.json()
    return json_["login"]


headers = {
    "Authorization": f"Bearer {x_github_token}",
    "Content-Type": "application/json",
}
login_handle = await whoami(headers)

https://api.github.com/userは、GitHubREST APIのドキュメントの「Get the authenticated user」に記載があります

終わりに

Python版Blackbeardも、GitHubAPIからユーザのログインハンドルを取得し、システムプロンプトを追加することができました。
これで完全版です!

  • Copilot Chatから送られてくるリクエストヘッダーのX-Github-Tokenを取得
  • Copilot Extensionsからは、X-Github-Tokenの値をAuthorizationヘッダーに含めて、GitHubREST APIにリクエス

ログインハンドルへのメンションをプロンプトに追加した時点のソースコードはこちらです。

しかし、必ずしもログインハンドルにメンションするわけではないようです。
(プロンプトはprintして確認したと思っているのですが、これが私の実装ミスであることに気づいた方はぜひお知らせください)


  1. 注目のdiscussion
  2. その分学びは多く(Server-sent eventsなど)、1日1エントリは捗りました