mcpField
C
copilot-sdk

copilot-sdk

github.com/hoodiniエージェントワークフロー291139 回インストール3 日前に更新
リポジトリ

copilot-sdk について

GitHub Copilot SDK は、Copilot CLI のエージェント実行環境をアプリケーションに組み込む SDK です。Python、TypeScript、Go、.NET で AI ワークフローを構築する開発者向けに、セッション、ストリーミング、カスタムツール、エージェントを提供します。

主な機能

  1. 014言語向けの SDK
  2. 02永続セッションの作成と再開
  3. 03ストリーミング応答とイベント処理
  4. 04カスタムツールとエージェントの定義
  5. 05システムメッセージとツール権限の設定

活用シーン

  1. 01Copilot エージェントのワークフローをアプリに組み込む
  2. 02複数ターンの会話とストリーミング出力の実装
  3. 03エージェントへのカスタムツールの提供
  4. 04GitHub MCP サーバー経由でリポジトリ、Issue、PR のツールを利用

MCP 対応

セッション設定で MCP サーバーに接続し、事前構築されたツールを利用できます。例では GitHub の MCP サーバーへの HTTP 接続を示しています。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/hoodini/ai-agents-skills --skill copilot-sdk

インストール後、Claude Code で/copilot-sdkを入力して読み込まれたか確認します。

詳細

GitHub Copilot SDK

Python、TypeScript、Go、または .NET を使用して、あらゆるアプリケーションに Copilot のエージェント型ワークフローを組み込めます。

概要

GitHub Copilot SDK は、Copilot CLI の背後にあるものと同じエンジンを公開します。これは、本番環境でテスト済みのエージェントランタイムで、プログラムから呼び出せます。独自のオーケストレーションを構築する必要はありません。エージェントの動作を定義すれば、計画、ツールの呼び出し、ファイルの編集などは Copilot が処理します。

前提条件

  1. GitHub Copilot CLI がインストールされ、認証済みであること(インストールガイド)
  2. 言語ランタイム:Node.js 18 以降、Python 3.8 以降、Go 1.21 以降、または .NET 8.0 以降

CLI を確認します:copilot --version

インストール

Node.js/TypeScript
mkdir copilot-demo && cd copilot-demo
npm init -y --init-type module
npm install @github/copilot-sdk tsx
Python
pip install github-copilot-sdk
Go
mkdir copilot-demo && cd copilot-demo
go mod init copilot-demo
go get github.com/github/copilot-sdk/go
.NET
dotnet new console -n CopilotDemo && cd CopilotDemo
dotnet add package GitHub.Copilot.SDK

クイックスタート

TypeScript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient();
const session = await client.createSession({ model: "gpt-4.1" });

const response = await session.sendAndWait({ prompt: "What is 2 + 2?" });
console.log(response?.data.content);

await client.stop();
process.exit(0);

実行:npx tsx index.ts

Python
import asyncio
from copilot import CopilotClient

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session({"model": "gpt-4.1"})
    response = await session.send_and_wait({"prompt": "What is 2 + 2?"})

    print(response.data.content)
    await client.stop()

asyncio.run(main())
Go
package main

import (
    "fmt"
    "log"
    "os"
    copilot "github.com/github/copilot-sdk/go"
)

func main() {
    client := copilot.NewClient(nil)
    if err := client.Start(); err != nil {
        log.Fatal(err)
    }
    defer client.Stop()

    session, err := client.CreateSession(&copilot.SessionConfig{Model: "gpt-4.1"})
    if err != nil {
        log.Fatal(err)
    }

    response, err := session.SendAndWait(copilot.MessageOptions{Prompt: "What is 2 + 2?"}, 0)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(*response.Data.Content)
    os.Exit(0)
}
.NET (C#)
using GitHub.Copilot.SDK;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-4.1" });

var response = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2 + 2?" });
Console.WriteLine(response?.Data.Content);

実行:dotnet run

ストリーミング応答

より優れた UX を実現するため、リアルタイム出力を有効にします。

TypeScript
import { CopilotClient, SessionEvent } from "@github/copilot-sdk";

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    streaming: true,
});

session.on((event: SessionEvent) => {
    if (event.type === "assistant.message_delta") {
        process.stdout.write(event.data.deltaContent);
    }
    if (event.type === "session.idle") {
        console.log(); // New line when done
    }
});

await session.sendAndWait({ prompt: "Tell me a short joke" });

await client.stop();
process.exit(0);
Python
import asyncio
import sys
from copilot import CopilotClient
from copilot.generated.session_events import SessionEventType

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session({
        "model": "gpt-4.1",
        "streaming": True,
    })

    def handle_event(event):
        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
            sys.stdout.write(event.data.delta_content)
            sys.stdout.flush()
        if event.type == SessionEventType.SESSION_IDLE:
            print()

    session.on(handle_event)
    await session.send_and_wait({"prompt": "Tell me a short joke"})
    await client.stop()

asyncio.run(main())
Go
session, err := client.CreateSession(&copilot.SessionConfig{
    Model:     "gpt-4.1",
    Streaming: true,
})

session.On(func(event copilot.SessionEvent) {
    if event.Type == "assistant.message_delta" {
        fmt.Print(*event.Data.DeltaContent)
    }
    if event.Type == "session.idle" {
        fmt.Println()
    }
})

_, err = session.SendAndWait(copilot.MessageOptions{Prompt: "Tell me a short joke"}, 0)
.NET
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    Streaming = true,
});

session.On(ev =>
{
    if (ev is AssistantMessageDeltaEvent deltaEvent)
        Console.Write(deltaEvent.Data.DeltaContent);
    if (ev is SessionIdleEvent)
        Console.WriteLine();
});

await session.SendAndWaitAsync(new MessageOptions { Prompt = "Tell me a short joke" });

カスタムツール

推論中に Copilot が呼び出せるツールを定義します。ツールを定義するときは、Copilot に次の内容を伝えます。

  1. ツールの機能(説明)
  2. 必要なパラメーター(スキーマ)
  3. 実行するコード(ハンドラー)
TypeScript (JSON Schema)
import { CopilotClient, defineTool, SessionEvent } from "@github/copilot-sdk";

const getWeather = defineTool("get_weather", {
    description: "Get the current weather for a city",
    parameters: {
        type: "object",
        properties: {
            city: { type: "string", description: "The city name" },
        },
        required: ["city"],
    },
    handler: async (args: { city: string }) => {
        const { city } = args;
        // In a real app, call a weather API here
        const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"];
        const temp = Math.floor(Math.random() * 30) + 50;
        const condition = conditions[Math.floor(Math.random() * conditions.length)];
        return { city, temperature: `${temp}°F`, condition };
    },
});

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    streaming: true,
    tools: [getWeather],
});

session.on((event: SessionEvent) => {
    if (event.type === "assistant.message_delta") {
        process.stdout.write(event.data.deltaContent);
    }
});

await session.sendAndWait({
    prompt: "What's the weather like in Seattle and Tokyo?",
});

await client.stop();
process.exit(0);
Python (Pydantic)
import asyncio
import random
import sys
from copilot import CopilotClient
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field

class GetWeatherParams(BaseModel):
    city: str = Field(description="The name of the city to get weather for")

@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
    city = params.city
    conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
    temp = random.randint(50, 80)
    condition = random.choice(conditions)
    return {"city": city, "temperature": f"{temp}°F", "condition": condition}

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session({
        "model": "gpt-4.1",
        "streaming": True,
        "tools": [get_weather],
    })

    def handle_event(event):
        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
            sys.stdout.write(event.data.delta_content)
            sys.stdout.flush()

    session.on(handle_event)

    await session.send_and_wait({
        "prompt": "What's the weather like in Seattle and Tokyo?"
    })

    await client.stop()

asyncio.run(main())
Go
type WeatherParams struct {
    City string `json:"city" jsonschema:"The city name"`
}

type WeatherResult struct {
    City        string `json:"city"`
    Temperature string `json:"temperature"`
    Condition   string `json:"condition"`
}

getWeather := copilot.DefineTool(
    "get_weather",
    "Get the current weather for a city",
    func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {
        conditions := []string{"sunny", "cloudy", "rainy", "partly cloudy"}
        temp := rand.Intn(30) + 50
        condition := conditions[rand.Intn(len(conditions))]
        return WeatherResult{
            City:        params.City,
            Temperature: fmt.Sprintf("%d°F", temp),
            Condition:   condition,
        }, nil
    },
)

session, _ := client.CreateSession(&copilot.SessionConfig{
    Model:     "gpt-4.1",
    Streaming: true,
    Tools:     []copilot.Tool{getWeather},
})
.NET (Microsoft.Extensions.AI)
using GitHub.Copilot.SDK;
using Microsoft.Extensions.AI;
using System.ComponentModel;

var getWeather = AIFunctionFactory.Create(
    ([Description("The city name")] string city) =>
    {
        var conditions = new[] { "sunny", "cloudy", "rainy", "partly cloudy" };
        var temp = Random.Shared.Next(50, 80);
        var condition = conditions[Random.Shared.Next(conditions.Length)];
        return new { city, temperature = $"{temp}°F", condition };
    },
    "get_weather",
    "Get the current weather for a city"
);

await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    Streaming = true,
    Tools = [getWeather],
});

ツールの仕組み

Copilot がツールを呼び出すことを決定すると、次のように処理されます。

  1. Copilot がパラメーター付きのツール呼び出しリクエストを送信します
  2. SDK がハンドラー関数を実行します
  3. 結果が Copilot に返されます
  4. Copilot がその結果を応答に反映します

Copilot は、ユーザーの質問とツールの説明に基づいて、ツールを呼び出すタイミングを決定します。

対話型 CLI アシスタント

完全な対話型アシスタントを構築します。

TypeScript
import { CopilotClient, defineTool, SessionEvent } from "@github/copilot-sdk";
import * as readline from "readline";

const getWeather = defineTool("get_weather", {
    description: "Get the current weather for a city",
    parameters: {
        type: "object",
        properties: {
            city: { type: "string", description: "The city name" },
        },
        required: ["city"],
    },
    handler: async ({ city }) => {
        const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"];
        const temp = Math.floor(Math.random() * 30) + 50;
        const condition = conditions[Math.floor(Math.random() * conditions.length)];
        return { city, temperature: `${temp}°F`, condition };
    },
});

const client = new CopilotClient();
const session = await client.createSession({
    model: "gpt-4.1",
    streaming: true,
    tools: [getWeather],
});

session.on((event: SessionEvent) => {
    if (event.type === "assistant.message_delta") {
        process.stdout.write(event.data.deltaContent);
    }
});

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

console.log("Weather Assistant (type 'exit' to quit)");
console.log("Try: 'What's the weather in Paris?'\n");

const prompt = () => {
    rl.question("You: ", async (input) => {
        if (input.toLowerCase() === "exit") {
            await client.stop();
            rl.close();
            return;
        }

        process.stdout.write("Assistant: ");
        await session.sendAndWait({ prompt: input });
        console.log("\n");
        prompt();
    });
};

prompt();
Python
import asyncio
import random
import sys
from copilot import CopilotClient
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field

class GetWeatherParams(BaseModel):
    city: str = Field(description="The name of the city to get weather for")

@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
    conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
    temp = random.randint(50, 80)
    condition = random.choice(conditions)
    return {"city": params.city, "temperature": f"{temp}°F", "condition": condition}

async def main():
    client = CopilotClient()
    await client.start()

    session = await client.create_session({
        "model": "gpt-4.1",
        "streaming": True,
        "tools": [get_weather],
    })

    def handle_event(event):
        if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
            sys.stdout.write(event.data.delta_content)
            sys.stdout.flush()

    session.on(handle_event)

    print("Weather Assistant (type 'exit' to quit)")
    print("Try: 'What's the weather in Paris?'\n")

    while True:
        try:
            user_input = input("You: ")
        except EOFError:
            break

        if user_input.lower() == "exit":
            break

        sys.stdout.write("Assistant: ")
        await session.send_and_wait({"prompt": user_input})
        print("\n")

    await client.stop()

asyncio.run(main())

MCP サーバーとの統合

事前に構築されたツールを利用するため、MCP(Model Context Protocol)サーバーに接続します。リポジトリ、issue、PR にアクセスするには、GitHub の MCP サーバーに接続します。

TypeScript
const session = await client.createSession({
    model: "gpt-4.1",
    mcpServers: {
        github: {
            type: "http",
            url: "https://api.githubcopilot.com/mcp/",
        },
    },
});
Python
session = await client.create_session({
    "model": "gpt-4.1",
    "mcp_servers": {
        "github": {
            "type": "http",
            "url": "https://api.githubcopilot.com/mcp/",
        },
    },
})
Go
session, _ := client.CreateSession(&copilot.SessionConfig{
    Model: "gpt-4.1",
    MCPServers: map[string]copilot.MCPServerConfig{
        "github": {
            Type: "http",
            URL:  "https://api.githubcopilot.com/mcp/",
        },
    },
})
.NET
await using var session = await client.CreateSessionAsync(new SessionConfig
{
    Model = "gpt-4.1",
    McpServers = new Dictionary<string, McpServerConfig>
    {
        ["github"] = new McpServerConfig
        {
            Type = "http",
            Url = "https://api.githubcopilot.com/mcp/",
        },
    },
});

カスタムエージェント

特定のタスク向けに、専門化された AI ペルソナを定義します。

TypeScript
const session = await client.createSession({
    model: "gpt-4.1",
    customAgents: [{
        name: "pr-reviewer",
        displayName: "PR Reviewer",
        description: "Reviews pull requests for best practices",
        prompt: "You are an expert code reviewer. Focus on security, performance, and maintainability.",
    }],
});
Python
session = await client.create_session({
    "model": "gpt-4.1",
    "custom_agents": [{
        "name": "pr-reviewer",
        "display_name": "PR Reviewer",
        "description": "Reviews pull requests for best practices",
        "prompt": "You are an expert code reviewer. Focus on security, performance, and maintainability.",
    }],
})

システムメッセージ

AI の動作とパーソナリティをカスタマイズします。

TypeScript
const session = await client.createSession({
    model: "gpt-4.1",
    systemMessage: {
        content: "You are a helpful assistant for our engineering team. Always be concise.",
    },
});
Python
session = await client.create_session({
    "model": "gpt-4.1",
    "system_message": {
        "content": "You are a helpful assistant for our engineering team. Always be concise.",
    },
})

外部 CLI サーバー

CLI をサーバーモードで別途実行し、SDK を接続します。デバッグ、リソースの共有、カスタム環境に役立ちます。

CLI をサーバーモードで起動する
copilot --server --port 4321
SDK を外部サーバーに接続する
TypeScript
const client = new CopilotClient({
    cliUrl: "localhost:4321"
});

const session = await client.createSession({ model: "gpt-4.1" });
Python
client = CopilotClient({
    "cli_url": "localhost:4321"
})
await client.start()

session = await client.create_session({"model": "gpt-4.1"})
Go
client := copilot.NewClient(&copilot.ClientOptions{
    CLIUrl: "localhost:4321",
})

if err := client.Start(); err != nil {
    log.Fatal(err)
}

session, _ := client.CreateSession(&copilot.SessionConfig{Model: "gpt-4.1"})
.NET
using var client = new CopilotClient(new CopilotClientOptions
{
    CliUrl = "localhost:4321"
});

await using var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-4.1" });

注: cliUrl を指定すると、SDK は CLI プロセスを起動または管理せず、既存のサーバーに接続するだけです。

イベントの種類

イベント説明
user.messageユーザー入力が追加されました
assistant.messageモデルからの完全な応答
assistant.message_deltaストリーミング応答のチャンク
assistant.reasoningモデルの推論(モデルに依存)
assistant.reasoning_deltaストリーミング推論のチャンク
tool.execution_startツールの呼び出しが開始されました
tool.execution_completeツールの実行が完了しました
session.idle処理中の項目はありません
session.errorエラーが発生しました

クライアントの設定

オプション説明デフォルト
cliPathCopilot CLI 実行ファイルのパスシステム PATH
cliUrl既存のサーバーに接続(例:「localhost:4321」)なし
portサーバー通信用ポートランダム
useStdioTCP の代わりに stdio トランスポートを使用true
logLevelログの詳細度"info"
autoStartサーバーを自動的に起動true
autoRestartクラッシュ時に再起動true
cwdCLI プロセスの作業ディレクトリ継承

セッション設定

オプション説明
model使用する LLM(「gpt-4.1」、「claude-sonnet-4.5」など)
sessionIdカスタムセッション識別子
toolsカスタムツール定義
mcpServersMCP サーバー接続
customAgentsカスタムエージェントのペルソナ
systemMessageデフォルトのシステムプロンプトを上書き
streaming応答チャンクの逐次送信を有効化
availableTools使用を許可するツールのホワイトリスト
excludedTools無効にするツールのブラックリスト

セッションの永続化

再起動をまたいで会話を保存し、再開できます。

カスタム ID で作成
const session = await client.createSession({
    sessionId: "user-123-conversation",
    model: "gpt-4.1"
});
セッションを再開
const session = await client.resumeSession("user-123-conversation");
await session.send({ prompt: "What did we discuss earlier?" });
セッションの一覧表示と削除
const sessions = await client.listSessions();
await client.deleteSession("old-session-id");

エラー処理

try {
    const client = new CopilotClient();
    const session = await client.createSession({ model: "gpt-4.1" });
    const response = await session.sendAndWait(
        { prompt: "Hello!" },
        30000 // timeout in ms
    );
} catch (error) {
    if (error.code === "ENOENT") {
        console.error("Copilot CLI not installed");
    } else if (error.code === "ECONNREFUSED") {
        console.error("Cannot connect to Copilot server");
    } else {
        console.error("Error:", error.message);
    }
} finally {
    await client.stop();
}

安全なシャットダウン

process.on("SIGINT", async () => {
    console.log("Shutting down...");
    await client.stop();
    process.exit(0);
});

よく使われるパターン

複数ターンの会話
const session = await client.createSession({ model: "gpt-4.1" });

await session.sendAndWait({ prompt: "My name is Alice" });
await session.sendAndWait({ prompt: "What's my name?" });
// Response: "Your name is Alice"
ファイル添付
await session.send({
    prompt: "Analyze this file",
    attachments: [{
        type: "file",
        path: "./data.csv",
        displayName: "Sales Data"
    }]
});
長時間処理の中断
const timeoutId = setTimeout(() => {
    session.abort();
}, 60000);

session.on((event) => {
    if (event.type === "session.idle") {
        clearTimeout(timeoutId);
    }
});

利用可能なモデル

実行時に利用可能なモデルを取得します。

const models = await client.getModels();
// Returns: ["gpt-4.1", "gpt-4o", "claude-sonnet-4.5", ...]

ベストプラクティス

  1. 必ずクリーンアップする:try-finally または defer を使用し、client.stop() が呼び出されるようにします
  2. タイムアウトを設定する:長時間の処理では、タイムアウトを指定して sendAndWait を使用します
  3. イベントを処理する:堅牢なエラー処理のため、エラーイベントを購読します
  4. ストリーミングを使用する:長い応答でより良い UX を実現するため、ストリーミングを有効にします
  5. セッションを永続化する:複数ターンの会話では、カスタムセッション ID を使用します
  6. 明確なツールを定義する:説明的なツール名と説明を記述します

アーキテクチャ

Your Application
       |
  SDK Client
       | JSON-RPC
  Copilot CLI (server mode)
       |
  GitHub (models, auth)

SDK は CLI プロセスのライフサイクルを自動的に管理します。すべての通信は、stdio または TCP 経由の JSON-RPC で行われます。

リソース

ステータス

この SDK はテクニカルプレビュー段階であり、破壊的変更が行われる可能性があります。現時点では、本番環境での使用は推奨されません。

コメント