跳至內容

內嵌 Copilot SDK

本導覽說明 API 如何內嵌 GitHub Copilot SDK,並將 Copilot 工作階段轉換為應用程式服務。您將瞭解應用程式如何啟動 SDK 用戶端、建立串流工作階段、接聽工作階段事件,以及避免使用過期的模型目錄。

SDK 的使用位置

主要整合點是 CopilotChatService。它以下列方式匯入 SDK:

using GitHub.Copilot;

這個命名空間是常見的移轉陷阱。在 1.0.0 SDK 發行前,命名空間為 GitHub.Copilot.SDK;此處使用的 v1.x 程式碼中,命名空間為 GitHub.Copilot ,即使套件參考仍名為 GitHub.Copilot.SDK

一個長時間存續的用戶端

Program.csCopilotChatService 註冊為單一執行個體:

builder.Services.AddSingleton<CopilotChatService>();

服務擁有單一 CopilotClient 欄位,存續期間與 API 處理程序相同。如此可避免每個 HTTP 要求都啟動及停止 Copilot 連線,並透過單一受控服務提供模型清單與聊天串流。

CopilotChatService 會實作 IAsyncDisposable。當主機釋放此單一執行個體時, CopilotChatService.DisposeAsync 會呼叫 CopilotClient.StopAsync() ,使 SDK 連線能順利關閉。

啟動及復原用戶端

CopilotChatService.EnsureStartedAsync 是列出模型或進行聊天前的閘道:

if (_isStarted && _client != null) return;

_isStarted = false;
if (_client != null)
{
    try { await _client.StopAsync(); } catch { }
}

_client = new CopilotClient();
await _client.StartAsync();
_isStarted = true;

此方法會將 _isStarted 以及 _client 作為單一真實來源。如果用戶端尚未啟動,或先前的失敗已將其標記為狀況不良,服務會停止所有舊用戶端並建立新的 CopilotClient、啟動它,並記錄新狀態。

復原作業會在下列位置完成: CopilotChatService.ChatStreamAsync。背景工作階段會攔截 IOException,記錄 Copilot 連線已中斷、將 _isStarted = false,並以例外狀況完成輸出通道。下一個要求將再次呼叫 EnsureStartedAsync 並重新建立用戶端。

建立串流工作階段

CopilotChatService.ChatStreamAsync 會建立 SessionConfig ,供每個提示詞使用:

SessionConfig config = new()
{
    Model = model,
    Streaming = true,
    SystemMessage = systemMessage != null ? new SystemMessageConfig
    {
        Mode = SystemMessageMode.Append,
        Content = systemMessage
    } : null
};

選取的模型來自要求,若未指定則使用 claude-haiku-4.5 作為服務預設值。 Streaming = true 會要求 SDK 發出回應增量。若提供系統訊息,則會建立 SystemMessageConfig,並以 Append 模式傳送,因此會附加應用程式內容,而不是取代工作階段的基礎系統行為。

工作階段使用下列方式建立: await using,因此會在該提示詞完成後以非同步方式釋放:

await using var session = await _client.CreateSessionAsync(config);

工作階段事件

服務會使用明確的泛型型別引數訂閱 SDK 事件:

session.On<SessionEvent>(evt => { /* switch on event type */ });

在 v1.x 中,明確的 <SessionEvent> 是必要的。舊版非泛型形式已無法可靠推斷事件型別,因此省略型別引數是常見的升級失敗原因。

CopilotChatService 會處理四種事件結構:

  • AssistantMessageDeltaEvent 會將 DeltaContent 寫入輸出串流。
  • AssistantMessageEvent 會記錄助理回應已完成。
  • SessionIdleEvent 會完成 TaskCompletionSource ,用於等候該回合完成。
  • SessionErrorEvent 會記錄 SDK 錯誤,並以例外狀況完成等候工作。

訂閱後,會使用下列方式傳送提示詞:

await session.SendAsync(new MessageOptions { Prompt = prompt });

將 SDK 事件銜接至 IAsyncEnumerable

SDK 工作階段會在背景 Task。增量內容會寫入 Channel<string>,而外層非同步迭代器會讀取該通道:

var outputChannel = Channel.CreateUnbounded<string>();

_ = Task.Run(async () =>
{
    // create session, handle events, write chunks
}, cancellationToken);

await foreach (var chunk in outputChannel.Reader.ReadAllAsync(cancellationToken))
{
    yield return chunk;
}

這個結構是刻意設計的。C# 非同步迭代器無法在 try/catch 區塊內使用 yield return;該區塊擁有 SDK 工作階段。通道可讓工作階段在內部處理例外狀況與完成作業,外層方法則向控制器公開簡潔的 IAsyncEnumerable<string>

列出線上模型

CopilotChatService.ListModelsAsync 會呼叫 CopilotClient.ListModelsAsync() ,並回傳已連線 Copilot CLI 實際提供的 ID 與顯示名稱:

var models = await _client.ListModelsAsync(cancellationToken);

硬式編碼模型 ID 是個陷阱。模型可用性會因帳戶、推出階段與提供者而異;此示範先前使用的過期硬式編碼清單,導致六個模型中只有一個可用。API 在下列位置仍保有靜態目錄: ChatController.AvailableModels,但它僅用作中繼資料與備援。正常路徑會從 SDK 擷取線上模型清單。