diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..7833d074 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,884 @@ +# Build Your First Copilot-Powered App + +In this tutorial, you'll use the Copilot SDK to build a command-line assistant. You'll start with the basics, add streaming responses, then add custom tools - giving Copilot the ability to call your code. + +**What you'll build:** + +``` +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! +``` + +## Prerequisites + +Before you begin, make sure you have: + +- **GitHub Copilot CLI** installed and authenticated ([Installation guide](https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli)) +- Your preferred language runtime: + - **Node.js** 18+ or **Python** 3.8+ or **Go** 1.21+ or **.NET** 8.0+ + +Verify the CLI is working: + +```bash +copilot --version +``` + +## Step 1: Install the SDK + +
+Node.js / TypeScript + +First, create a new directory and initialize your project: + +```bash +mkdir copilot-demo && cd copilot-demo +npm init -y +``` + +Then install the SDK and TypeScript runner: + +```bash +npm install @github/copilot-sdk tsx +``` + +
+ +
+Python + +```bash +pip install github-copilot-sdk +``` + +
+ +
+Go + +First, create a new directory and initialize your module: + +```bash +mkdir copilot-demo && cd copilot-demo +go mod init copilot-demo +``` + +Then install the SDK: + +```bash +go get github.com/github/copilot-sdk/go +``` + +
+ +
+.NET + +First, create a new console project: + +```bash +dotnet new console -n CopilotDemo && cd CopilotDemo +``` + +Then add the SDK: + +```bash +dotnet add package GitHub.Copilot.SDK +``` + +
+ +## Step 2: Send Your First Message + +Create a new file and add the following code. This is the simplest way to use the SDK—about 5 lines of code. + +
+Node.js / TypeScript + +Create `index.ts`: + +```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); +``` + +Run it: + +```bash +npx tsx index.ts +``` + +
+ +
+Python + +Create `main.py`: + +```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()) +``` + +Run it: + +```bash +python main.py +``` + +
+ +
+Go + +Create `main.go`: + +```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) +} +``` + +Run it: + +```bash +go run main.go +``` + +
+ +
+.NET + +Create a new console project and add this to `Program.cs`: + +```csharp +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); +``` + +Run it: + +```bash +dotnet run +``` + +
+ +**You should see:** + +``` +4 +``` + +Congratulations! You just built your first Copilot-powered app. + +## Step 3: Add Streaming Responses + +Right now, you wait for the complete response before seeing anything. Let's make it interactive by streaming the response as it's generated. + +
+Node.js / TypeScript + +Update `index.ts`: + +```typescript +import { CopilotClient, SessionEvent } 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((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 + +Update `main.py`: + +```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, + }) + + # 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({"prompt": "Tell me a short joke"}) + + await client.stop() + +asyncio.run(main()) +``` + +
+ +
+Go + +Update `main.go`: + +```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", + Streaming: true, + }) + if err != nil { + log.Fatal(err) + } + + // Listen for response chunks + 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) + if err != nil { + log.Fatal(err) + } + os.Exit(0) +} +``` + +
+ +
+.NET + +Update `Program.cs`: + +```csharp +using GitHub.Copilot.SDK; + +await using var client = new CopilotClient(); +await using var session = await client.CreateSessionAsync(new SessionConfig +{ + Model = "gpt-4.1", + Streaming = true, +}); + +// Listen for response chunks +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" }); +``` + +
+ +Run the code again. You'll see the response appear word by word. + +## Step 4: Add a Custom Tool + +Now for the powerful part. Let's give Copilot the ability to call your code by defining a custom tool. We'll create a simple weather lookup tool. + +
+Node.js / TypeScript + +Update `index.ts`: + +```typescript +import { CopilotClient, defineTool, SessionEvent } 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((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 + +Update `main.py`: + +```python +import asyncio +import random +import sys +from copilot import CopilotClient +from copilot.tools import define_tool +from copilot.generated.session_events import SessionEventType + +# Define a tool that Copilot can call +@define_tool(description="Get the current weather for a city") +async def get_weather(params: dict) -> 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({ + "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({ + "prompt": "What's the weather like in Seattle and Tokyo?" + }) + + await client.stop() + +asyncio.run(main()) +``` + +
+ +
+Go + +Update `main.go`: + +```go +package main + +import ( + "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() { + // 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(); err != nil { + log.Fatal(err) + } + defer client.Stop() + + session, err := client.CreateSession(&copilot.SessionConfig{ + Model: "gpt-4.1", + Streaming: true, + Tools: []copilot.Tool{getWeather}, + }) + if err != nil { + log.Fatal(err) + } + + 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: "What's the weather like in Seattle and Tokyo?", + }, 0) + if err != nil { + log.Fatal(err) + } + os.Exit(0) +} +``` + +
+ +
+.NET + +Update `Program.cs`: + +```csharp +using GitHub.Copilot.SDK; +using Microsoft.Extensions.AI; +using System.ComponentModel; + +await using var client = new CopilotClient(); + +// Define a tool that Copilot can call +var getWeather = AIFunctionFactory.Create( + ([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 }; + }, + "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], +}); + +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 = "What's the weather like in Seattle and Tokyo?", +}); +``` + +
+ +Run it and you'll see Copilot call your tool to get weather data, then respond with the results! + +## Step 5: Build an Interactive Assistant + +Let's put it all together into a useful interactive assistant: + +
+Node.js / TypeScript + +```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(); +``` + +Run with: + +```bash +npx tsx weather-assistant.ts +``` + +
+ +
+Python + +Create `weather_assistant.py`: + +```python +import asyncio +import random +import sys +from copilot import CopilotClient +from copilot.tools import define_tool +from copilot.generated.session_events import SessionEventType + +@define_tool(description="Get the current weather for a city") +async def get_weather(params: dict) -> 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) + + 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({"prompt": user_input}) + print("\n") + + await client.stop() + +asyncio.run(main()) +``` + +Run with: + +```bash +python weather_assistant.py +``` + +
+ +**Example session:** + +``` +🌤️ 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 +``` + +You've built an assistant with a custom tool that Copilot can call! + +--- + +## How Tools Work + +When you define a tool, you're telling Copilot: +1. **What the tool does** (description) +2. **What parameters it needs** (schema) +3. **What code to run** (handler) + +Copilot decides when to call your tool based on the user's question. When it does: +1. Copilot sends a tool call request with the parameters +2. The SDK runs your handler function +3. The result is sent back to Copilot +4. Copilot incorporates the result into its response + +--- + +## What's Next? + +Now that you've got the basics, here are more powerful features to explore: + +### Connect to MCP Servers + +MCP (Model Context Protocol) servers provide pre-built tools. Connect to GitHub's MCP server to give Copilot access to repositories, issues, and pull requests: + +```typescript +const session = await client.createSession({ + mcpServers: { + github: { + type: "http", + url: "https://api.githubcopilot.com/mcp/", + }, + }, +}); +``` + +### Create Custom Agents + +Define specialized AI personas for specific tasks: + +```typescript +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.", + }], +}); +``` + +### Customize the System Message + +Control the AI's behavior and personality: + +```typescript +const session = await client.createSession({ + systemMessage: { + content: "You are a helpful assistant for our engineering team. Always be concise.", + }, +}); +``` + +--- + +## Learn More + +- [Node.js SDK Reference](../nodejs/README.md) +- [Python SDK Reference](../python/README.md) +- [Go SDK Reference](../go/README.md) +- [.NET SDK Reference](../dotnet/README.md) +- [GitHub MCP Server Documentation](https://github.com/github/github-mcp-server) +- [MCP Servers Directory](https://github.com/modelcontextprotocol/servers) - Explore more MCP servers + +--- + +**You did it!** You've learned the core concepts of the GitHub Copilot SDK: +- ✅ Creating a client and session +- ✅ Sending messages and receiving responses +- ✅ Streaming for real-time output +- ✅ Defining custom tools that Copilot can call + +Now go build something amazing! 🚀