你将生成的内容:
You: What's the weather like in Seattle?
Copilot: Let me check the weather for Seattle...
Currently 62°F and cloudy with a chance of rain.
Typical Seattle weather!
You: How about Tokyo?
Copilot: In Tokyo it's 75°F and sunny. Great day to be outside!
先决条件
在开始之前,请确保具备:
- GitHub Copilot CLI 安装和身份验证 (Installation 指南)
- 首选语言运行时:
- Node.js 20+ 或 Python 3.11+ 或 Go 1.24+ 或 > Rust 1.94+ 或 Java 17+ 或 .NET 8.0+
验证 CLI 是否正常工作:
copilot --version
步骤 1:安装 SDK
首先,创建新目录并初始化项目:
mkdir copilot-demo && cd copilot-demo
npm init -y --init-type module
然后安装 SDK 和 TypeScript 运行程序:
npm install @github/copilot-sdk tsx
pip install github-copilot-sdk
首先,创建新的目录并初始化模块:
mkdir copilot-demo && cd copilot-demo
go mod init copilot-demo
然后安装 SDK:
go get github.com/github/copilot-sdk/go
首先,创建新的二进制箱:
cargo new copilot-demo && cd copilot-demo
然后安装示例使用的 SDK 和直接依赖项:
cargo add github-copilot-sdk --features derive
# Used by #[tokio::main] and tokio::spawn
cargo add tokio --features rt-multi-thread,macros
# Used by custom-tool parameter derives later in this guide
cargo add serde --features derive
cargo add schemars
首先,创建新的控制台项目:
dotnet new console -n CopilotDemo && cd CopilotDemo
然后添加 SDK:
dotnet add package GitHub.Copilot.SDK
首先,创建新目录并初始化项目。
Maven—添加到您的pom.xml中:
<dependency>
<groupId>com.github</groupId>
<artifactId>copilot-sdk-java</artifactId>
<version>${copilot.sdk.version}</version>
</dependency>
Gradle—添加到您的build.gradle:
implementation 'com.github:copilot-sdk-java:${copilotSdkVersion}'
步骤 2:发送第一条消息
创建新文件并添加以下代码。 这是使用 SDK 的最简单方法-大约 5 行代码。
创建 index.ts:
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
创建 main.py:
import asyncio
from copilot import CopilotClient
from copilot.session import PermissionHandler
async def main():
client = CopilotClient()
await client.start()
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-4.1")
response = await session.send_and_wait("What is 2 + 2?")
print(response.data.content)
await client.stop()
asyncio.run(main())
运行它:
python main.py
创建 main.go:
package main
import (
"context"
"fmt"
"log"
"os"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
if err != nil {
log.Fatal(err)
}
response, err := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "What is 2 + 2?"})
if err != nil {
log.Fatal(err)
}
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
fmt.Println(d.Content)
}
os.Exit(0)
}
运行它:
go run main.go
创建 src/main.rs:
use std::sync::Arc;
use std::time::Duration;
use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::start(ClientOptions::default()).await?;
let session = client
.create_session(SessionConfig::default().with_handler(Arc::new(ApproveAllHandler)))
.await?;
let response = session
.send_and_wait(
MessageOptions::new("What is 2 + 2?").with_wait_timeout(Duration::from_secs(120)),
)
.await?;
if let Some(event) = response {
if let Some(content) = event.data.get("content").and_then(|value| value.as_str()) {
println!("{content}");
}
}
session.disconnect().await?;
client.stop().await?;
Ok(())
}
运行它:
cargo run
创建新的控制台项目并将其添加到 Program.cs:
using GitHub.Copilot;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
OnPermissionRequest = PermissionHandler.ApproveAll
});
var response = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2 + 2?" });
Console.WriteLine(response?.Data.Content);
运行它:
dotnet run
创建 HelloCopilot.java:
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;
public class HelloCopilot {
public static void main(String[] args) throws Exception {
try (var client = new CopilotClient()) {
client.start().get();
var session = client.createSession(
new SessionConfig()
.setModel("gpt-4.1")
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
var response = session.sendAndWait(
new MessageOptions().setPrompt("What is 2 + 2?")
).get();
System.out.println(response.getData().content());
client.stop().get();
}
}
}
运行它:
javac -cp copilot-sdk.jar HelloCopilot.java && java -cp .:copilot-sdk.jar HelloCopilot
应会看到:
4
祝贺! 你刚刚创建了你的第一个由 Copilot 提供支持的应用。
步骤 3:添加流式响应
现在,在看到任何内容之前,请等待完整的响应。 让我们在生成响应的同时进行流式传输,让它具有交互性。
更新index.ts:
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
const session = await client.createSession({
model: "gpt-4.1",
streaming: true,
});
// Listen for response chunks
session.on("assistant.message_delta", (event) => {
process.stdout.write(event.data.deltaContent);
});
session.on("session.idle", () => {
console.log(); // New line when done
});
await session.sendAndWait({ prompt: "Tell me a short joke" });
await client.stop();
process.exit(0);
更新main.py:
import asyncio
import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.generated.session_events import SessionEventType
async def main():
client = CopilotClient()
await client.start()
session = await client.create_session(on_permission_request=PermissionHandler.approve_all, model="gpt-4.1", streaming=True)
# Listen for response chunks
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() # New line when done
session.on(handle_event)
await session.send_and_wait("Tell me a short joke")
await client.stop()
asyncio.run(main())
更新main.go:
package main
import (
"context"
"fmt"
"log"
"os"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-4.1",
Streaming: copilot.Bool(true),
})
if err != nil {
log.Fatal(err)
}
// Listen for response chunks
session.On(func(event copilot.SessionEvent) {
switch d := event.Data.(type) {
case *copilot.AssistantMessageDeltaData:
fmt.Print(d.DeltaContent)
case *copilot.SessionIdleData:
_ = d
fmt.Println()
}
})
_, err = session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Tell me a short joke"})
if err != nil {
log.Fatal(err)
}
os.Exit(0)
}
更新src/main.rs:
use std::io::{self, Write};
use std::sync::Arc;
use std::time::Duration;
use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::start(ClientOptions::default()).await?;
let mut config = SessionConfig::default();
config.streaming = Some(true);
let session = client
.create_session(config.with_handler(Arc::new(ApproveAllHandler)))
.await?;
// Listen for response chunks
let mut events = session.subscribe();
tokio::spawn(async move {
while let Ok(event) = events.recv().await {
match event.event_type.as_str() {
"assistant.message_delta" => {
if let Some(text) =
event.data.get("deltaContent").and_then(|value| value.as_str())
{
print!("{text}");
io::stdout().flush().ok();
}
}
"assistant.message" => println!(),
_ => {}
}
}
});
session
.send_and_wait(
MessageOptions::new("Tell me a short joke")
.with_wait_timeout(Duration::from_secs(120)),
)
.await?;
session.disconnect().await?;
client.stop().await?;
Ok(())
}
更新Program.cs:
using GitHub.Copilot;
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
OnPermissionRequest = PermissionHandler.ApproveAll,
Streaming = true,
});
// Listen for response chunks
session.On<SessionEvent>(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" });
更新HelloCopilot.java:
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;
public class HelloCopilot {
public static void main(String[] args) throws Exception {
try (var client = new CopilotClient()) {
client.start().get();
var session = client.createSession(
new SessionConfig()
.setModel("gpt-4.1")
.setStreaming(true)
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
// Listen for response chunks
session.on(AssistantMessageDeltaEvent.class, delta -> {
System.out.print(delta.getData().deltaContent());
});
session.on(SessionIdleEvent.class, idle -> {
System.out.println(); // New line when done
});
session.sendAndWait(
new MessageOptions().setPrompt("Tell me a short joke")
).get();
client.stop().get();
}
}
}
再次运行代码。 你将看到响应按单词显示。
事件订阅方法
SDK 提供订阅会话事件的方法:
| 方法 | Description |
|---|---|
on(handler) | 订阅所有事件;返回取消订阅函数 |
on(eventType, handler) | 订阅特定的事件类型(仅限 Node.js/TypeScript);返回取消订阅函数 |
subscribe() | 订阅所有事件(Rust);按 event_type 筛选 |
// Subscribe to all events
const unsubscribeAll = session.on((event) => {
console.log("Event:", event.type);
});
// Subscribe to specific event type
const unsubscribeIdle = session.on("session.idle", (event) => {
console.log("Session is idle");
});
// Later, to unsubscribe:
unsubscribeAll();
unsubscribeIdle();
from copilot import CopilotClient, PermissionDecisionApproveOnce
from copilot.generated.session_events import SessionEvent, SessionEventType
client = CopilotClient()
session = await client.create_session(on_permission_request=lambda req, inv: PermissionDecisionApproveOnce())
# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))
# Filter by event type in your handler
def handle_event(event: SessionEvent) -> None:
if event.type == SessionEventType.SESSION_IDLE:
print("Session is idle")
elif event.type == SessionEventType.ASSISTANT_MESSAGE:
print(f"Message: {event.data.content}")
unsubscribe = session.on(handle_event)
# Later, to unsubscribe:
unsubscribe()
# Subscribe to all events
unsubscribe = session.on(lambda event: print(f"Event: {event.type}"))
# Filter by event type in your handler
def handle_event(event):
if event.type == SessionEventType.SESSION_IDLE:
print("Session is idle")
elif event.type == SessionEventType.ASSISTANT_MESSAGE:
print(f"Message: {event.data.content}")
unsubscribe = session.on(handle_event)
# Later, to unsubscribe:
unsubscribe()
package main
import (
"fmt"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
session := &copilot.Session{}
// Subscribe to all events
unsubscribe := session.On(func(event copilot.SessionEvent) {
fmt.Println("Event:", event.Type)
})
// Filter by event type in your handler
session.On(func(event copilot.SessionEvent) {
switch d := event.Data.(type) {
case *copilot.SessionIdleData:
_ = d
fmt.Println("Session is idle")
case *copilot.AssistantMessageData:
fmt.Println("Message:", d.Content)
}
})
// Later, to unsubscribe:
unsubscribe()
}
// Subscribe to all events
unsubscribe := session.On(func(event copilot.SessionEvent) {
fmt.Println("Event:", event.Type)
})
// Filter by event type in your handler
session.On(func(event copilot.SessionEvent) {
switch d := event.Data.(type) {
case *copilot.SessionIdleData:
_ = d
fmt.Println("Session is idle")
case *copilot.AssistantMessageData:
fmt.Println("Message:", d.Content)
}
})
// Later, to unsubscribe:
unsubscribe()
let mut events = session.subscribe();
tokio::spawn(async move {
while let Ok(event) = events.recv().await {
println!("Event: {}", event.event_type);
match event.event_type.as_str() {
"session.idle" => println!("Session is idle"),
"assistant.message" => {
if let Some(content) = event.data.get("content").and_then(|value| value.as_str()) {
println!("Message: {content}");
}
}
_ => {}
}
}
});
using GitHub.Copilot;
public static class EventSubscriptionExample
{
public static void Example(CopilotSession session)
{
// Subscribe to all events
var unsubscribe = session.On<SessionEvent>(ev => Console.WriteLine($"Event: {ev.Type}"));
// Filter by event type using pattern matching
session.On<SessionEvent>(ev =>
{
switch (ev)
{
case SessionIdleEvent:
Console.WriteLine("Session is idle");
break;
case AssistantMessageEvent msg:
Console.WriteLine($"Message: {msg.Data.Content}");
break;
}
});
// Later, to unsubscribe:
unsubscribe.Dispose();
}
}
// Subscribe to all events
var unsubscribe = session.On<SessionEvent>(ev => Console.WriteLine($"Event: {ev.Type}"));
// Filter by event type using pattern matching
session.On<SessionEvent>(ev =>
{
switch (ev)
{
case SessionIdleEvent:
Console.WriteLine("Session is idle");
break;
case AssistantMessageEvent msg:
Console.WriteLine($"Message: {msg.Data.Content}");
break;
}
});
// Later, to unsubscribe:
unsubscribe.Dispose();
// Subscribe to all events
var unsubscribe = session.on(event -> {
System.out.println("Event: " + event.getType());
});
// Subscribe to a specific event type
session.on(AssistantMessageEvent.class, msg -> {
System.out.println("Message: " + msg.getData().content());
});
session.on(SessionIdleEvent.class, idle -> {
System.out.println("Session is idle");
});
// Later, to unsubscribe:
unsubscribe.close();
步骤 4:添加自定义工具
接下来是强大之处。 让 Copilot 通过定义自定义工具来调用你的代码。 我们将创建一个简单的天气查找工具。
更新index.ts:
import { CopilotClient, defineTool } from "@github/copilot-sdk";
// Define a tool that Copilot can call
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, you'd 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("assistant.message_delta", (event) => {
process.stdout.write(event.data.deltaContent);
});
session.on("session.idle", () => {
console.log(); // New line when done
});
await session.sendAndWait({
prompt: "What's the weather like in Seattle and Tokyo?",
});
await client.stop();
process.exit(0);
更新main.py:
import asyncio
import random
import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field
# Define the parameters for the tool using Pydantic
class GetWeatherParams(BaseModel):
city: str = Field(description="The name of the city to get weather for")
# Define a tool that Copilot can call
@define_tool(description="Get the current weather for a city")
async def get_weather(params: GetWeatherParams) -> dict:
city = params.city
# In a real app, you'd call a weather API here
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(on_permission_request=PermissionHandler.approve_all, 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()
if event.type == SessionEventType.SESSION_IDLE:
print()
session.on(handle_event)
await session.send_and_wait("What's the weather like in Seattle and Tokyo?")
await client.stop()
asyncio.run(main())
更新main.go:
package main
import (
"context"
"fmt"
"log"
"math/rand"
"os"
copilot "github.com/github/copilot-sdk/go"
)
// Define the parameter type
type WeatherParams struct {
City string `json:"city" jsonschema:"The city name"`
}
// Define the return type
type WeatherResult struct {
City string `json:"city"`
Temperature string `json:"temperature"`
Condition string `json:"condition"`
}
func main() {
ctx := context.Background()
// Define a tool that Copilot can call
getWeather := copilot.DefineTool(
"get_weather",
"Get the current weather for a city",
func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) {
// In a real app, you'd call a weather API here
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
},
)
client := copilot.NewClient(nil)
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-4.1",
Streaming: copilot.Bool(true),
Tools: []copilot.Tool{getWeather},
})
if err != nil {
log.Fatal(err)
}
session.On(func(event copilot.SessionEvent) {
switch d := event.Data.(type) {
case *copilot.AssistantMessageDeltaData:
fmt.Print(d.DeltaContent)
case *copilot.SessionIdleData:
_ = d
fmt.Println()
}
})
_, err = session.SendAndWait(ctx, copilot.MessageOptions{
Prompt: "What's the weather like in Seattle and Tokyo?",
})
if err != nil {
log.Fatal(err)
}
os.Exit(0)
}
更新src/main.rs:
use std::io::{self, Write};
use std::sync::Arc;
use std::time::Duration;
use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::tool::{JsonSchema, ToolHandlerRouter, define_tool};
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};
use serde::Deserialize;
#[derive(Deserialize, JsonSchema)]
struct GetWeatherParams {
city: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Define a tool that Copilot can call
let router = ToolHandlerRouter::new(
vec![define_tool(
"get_weather",
"Get the current weather for a city",
|_inv, params: GetWeatherParams| async move {
Ok(ToolResult::Text(format!(
"{}: 62°F and sunny",
params.city
)))
},
)],
Arc::new(ApproveAllHandler),
);
let tools = router.tools();
let client = Client::start(ClientOptions::default()).await?;
let mut config = SessionConfig::default();
config.streaming = Some(true);
config.tools = Some(tools);
let session = client.create_session(config.with_handler(Arc::new(router))).await?;
let mut events = session.subscribe();
tokio::spawn(async move {
while let Ok(event) = events.recv().await {
match event.event_type.as_str() {
"assistant.message_delta" => {
if let Some(text) =
event.data.get("deltaContent").and_then(|value| value.as_str())
{
print!("{text}");
io::stdout().flush().ok();
}
}
"assistant.message" => println!(),
_ => {}
}
}
});
session
.send_and_wait(
MessageOptions::new("What's the weather like in Seattle and Tokyo?")
.with_wait_timeout(Duration::from_secs(120)),
)
.await?;
session.disconnect().await?;
client.stop().await?;
Ok(())
}
更新Program.cs:
using GitHub.Copilot;
using Microsoft.Extensions.AI;
using System.ComponentModel;
await using var client = new CopilotClient();
// Define a tool that Copilot can call
var getWeather = CopilotTool.DefineTool(
([Description("The city name")] string city) =>
{
// In a real app, you'd call a weather API here
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 };
},
factoryOptions: new AIFunctionFactoryOptions
{
Name = "get_weather",
Description = "Get the current weather for a city",
}
);
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
OnPermissionRequest = PermissionHandler.ApproveAll,
Streaming = true,
Tools = [getWeather],
});
session.On<SessionEvent>(ev =>
{
if (ev is AssistantMessageDeltaEvent deltaEvent)
{
Console.Write(deltaEvent.Data.DeltaContent);
}
if (ev is SessionIdleEvent)
{
Console.WriteLine();
}
});
await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "What's the weather like in Seattle and Tokyo?",
});
更新HelloCopilot.java:
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
public class HelloCopilot {
public static void main(String[] args) throws Exception {
var random = new Random();
var conditions = List.of("sunny", "cloudy", "rainy", "partly cloudy");
// Define a tool that Copilot can call
var getWeather = ToolDefinition.create(
"get_weather",
"Get the current weather for a city",
Map.of(
"type", "object",
"properties", Map.of(
"city", Map.of("type", "string", "description", "The city name")
),
"required", List.of("city")
),
invocation -> {
var city = (String) invocation.getArguments().get("city");
var temp = random.nextInt(30) + 50;
var condition = conditions.get(random.nextInt(conditions.size()));
return CompletableFuture.completedFuture(Map.of(
"city", city,
"temperature", temp + "°F",
"condition", condition
));
}
);
try (var client = new CopilotClient()) {
client.start().get();
var session = client.createSession(
new SessionConfig()
.setModel("gpt-4.1")
.setStreaming(true)
.setTools(List.of(getWeather))
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
session.on(AssistantMessageDeltaEvent.class, delta -> {
System.out.print(delta.getData().deltaContent());
});
session.on(SessionIdleEvent.class, idle -> {
System.out.println();
});
session.sendAndWait(
new MessageOptions().setPrompt("What's the weather like in Seattle and Tokyo?")
).get();
client.stop().get();
}
}
}
运行它,你会看到 Copilot 调用你的工具来获取天气数据,然后根据结果作出回应!
步骤 5:生成交互式助手
让我们把这些内容整合成一个实用的交互式助手:
import { CopilotClient, defineTool } 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("assistant.message_delta", (event) => {
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();
运行方式:
npx tsx weather-assistant.ts
创建 weather_assistant.py:
import asyncio
import random
import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
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(on_permission_request=PermissionHandler.approve_all, 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?' or 'Compare weather in NYC and LA'\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(user_input)
print("\n")
await client.stop()
asyncio.run(main())
运行方式:
python weather_assistant.py
创建 weather-assistant.go:
package main
import (
"bufio"
"context"
"fmt"
"log"
"math/rand"
"os"
"strings"
copilot "github.com/github/copilot-sdk/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"`
}
func main() {
ctx := context.Background()
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
},
)
client := copilot.NewClient(nil)
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
Model: "gpt-4.1",
Streaming: copilot.Bool(true),
Tools: []copilot.Tool{getWeather},
})
if err != nil {
log.Fatal(err)
}
session.On(func(event copilot.SessionEvent) {
switch d := event.Data.(type) {
case *copilot.AssistantMessageDeltaData:
fmt.Print(d.DeltaContent)
case *copilot.SessionIdleData:
_ = d
fmt.Println()
}
})
fmt.Println("🌤️ Weather Assistant (type 'exit' to quit)")
fmt.Println(" Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n")
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Print("You: ")
if !scanner.Scan() {
break
}
input := scanner.Text()
if strings.ToLower(input) == "exit" {
break
}
fmt.Print("Assistant: ")
_, err = session.SendAndWait(ctx, copilot.MessageOptions{Prompt: input})
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
break
}
fmt.Println()
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "Input error: %v\n", err)
}
}
运行方式:
go run weather-assistant.go
创建 src/main.rs:
use std::io::{self, BufRead, Write};
use std::sync::Arc;
use std::time::Duration;
use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::tool::{JsonSchema, ToolHandlerRouter, define_tool};
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};
use serde::Deserialize;
#[derive(Deserialize, JsonSchema)]
struct GetWeatherParams {
city: String,
}
fn read_line() -> Option<String> {
let stdin = io::stdin();
let mut line = String::new();
stdin.lock().read_line(&mut line).ok()?;
if line.is_empty() {
return None;
}
Some(line.trim_end_matches(&['\n', '\r'][..]).to_string())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let router = ToolHandlerRouter::new(
vec![define_tool(
"get_weather",
"Get the current weather for a city",
|_inv, params: GetWeatherParams| async move {
Ok(ToolResult::Text(format!(
"{}: 62°F and sunny",
params.city
)))
},
)],
Arc::new(ApproveAllHandler),
);
let tools = router.tools();
let client = Client::start(ClientOptions::default()).await?;
let mut config = SessionConfig::default();
config.streaming = Some(true);
config.tools = Some(tools);
let session = client.create_session(config.with_handler(Arc::new(router))).await?;
let mut events = session.subscribe();
tokio::spawn(async move {
while let Ok(event) = events.recv().await {
match event.event_type.as_str() {
"assistant.message_delta" => {
if let Some(text) =
event.data.get("deltaContent").and_then(|value| value.as_str())
{
print!("{text}");
io::stdout().flush().ok();
}
}
"assistant.message" => println!(),
_ => {}
}
}
});
println!("Weather Assistant (type 'exit' to quit)");
println!("Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n");
loop {
print!("You: ");
io::stdout().flush().ok();
let Some(input) = read_line() else { break };
if input.eq_ignore_ascii_case("exit") {
break;
}
print!("Assistant: ");
io::stdout().flush().ok();
session
.send_and_wait(MessageOptions::new(input).with_wait_timeout(Duration::from_secs(120)))
.await?;
println!();
}
session.disconnect().await?;
client.stop().await?;
Ok(())
}
运行方式:
cargo run
创建新的控制台项目并更新 Program.cs:
using GitHub.Copilot;
using Microsoft.Extensions.AI;
using System.ComponentModel;
// Define the weather tool
var getWeather = CopilotTool.DefineTool(
([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 };
},
factoryOptions: new AIFunctionFactoryOptions
{
Name = "get_weather",
Description = "Get the current weather for a city",
});
await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-4.1",
OnPermissionRequest = PermissionHandler.ApproveAll,
Streaming = true,
Tools = [getWeather]
});
// Listen for response chunks
session.On<SessionEvent>(ev =>
{
if (ev is AssistantMessageDeltaEvent deltaEvent)
{
Console.Write(deltaEvent.Data.DeltaContent);
}
if (ev is SessionIdleEvent)
{
Console.WriteLine();
}
});
Console.WriteLine("🌤️ Weather Assistant (type 'exit' to quit)");
Console.WriteLine(" Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n");
while (true)
{
Console.Write("You: ");
var input = Console.ReadLine();
if (string.IsNullOrEmpty(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
break;
}
Console.Write("Assistant: ");
await session.SendAndWaitAsync(new MessageOptions { Prompt = input });
Console.WriteLine("\n");
}
运行方式:
dotnet run
创建 WeatherAssistant.java:
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.events.*;
import com.github.copilot.sdk.json.*;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
public class WeatherAssistant {
public static void main(String[] args) throws Exception {
var random = new Random();
var conditions = List.of("sunny", "cloudy", "rainy", "partly cloudy");
var getWeather = ToolDefinition.create(
"get_weather",
"Get the current weather for a city",
Map.of(
"type", "object",
"properties", Map.of(
"city", Map.of("type", "string", "description", "The city name")
),
"required", List.of("city")
),
invocation -> {
var city = (String) invocation.getArguments().get("city");
var temp = random.nextInt(30) + 50;
var condition = conditions.get(random.nextInt(conditions.size()));
return CompletableFuture.completedFuture(Map.of(
"city", city,
"temperature", temp + "°F",
"condition", condition
));
}
);
try (var client = new CopilotClient()) {
client.start().get();
var session = client.createSession(
new SessionConfig()
.setModel("gpt-4.1")
.setStreaming(true)
.setOnPermissionRequest(request ->
CompletableFuture.completedFuture(PermissionDecision.allow())
)
.setTools(List.of(getWeather))
).get();
session.on(AssistantMessageDeltaEvent.class, delta -> {
System.out.print(delta.getData().deltaContent());
});
session.on(SessionIdleEvent.class, idle -> {
System.out.println();
});
System.out.println("🌤️ Weather Assistant (type 'exit' to quit)");
System.out.println(" Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n");
var scanner = new Scanner(System.in);
while (true) {
System.out.print("You: ");
if (!scanner.hasNextLine()) break;
var input = scanner.nextLine();
if (input.equalsIgnoreCase("exit")) break;
System.out.print("Assistant: ");
session.sendAndWait(
new MessageOptions().setPrompt(input)
).get();
System.out.println("\n");
}
client.stop().get();
}
}
}
运行方式:
javac -cp copilot-sdk.jar WeatherAssistant.java && java -cp .:copilot-sdk.jar WeatherAssistant
示例会话:
🌤️ Weather Assistant (type 'exit' to quit)
Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'
You: What's the weather in Seattle?
Assistant: Let me check the weather for Seattle...
It's currently 62°F and cloudy in Seattle.
You: How about Tokyo and London?
Assistant: I'll check both cities for you:
- Tokyo: 75°F and sunny
- London: 58°F and rainy
You: exit
你已使用Copilot可以调用的自定义工具构建了助手!
工具的工作原理
定义工具时,你将告诉Copilot:
- 该工具的作用 (说明)
- 它需要哪些参数 (架构)
- 要运行的代码 (处理程序)
Copilot根据用户的问题决定何时调用工具。 当这种情况发生时:
- Copilot使用参数发送工具调用请求
- SDK 运行你的处理函数
- 结果被发回给 Copilot
- Copilot将结果合并到其响应中
接下来会发生什么?
现在,你已获得基础知识,下面提供了更强大的功能来探索:
连接到 MCP 服务器
MCP(模型上下文协议)服务器提供预构建的工具。 连接到 GitHub 的 MCP 服务器,使 Copilot 能够访问存储库、Issue 和拉取请求:
const session = await client.createSession({
mcpServers: {
github: {
type: "http",
url: "https://api.githubcopilot.com/mcp/",
},
},
});
📖 ** Using MCP servers with the GitHub Copilot SDK** - 了解本地服务器与远程服务器、所有配置选项和故障排除。
创建自定义代理
定义特定任务的专用 AI 角色:
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.",
}],
});
提示
还可以在会话配置中设置 agent: "pr-reviewer" ,以便从一开始就预先选择此代理。 有关详细信息,请参阅 自定义代理和子代理编排 。
自定义系统消息
通过追加说明来控制 AI 的行为和个性:
const session = await client.createSession({
systemMessage: {
content: "You are a helpful assistant for our engineering team. Always be concise.",
},
});
若要进行更精细的控制,请使用 mode: "customize" 替代系统提示的各个部分,同时保留其余部分:
const session = await client.createSession({
systemMessage: {
mode: "customize",
sections: {
tone: { action: "replace", content: "Respond in a warm, professional tone. Be thorough in explanations." },
code_change_rules: { action: "remove" },
guidelines: { action: "append", content: "\n* Always cite data sources" },
},
content: "Focus on financial analysis and reporting.",
},
});
可用节 ID:identity,tone,tool_efficiency,environment_context,code_change_rules,guidelines,safety,tool_instructions,custom_instructions,runtime_instructions,last_instructions。
每个替代都支持四个操作: replace、 remove、 append和 prepend。 未知节 ID 会被妥善处理——内容会追加到附加说明中,并发出警告;对于未知节上的 remove,会将其静默忽略。
有关 TypeScript 中的示例,请参阅特定于语言的 SDK README, Python、Go、Rust、Java和C#。
连接到外部 CLI 服务器
默认情况下,SDK 会自动管理Copilot CLI 进程生命周期,根据需要启动和停止 CLI。 但是,还可以单独在服务器模式下运行 CLI,并让 SDK 连接到它。 这可用于:
- 调试:使 CLI 在 SDK 重启之间保持运行以检查日志
- 资源共享:多个 SDK 客户端可以连接到同一 CLI 服务器
- 开发:使用自定义设置或在不同的环境中运行 CLI
在服务器模式下运行 CLI
使用 --headless 标志在服务器模式下启动 CLI,并根据需要指定端口:
copilot --headless --port 4321
如果未指定端口,CLI 将选择随机可用的端口。
默认情况下,无头服务器仅接受来自环回 (127.0.0.1) 的连接,因此 SDK 必须在同一台机器上运行。 若要接受来自其他主机的连接(例如,在容器中或在单独的服务器上运行 CLI 时),请使用 --host以下命令绑定到非环回地址:
# Listen on all interfaces
copilot --headless --host 0.0.0.0 --port 4321
警告
将无头服务器暴露在非回环地址上,会使任何能够路由到该地址的用户都可以访问该服务器。 将其与适合你的环境的网络控制(防火墙、专用网络、反向代理)和身份验证配对。
将 SDK 连接到外部服务器
在服务器模式下运行 CLI 后,使用“cli url”选项将 SDK 客户端配置为连接到它:
import { CopilotClient, approveAll } from "@github/copilot-sdk";
const client = new CopilotClient({
cliUrl: "localhost:4321"
});
// Use the client normally
const session = await client.createSession({ onPermissionRequest: approveAll });
// ...
from copilot import CopilotClient, RuntimeConnection
from copilot.session import PermissionHandler
client = CopilotClient(connection=RuntimeConnection.for_uri("localhost:4321"))
await client.start()
# Use the client normally
session = await client.create_session(on_permission_request=PermissionHandler.approve_all)
# ...
package main
import (
"context"
"log"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(&copilot.ClientOptions{
Connection: copilot.UriConnection{URL: "localhost:4321"},
})
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
// Use the client normally
_, _ = client.CreateSession(ctx, &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
}
import copilot "github.com/github/copilot-sdk/go"
client := copilot.NewClient(&copilot.ClientOptions{
Connection: copilot.UriConnection{URL: "localhost:4321"},
})
if err := client.Start(ctx); err != nil {
log.Fatal(err)
}
defer client.Stop()
// Use the client normally
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
// ...
use std::sync::Arc;
use github_copilot_sdk::handler::ApproveAllHandler;
use github_copilot_sdk::{Client, ClientOptions, SessionConfig, Transport};
let mut options = ClientOptions::default();
options.transport = Transport::External {
host: "localhost".to_string(),
port: 4321,
};
let client = Client::start(options).await?;
// Use the client normally
let session = client
.create_session(SessionConfig::default().with_handler(Arc::new(ApproveAllHandler)))
.await?;
// ...
using GitHub.Copilot;
using var client = new CopilotClient(new CopilotClientOptions
{
Connection = RuntimeConnection.ForUri("localhost:4321"),
});
// Use the client normally
await using var session = await client.CreateSessionAsync(new()
{
OnPermissionRequest = PermissionHandler.ApproveAll
});
// ...
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.json.*;
var client = new CopilotClient(
new CopilotClientOptions().setCliUrl("localhost:4321")
);
client.start().get();
// Use the client normally
var session = client.createSession(
new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
).get();
// ...
注意: 当提供 cli_url / cliUrl / Go 的 UriConnection,或 Rust 使用 Transport::External 时,SDK 不会启动或管理 CLI 进程——它只会连接到指定 URL 处的现有服务器。
遥测和可观测性
Copilot SDK 支持使用 OpenTelemetry 进行分布式跟踪。 向客户端提供配置 telemetry ,以便从 CLI 进程启用跟踪导出,并在 SDK 和 CLI 之间自动传播 W3C 跟踪上下文 。
启用遥测
创建客户端时,传入 telemetry(或 Telemetry)配置。 这是选择加入 - 不需要单独的“已启用”标志。
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient({
telemetry: {
otlpEndpoint: "http://localhost:4318",
},
});
可选的同级依赖项:@opentelemetry/api
from copilot import CopilotClient, CopilotClientOptions
client = CopilotClient(CopilotClientOptions(
telemetry={
"otlp_endpoint": "http://localhost:4318",
},
))
使用遥测额外功能进行安装: pip install copilot-sdk[telemetry] (提供 opentelemetry-api)
client, err := copilot.NewClient(copilot.ClientOptions{
Telemetry: &copilot.TelemetryConfig{
OTLPEndpoint: "http://localhost:4318",
},
})
依赖:go.opentelemetry.io/otel
use github_copilot_sdk::{Client, ClientOptions, OtelExporterType, TelemetryConfig};
let mut options = ClientOptions::default();
options.telemetry = Some(
TelemetryConfig::new()
.with_exporter_type(OtelExporterType::OtlpHttp)
.with_otlp_endpoint("http://localhost:4318"),
);
let client = Client::start(options).await?;
没有额外的依赖项 - SDK 为生成的 CLI 进程注入遥测环境变量。
var client = new CopilotClient(new CopilotClientOptions
{
Telemetry = new TelemetryConfig
{
OtlpEndpoint = "http://localhost:4318",
},
});
没有额外的依赖项 - 使用内置 System.Diagnostics.Activity。
import com.github.copilot.sdk.CopilotClient;
import com.github.copilot.sdk.json.*;
var client = new CopilotClient(new CopilotClientOptions()
.setTelemetry(new TelemetryConfig()
.setOtlpEndpoint("http://localhost:4318")));
依赖:io.opentelemetry:opentelemetry-api
TelemetryConfig 选项
| 选项 | Node.js | Python | Go | Rust | Java | .NET | Description |
|---|---|---|---|---|---|---|---|
| OTLP 终结点 | otlpEndpoint | otlp_endpoint | OTLPEndpoint | otlp_endpoint | otlpEndpoint | OtlpEndpoint | OTLP HTTP 终结点 URL |
| 文件路径 | filePath | file_path | FilePath | file_path | filePath | FilePath | JSON 行跟踪输出的文件路径 |
| 导出程序类型 | exporterType | exporter_type | ExporterType | exporter_type | exporterType | ExporterType | |
"otlp-http" 或 "file" | |||||||
| 源名称 | sourceName | source_name | SourceName | source_name | sourceName | SourceName | 仪器范围名称 |
| 捕获内容 | captureContent | capture_content | CaptureContent | capture_content | captureContent | CaptureContent | 是否捕获消息内容 |
文件导出
若要将追踪数据写入本地文件而不是 OTLP 端点,请执行以下操作:
const client = new CopilotClient({
telemetry: {
filePath: "./traces.jsonl",
exporterType: "file",
},
});
跟踪上下文传播
自动传播跟踪上下文 - 无需手动检测:
- SDK → CLI:来自当前 span/活动的
traceparent和tracestate请求头会包含在session.create、session.resume和session.sendRPC 调用中。 - CLI → SDK:当 CLI 调用工具处理程序时,将传播 CLI 范围中的跟踪上下文,以便工具代码在正确的父范围下运行。
📖 ** Copilot SDK 的 OpenTelemetry 检测** — TelemetryConfig 选项、跟踪上下文传播和每种语言依赖项。
了解详细信息
- Authentication - GitHub OAuth、环境变量和 BYOK
- BYOK (bring your own key) - 使用你自己的 Azure AI Foundry、OpenAI 等 API 密钥。
- Node.js SDK 参考
- Python SDK 参考文档
- Go SDK 参考
- Rust SDK 参考文档
- .NET SDK 参考
- Java SDK 参考
- Using MCP servers with the GitHub Copilot SDK - 通过模型上下文协议集成外部工具
- GitHub MCP 服务器文档
- MCP 服务器目录 - 浏览更多 MCP 服务器
- Copilot SDK 的 OpenTelemetry 检测 - TelemetryConfig、跟踪上下文传播和各语言依赖项
你做到了! 你已了解 GitHub Copilot SDK 的核心概念:
- ✅ 创建客户端和会话
- ✅ 发送消息和接收响应
- ✅ 用于实时输出的流式传输
- ✅定义Copilot可以调用的自定义工具
现在就去创造精彩的作品吧! 🚀