copilot-sdk

Créez des applications alimentées par GitHub Copilot à l'aide du Copilot SDK. À utiliser lors de la création d'intégrations programmatiques avec Copilot sur Node.js/TypeScript, Python, Go ou .NET. Couvre la gestion des sessions, les outils personnalisés, le streaming, les hooks, les serveurs MCP, les fournisseurs BYOK, la persistance des sessions, les agents personnalisés, les compétences et les modèles de déploiement. Nécessite GitHub Copilot CLI installé et un abonnement GitHub Copilot (sauf en utilisant BYOK).

npx skills add https://github.com/microsoft/skills --skill copilot-sdk

SDK GitHub Copilot

Construisez des applications qui interagissent programmatiquement avec GitHub Copilot. Le SDK encapsule la CLI Copilot via JSON-RPC, fournissant la gestion des sessions, les outils personnalisés, les hooks, l'intégration de serveur MCP et le streaming sur Node.js, Python, Go et .NET.

Prérequis

  • GitHub Copilot CLI installée et authentifiée (copilot --version)
  • Abonnement GitHub Copilot (Individual, Business ou Enterprise) — non requis pour BYOK
  • Runtime : Node.js 18+ / Python 3.8+ / Go 1.21+ / .NET 8.0+

Installation

Langage Package Installation
Node.js @github/copilot-sdk npm install @github/copilot-sdk
Python github-copilot-sdk pip install github-copilot-sdk
Go github.com/github/copilot-sdk/go go get github.com/github/copilot-sdk/go
.NET GitHub.Copilot.SDK dotnet add package GitHub.Copilot.SDK

Architecture

Le SDK communique avec la CLI Copilot via JSON-RPC sur stdio (défaut) ou TCP. La CLI gère les appels de modèle, l'exécution des outils, l'état de la session et le cycle de vie du serveur MCP.

Votre App → Client SDK → [stdio/TCP] → CLI Copilot → Fournisseur de modèle
                                              ↕
                                         Serveurs MCP

Modes de transport :

Mode Description Cas d'usage
Stdio (défaut) CLI en tant que sous-processus via pipes Dev local, processus unique
TCP CLI en tant que serveur réseau Multi-client, services backend

Motif fondamental : Client → Session → Message

Toute utilisation du SDK suit ce motif : créer un client, créer une session, envoyer des messages.

Node.js / 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();

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

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

session, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "What is 2 + 2?"})
fmt.Println(*response.Data.Content)

.NET

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);

Réponses en streaming

Activez la sortie en temps réel en définissant streaming: true et en vous abonnant aux événements delta.

Node.js

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

session.on("assistant.message_delta", (event) => {
    process.stdout.write(event.data.deltaContent);
});
session.on("session.idle", () => console.log());

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

Python

from copilot.generated.session_events import SessionEventType

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 joke"})

Abonnement aux événements

Méthode Description
on(handler) S'abonner à tous les événements ; retourne une fonction de désabonnement
on(eventType, handler) S'abonner à un type d'événement spécifique (Node.js uniquement)

Appelez la fonction retournée pour vous désabonner. En .NET, appelez .Dispose() sur le disposable retourné.


Outils personnalisés

Définissez des outils que Copilot peut appeler pour étendre ses capacités.

Node.js

import { CopilotClient, defineTool } 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 ({ city }) => ({ city, temperature: "72°F", condition: "sunny" }),
});

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

Python

from copilot.tools import define_tool
from pydantic import BaseModel, Field

class GetWeatherParams(BaseModel):
    city: str = Field(description="The city name")

@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
    return {"city": params.city, "temperature": "72°F", "condition": "sunny"}

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

Go

type WeatherParams struct {
    City string `json:"city" jsonschema:"The city name"`
}

getWeather := copilot.DefineTool("get_weather", "Get weather for a city",
    func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {
        return WeatherResult{City: params.City, Temperature: "72°F"}, nil
    },
)

session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
    Model: "gpt-4.1",
    Tools: []copilot.Tool{getWeather},
})

.NET

using Microsoft.Extensions.AI;
using System.ComponentModel;

var getWeather = AIFunctionFactory.Create(
    ([Description("The city name")] string city) => new { city, temperature = "72°F" },
    "get_weather", "Get the current weather for a city");

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

Exigences des outils

  • Le gestionnaire doit retourner des données sérialisables en JSON (pas undefined)
  • Les paramètres doivent suivre le format JSON Schema
  • La description de l'outil doit indiquer clairement quand il doit être utilisé

Hooks

Interceptez et personnalisez le comportement de la session à des points clés du cycle de vie.

Hook Déclencheur Cas d'usage
onPreToolUse Avant l'exécution de l'outil Contrôle des permissions, modification des arguments
onPostToolUse Après l'exécution de l'outil Transformation des résultats, journalisation, masquage
onUserPromptSubmitted L'utilisateur envoie un message Modification du prompt, filtrage, injection de contexte
onSessionStart La session commence (nouvelle ou reprise) Ajouter du contexte, configurer la session
onSessionEnd La session se termine Nettoyage, analytiques, métriques
onErrorOccurred Une erreur se produit Gestion d'erreur personnalisée, logique de retry, surveillance

Hook Pre-Tool Use

Contrôlez les permissions des outils, modifiez les arguments ou injectez du contexte avant l'exécution de l'outil.

const session = await client.createSession({
    hooks: {
        onPreToolUse: async (input) => {
            if (["shell", "bash"].includes(input.toolName)) {
                return { permissionDecision: "deny", permissionDecisionReason: "Shell access not permitted" };
            }
            return { permissionDecision: "allow" };
        },
    },
});

Champs d'entrée : timestamp, cwd, toolName, toolArgs

Champs de sortie :

Champ Type Description
permissionDecision "allow" | "deny" | "ask" S'il faut autoriser l'appel de l'outil
permissionDecisionReason string Explication pour deny/ask
modifiedArgs object Arguments modifiés à transmettre
additionalContext string Contexte supplémentaire pour la conversation
suppressOutput boolean Masquer la sortie de l'outil de la conversation

Hook Post-Tool Use

Transformez les résultats, masquez les données sensibles ou journalisez l'activité des outils après l'exécution.

hooks: {
    onPostToolUse: async (input) => {
        // Redact sensitive data from results
        if (typeof input.toolResult === "string") {
            let redacted = input.toolResult;
            for (const pattern of SENSITIVE_PATTERNS) {
                redacted = redacted.replace(pattern, "[REDACTED]");
            }
            if (redacted !== input.toolResult) {
                return { modifiedResult: redacted };
            }
        }
        return null; // Pass through unchanged
    },
}

Champs de sortie : modifiedResult, additionalContext, suppressOutput

Hook User Prompt Submitted

Modifiez ou améliorez les prompts utilisateur avant le traitement. Utile pour les templates de prompt, l'injection de contexte et la validation d'entrée.

hooks: {
    onUserPromptSubmitted: async (input) => {
        return {
            modifiedPrompt: `[User from engineering team] ${input.prompt}`,
            additionalContext: "Follow company coding standards.",
        };
    },
}

Champs de sortie : modifiedPrompt, additionalContext, suppressOutput

Hooks de cycle de vie de session

hooks: {
    onSessionStart: async (input, invocation) => {
        // input.source: "startup" | "resume" | "new"
        console.log(`Session ${invocation.sessionId} started (${input.source})`);
        return { additionalContext: "Project uses TypeScript and React." };
    },
    onSessionEnd: async (input, invocation) => {
        // input.reason: "complete" | "error" | "abort" | "timeout" | "user_exit"
        await recordMetrics({ sessionId: invocation.sessionId, reason: input.reason });
        return null;
    },
}

Hook de gestion d'erreur

hooks: {
    onErrorOccurred: async (input) => {
        // input.errorContext: "model_call" | "tool_execution" | "system" | "user_input"
        // input.recoverable: boolean
        if (input.errorContext === "model_call" && input.error.includes("rate")) {
            return { errorHandling: "retry", retryCount: 3, userNotification: "Rate limited. Retrying..." };
        }
        return null; // Default error handling
    },
}

Champs de sortie : suppressOutput, errorHandling ("retry" | "skip" | "abort"), retryCount, userNotification

Exemple de hook Python

async def on_pre_tool_use(input_data, invocation):
    if input_data["toolName"] in ["shell", "bash"]:
        return {"permissionDecision": "deny", "permissionDecisionReason": "Not permitted"}
    return {"permissionDecision": "allow"}

session = await client.create_session({
    "hooks": {"on_pre_tool_use": on_pre_tool_use}
})

Exemple de hook Go

session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
    Hooks: &copilot.SessionHooks{
        OnPreToolUse: func(input copilot.PreToolUseHookInput, inv copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {
            return &copilot.PreToolUseHookOutput{PermissionDecision: "allow"}, nil
        },
    },
})

Intégration du serveur MCP

Connectez-vous à des serveurs MCP (Model Context Protocol) pour les capacités des outils prédéfinis.

Serveur Stdio local

const session = await client.createSession({
    mcpServers: {
        filesystem: {
            type: "local",
            command: "npx",
            args: ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
            tools: ["*"],
            env: { DEBUG: "true" },
            cwd: "./servers",
            timeout: 30000,
        },
    },
});

Serveur HTTP distant

const session = await client.createSession({
    mcpServers: {
        github: {
            type: "http",
            url: "https://api.githubcopilot.com/mcp/",
            headers: { Authorization: "Bearer ${TOKEN}" },
            tools: ["*"],
        },
    },
});

Champs de configuration MCP

Local/Stdio :

Champ Type Requis Description
type "local" Non Par défaut local
command string Oui Chemin de l'exécutable
args string[] Oui Arguments de la commande
env object Non Variables d'environnement
cwd string Non Répertoire de travail
tools string[] Non ["*"] pour tous, [] pour aucun
timeout number Non Timeout en millisecondes

HTTP distant :

Champ Type Requis Description
type "http" Oui Type de serveur
url string Oui URL du serveur
headers object Non En-têtes HTTP
tools string[] Non Filtre des outils
timeout number Non Timeout en ms

Débogage MCP

Testez les serveurs MCP de manière indépendante avant l'intégration :

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | /path/to/your/mcp-server

Utilisez l'inspecteur MCP pour le débogage interactif :

npx @modelcontextprotocol/inspector /path/to/your/mcp-server

Problèmes MCP courants :

  • Les outils n'apparaissent pas → Définissez tools: ["*"] et vérifiez que le serveur répond à tools/list
  • Le serveur ne démarre pas → Utilisez des chemins de commande absolus, vérifiez cwd
  • Pollution de stdout → La sortie de débogage doit aller sur stderr, pas stdout

Authentification

Méthodes (ordre de priorité)

  1. Token explicitegithubToken dans le constructeur
  2. Clé HMAC — Variables d'environnement CAPI_HMAC_KEY ou COPILOT_HMAC_KEY
  3. Token API directGITHUB_COPILOT_API_TOKEN avec COPILOT_API_URL
  4. Variables d'environnementCOPILOT_GITHUB_TOKENGH_TOKENGITHUB_TOKEN
  5. OAuth stocké — De copilot auth login
  6. GitHub CLI — Credentials gh auth

Token programmatique

const client = new CopilotClient({ githubToken: process.env.GITHUB_TOKEN });

Application GitHub OAuth

Pour les applications multi-utilisateurs où les utilisateurs se connectent avec GitHub :

const client = new CopilotClient({
    githubToken: userAccessToken,    // gho_ ou ghu_ token du flux OAuth
    useLoggedInUser: false,          // Ne pas utiliser les credentials CLI stockés
});

Types de token supportés : gho_ (OAuth), ghu_ (GitHub App), github_pat_ (PAT à granularité fine). Non supporté : ghp_ (PAT classique — déprécié).

Désactiver la connexion automatique

Empêchez le SDK d'utiliser les credentials stockés :

const client = new CopilotClient({ useLoggedInUser: false });

BYOK (Bring Your Own Key)

Utilisez vos propres clés API — aucun abonnement Copilot requis. La CLI n'agit que comme runtime d'agent.

Configurations de fournisseur

OpenAI :

provider: { type: "openai", baseUrl: "https://api.openai.com/v1", apiKey: process.env.OPENAI_API_KEY }

Azure AI Foundry (compatible OpenAI) :

provider: {
    type: "openai",
    baseUrl: "https://your-resource.openai.azure.com/openai/v1/",
    apiKey: process.env.FOUNDRY_API_KEY,
    wireApi: "responses",  // Utilisez "responses" pour les séries GPT-5, "completions" pour les autres
}

Azure OpenAI (endpoint natif) :

provider: {
    type: "azure",
    baseUrl: "https://my-resource.openai.azure.com",  // Juste l'hôte — pas /openai/v1
    apiKey: process.env.AZURE_OPENAI_KEY,
    azure: { apiVersion: "2024-10-21" },
}

Anthropic :

provider: { type: "anthropic", baseUrl: "https://api.anthropic.com", apiKey: process.env.ANTHROPIC_API_KEY }

Ollama (local) :

provider: { type: "openai", baseUrl: "http://localhost:11434/v1" }

Référence de configuration du fournisseur

Champ Type Description
type "openai" | "azure" | "anthropic" Type de fournisseur
baseUrl string Requis. URL du point de terminaison API
apiKey string Clé API (optionnelle pour les fournisseurs locaux)
bearerToken string Authentification par token bearer (prioritaire sur apiKey)
wireApi "completions" | "responses" Format API (défaut : "completions")
azure.apiVersion string Version API Azure (défaut : "2024-10-21")

Identité gérée Azure avec BYOK

Utilisez DefaultAzureCredential pour obtenir des tokens bearer de courte durée pour les déploiements Azure :

from azure.identity import DefaultAzureCredential
from copilot import CopilotClient, ProviderConfig, SessionConfig

credential = DefaultAzureCredential()
token = credential.get_token("https://cognitiveservices.azure.com/.default").token

session = await client.create_session(SessionConfig(
    model="gpt-4.1",
    provider=ProviderConfig(
        type="openai",
        base_url=f"{foundry_url}/openai/v1/",
        bearer_token=token,
        wire_api="responses",
    ),
))

Remarque : Les tokens bearer expirent (~1 heure). Pour les applications longue durée, actualisez le token avant chaque nouvelle session. Le SDK n'actualise pas automatiquement les tokens.

Limitations de BYOK

  • Credentials statiques uniquement — pas de support natif Entra ID, OIDC ou identité gérée
  • Pas d'actualisation automatique — les tokens expirés nécessitent de créer une nouvelle session
  • Les clés ne sont pas persistées — vous devez re-fournir la configuration provider lors de la reprise de session
  • Disponibilité du modèle — limité à ce que votre fournisseur propose

Persistance de session

Reprenez les sessions lors des redémarrages en fournissant votre propre ID de session.

// Créer avec un ID explicite
const session = await client.createSession({
    sessionId: "user-123-task-456",
    model: "gpt-4.1",
});

// Reprendre plus tard (même depuis une autre instance de client)
const resumed = await client.resumeSession("user-123-task-456");
await resumed.sendAndWait({ prompt: "What did we discuss?" });

Gestion des sessions

const sessions = await client.listSessions();           // Lister toutes
const lastId = await client.getLastSessionId();          // Obtenir la plus récente
await client.deleteSession("user-123-task-456");         // Supprimer du stockage
await session.destroy();                                 // Détruire la session active

Options de reprise

Lors de la reprise, vous pouvez reconfigurer : model, systemMessage, availableTools, excludedTools, provider (requis pour BYOK), reasoningEffort, streaming, mcpServers, customAgents, skillDirectories, infiniteSessions.

Meilleures pratiques d'ID de session

Motif Exemple Cas d'usage
user-{userId}-{taskId} user-alice-pr-review-42 Applications multi-utilisateurs
tenant-{tenantId}-{workflow} tenant-acme-onboarding SaaS multi-tenants
{userId}-{taskType}-{timestamp} alice-deploy-1706932800 Nettoyage basé sur le temps

Qu'est-ce qui est persisté

L'état de la session est sauvegardé dans ~/.copilot/session-state/{sessionId}/:

Données Persistées ? Notes
Historique de conversation ✅ Oui Thread de messages complet
Résultats des appels d'outils ✅ Oui En cache pour le contexte
État de planification de l'agent ✅ Oui Fichier plan.md
Artefacts de session ✅ Oui Dans le répertoire files/
Clés de fournisseur/API ❌ Non Doit être re-fournie lors de la reprise
État des outils en mémoire ❌ Non Concevez les outils pour qu'ils soient stateless

Sessions infinies

Pour les workflows longue durée qui peuvent dépasser les limites de contexte, activez la compaction automatique :

const session = await client.createSession({
    infiniteSessions: {
        enabled: true,
        backgroundCompactionThreshold: 0.80,  // Commencer la compaction en arrière-plan à 80%
        bufferExhaustionThreshold: 0.95,       // Bloquer et compacter à 95%
    },
});

Les seuils sont des ratios d'utilisation du contexte (0.0–1.0), pas des décomptes de tokens absolus.


Agents personnalisés

Définissez des personas d'IA spécialisés :

const session = await client.createSession({
    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.",
    }],
});

Message système

Contrôlez le comportement et la personnalité de l'IA :

const session = await client.createSession({
    systemMessage: { content: "You are a helpful assistant. Always be concise." },
});

Intégration des compétences

Chargez des répertoires de compétences pour étendre les capacités de Copilot :

const session = await client.createSession({
    skillDirectories: ["./skills/code-review", "./skills/documentation"],
    disabledSkills: ["experimental-feature"],
});

Les compétences peuvent être combinées avec les agents personnalisés et les serveurs MCP :

const session = await client.createSession({
    skillDirectories: ["./skills/security"],
    customAgents: [{ name: "auditor", prompt: "Focus on OWASP Top 10." }],
    mcpServers: { postgres: { type: "local", command: "npx", args: ["-y", "@modelcontextprotocol/server-postgres"], tools: ["*"] } },
});

Gestionnaires de permissions et d'entrée

Gérez les permissions des outils et les demandes d'entrée utilisateur par programmation. Le SDK utilise un modèle de permissions deny-by-default — toutes les demandes de permission sont refusées sauf si vous fournissez un gestionnaire.

const session = await client.createSession({
    onPermissionRequest: async (request) => {
        if (request.kind === "shell") {
            return { approved: request.command.startsWith("git") };
        }
        return { approved: true };
    },
    onUserInputRequest: async (request) => {
        return { response: "yes" };
    },
});

Suivi de l'utilisation des tokens

Abonnez-vous aux événements d'utilisation au lieu d'utiliser la CLI /usage :

session.on("assistant.usage", (event) => {
    console.log("Tokens:", { input: event.data.inputTokens, output: event.data.outputTokens });
});

Motifs de déploiement

CLI locale (par défaut)

Le SDK lance automatiquement la CLI en tant que sous-processus. Configuration la plus simple — zéro configuration.

const client = new CopilotClient(); // Gère automatiquement le processus CLI

Serveur CLI externe (services backend)

Exécutez la CLI en mode headless, connectez-vous au SDK via TCP :

copilot --headless --port 4321
const client = new CopilotClient({ cliUrl: "localhost:4321" });

Support multi-client : Plusieurs clients SDK peuvent partager un serveur CLI.

CLI intégrée (applications de bureau)

Expédiez le binaire CLI avec votre application :

const client = new CopilotClient({ cliPath: path.join(__dirname, "vendor", "copilot") });

Docker Compose

services:
  copilot-cli:
    image: ghcr.io/github/copilot-cli:latest
    command: ["--headless", "--port", "4321"]
    environment:
      - COPILOT_GITHUB_TOKEN=${COPILOT_GITHUB_TOKEN}
    volumes:
      - session-data:/root/.copilot/session-state
  api:
    build: .
    environment:
      - CLI_URL=copilot-cli:4321
    depends_on: [copilot-cli]
volumes:
  session-data:

Motifs d'isolation de session

Motif Isolation Ressources Meilleur pour
CLI par utilisateur Complète Élevée SaaS multi-tenants, conformité
CLI partagée + IDs de session Logique Faible Outils internes
Sessions partagées Aucune Faible Collaboration d'équipe (nécessite un verrouillage)

Liste de contrôle pour la production

  • Nettoyage des sessions : suppression périodique des sessions expirées
  • Vérifications de santé : ping du serveur CLI, redémarrage s'il ne répond pas
  • Stockage persistant : montez ~/.copilot/session-state/ pour les conteneurs
  • Gestion des secrets : utilisez Vault/K8s Secrets pour les tokens
  • Verrouillage de session : Redis ou similaire pour l'accès aux sessions partagées
  • Arrêt gracieux : videz les sessions actives avant d'arrêter la CLI

Configuration du client

Option Type Défaut Description
cliPath string Détection automatique Chemin vers l'exécutable Copilot CLI
cliUrl string URL du serveur CLI externe
githubToken string Token GitHub pour l'authentification
useLoggedInUser boolean true Utiliser les credentials CLI stockés
logLevel string "none" "none" | "error" \