diff --git a/.github/agents/docs-maintenance.agent.md b/.github/agents/docs-maintenance.agent.md
index 9b605c26..3f55e848 100644
--- a/.github/agents/docs-maintenance.agent.md
+++ b/.github/agents/docs-maintenance.agent.md
@@ -27,7 +27,7 @@ The human will then review the plan and selectively ask Copilot to implement spe
Create a file called `docs/IMPROVEMENT_PLAN.md` with this structure:
-```markdown
+````markdown
# Documentation Improvement Plan
Generated: [date]
@@ -43,6 +43,7 @@ Audited by: docs-maintenance agent
## Critical Issues (Fix Immediately)
### 1. [Issue Title]
+
- **File**: `docs/path/to/file.md`
- **Line**: ~42
- **Problem**: [description]
@@ -53,6 +54,7 @@ Audited by: docs-maintenance agent
## High Priority (Should Fix Soon)
### 1. [Issue Title]
+
- **File**: `docs/path/to/file.md`
- **Problem**: [description]
- **Fix**: [specific action to take]
@@ -79,15 +81,18 @@ The following code samples don't match the SDK interface:
### File: `docs/example.md`
**Line ~25 - TypeScript sample uses wrong method name:**
+
```typescript
// Current (wrong):
-await client.create_session()
+await client.create_session();
// Should be:
-await client.createSession()
+await client.createSession();
```
+````
**Line ~45 - Python sample has camelCase:**
+
```python
# Current (wrong):
client = CopilotClient(cliPath="/usr/bin/copilot")
@@ -98,14 +103,15 @@ client = CopilotClient(cli_path="/usr/bin/copilot")
## Broken Links
-| Source File | Line | Broken Link | Suggested Fix |
-|-------------|------|-------------|---------------|
-| `docs/a.md` | 15 | `./missing.md` | Remove or create file |
+| Source File | Line | Broken Link | Suggested Fix |
+| ----------- | ---- | -------------- | --------------------- |
+| `docs/a.md` | 15 | `./missing.md` | Remove or create file |
## Consistency Issues
- [ ] Term "XXX" used inconsistently (file1.md says "A", file2.md says "B")
- [ ] ...
+
```
After creating this plan file, your work is complete. The platform (github.com) will handle creating a PR if applicable.
@@ -242,21 +248,23 @@ When auditing documentation, check:
The expected documentation structure is:
```
+
docs/
-├── getting-started.md # Quick start tutorial
-├── debugging.md # General debugging guide
-├── compatibility.md # SDK vs CLI feature comparison
+├── getting-started.md # Quick start tutorial
+├── debugging.md # General debugging guide
+├── compatibility.md # SDK vs CLI feature comparison
├── hooks/
-│ ├── overview.md # Hooks introduction
-│ ├── pre-tool-use.md # Permission control
-│ ├── post-tool-use.md # Result transformation
-│ ├── user-prompt-submitted.md
-│ ├── session-lifecycle.md
-│ └── error-handling.md
+│ ├── overview.md # Hooks introduction
+│ ├── pre-tool-use.md # Permission control
+│ ├── post-tool-use.md # Result transformation
+│ ├── user-prompt-submitted.md
+│ ├── session-lifecycle.md
+│ └── error-handling.md
└── mcp/
- ├── overview.md # MCP configuration
- └── debugging.md # MCP troubleshooting
-```
+├── overview.md # MCP configuration
+└── debugging.md # MCP troubleshooting
+
+````
Additional directories to consider:
- `docs/tools/` - Custom tool development
@@ -274,7 +282,7 @@ find docs -name "*.md" -type f | sort
# Check for README references
grep -r "docs/" README.md
-```
+````
### Step 2: Check Feature Coverage
@@ -342,6 +350,7 @@ cat nodejs/src/types.ts | grep -A 10 "export interface ExportSessionOptions"
```
**Must match:**
+
- `CopilotClient` constructor options: `cliPath`, `cliUrl`, `useStdio`, `port`, `logLevel`, `autoStart`, `autoRestart`, `env`, `githubToken`, `useLoggedInUser`
- `createSession()` config: `model`, `tools`, `hooks`, `systemMessage`, `mcpServers`, `availableTools`, `excludedTools`, `streaming`, `reasoningEffort`, `provider`, `infiniteSessions`, `customAgents`, `workingDirectory`
- `CopilotSession` methods: `send()`, `sendAndWait()`, `getMessages()`, `destroy()`, `abort()`, `on()`, `once()`, `off()`
@@ -360,6 +369,7 @@ cat python/copilot/types.py | grep -A 15 "class SessionHooks"
```
**Must match (snake_case):**
+
- `CopilotClient` options: `cli_path`, `cli_url`, `use_stdio`, `port`, `log_level`, `auto_start`, `auto_restart`, `env`, `github_token`, `use_logged_in_user`
- `create_session()` config keys: `model`, `tools`, `hooks`, `system_message`, `mcp_servers`, `available_tools`, `excluded_tools`, `streaming`, `reasoning_effort`, `provider`, `infinite_sessions`, `custom_agents`, `working_directory`
- `CopilotSession` methods: `send()`, `send_and_wait()`, `get_messages()`, `destroy()`, `abort()`, `export_session()`
@@ -378,7 +388,8 @@ cat go/types.go | grep -A 15 "type SessionHooks struct"
```
**Must match (PascalCase for exported):**
-- `ClientOptions` fields: `CLIPath`, `CLIUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `AutoRestart`, `Env`, `GithubToken`, `UseLoggedInUser`
+
+- `ClientOptions` fields: `CLIPath`, `CLIUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `AutoRestart`, `Env`, `GitHubToken`, `UseLoggedInUser`
- `SessionConfig` fields: `Model`, `Tools`, `Hooks`, `SystemMessage`, `MCPServers`, `AvailableTools`, `ExcludedTools`, `Streaming`, `ReasoningEffort`, `Provider`, `InfiniteSessions`, `CustomAgents`, `WorkingDirectory`
- `Session` methods: `Send()`, `SendAndWait()`, `GetMessages()`, `Destroy()`, `Abort()`, `ExportSession()`
- Hook fields: `OnPreToolUse`, `OnPostToolUse`, `OnUserPromptSubmitted`, `OnSessionStart`, `OnSessionEnd`, `OnErrorOccurred`
@@ -396,7 +407,8 @@ cat dotnet/src/Types.cs | grep -A 15 "public class SessionHooks"
```
**Must match (PascalCase):**
-- `CopilotClientOptions` properties: `CliPath`, `CliUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `AutoRestart`, `Environment`, `GithubToken`, `UseLoggedInUser`
+
+- `CopilotClientOptions` properties: `CliPath`, `CliUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `AutoRestart`, `Environment`, `GitHubToken`, `UseLoggedInUser`
- `SessionConfig` properties: `Model`, `Tools`, `Hooks`, `SystemMessage`, `McpServers`, `AvailableTools`, `ExcludedTools`, `Streaming`, `ReasoningEffort`, `Provider`, `InfiniteSessions`, `CustomAgents`, `WorkingDirectory`
- `CopilotSession` methods: `SendAsync()`, `SendAndWaitAsync()`, `GetMessagesAsync()`, `DisposeAsync()`, `AbortAsync()`, `ExportSessionAsync()`
- Hook properties: `OnPreToolUse`, `OnPostToolUse`, `OnUserPromptSubmitted`, `OnSessionStart`, `OnSessionEnd`, `OnErrorOccurred`
@@ -429,7 +441,7 @@ cat dotnet/src/Types.cs | grep -A 15 "public class SessionHooks"
Run this to extract all code blocks and check for common issues:
-```bash
+````bash
# Extract TypeScript examples and check for Python-style naming
grep -A 20 '```typescript' docs/**/*.md | grep -E "cli_path|create_session|send_and_wait" && echo "ERROR: Python naming in TypeScript"
@@ -438,7 +450,7 @@ grep -A 20 '```python' docs/**/*.md | grep -E "cliPath|createSession|sendAndWait
# Check Go examples have context parameter
grep -A 20 '```go' docs/**/*.md | grep -E "CreateSession\([^c]|Send\([^c]" && echo "WARNING: Go method may be missing context"
-```
+````
### Step 6: Create the Plan
@@ -448,6 +460,7 @@ After completing the audit:
2. Your work is complete - the platform handles PR creation
The human reviewer can then:
+
- Review the plan
- Comment on specific items to prioritize
- Ask Copilot to implement specific fixes from the plan
diff --git a/docs/auth/index.md b/docs/auth/index.md
index 9fc65fe2..fac50fc6 100644
--- a/docs/auth/index.md
+++ b/docs/auth/index.md
@@ -4,18 +4,19 @@ The GitHub Copilot SDK supports multiple authentication methods to fit different
## Authentication Methods
-| Method | Use Case | Copilot Subscription Required |
-|--------|----------|-------------------------------|
-| [GitHub Signed-in User](#github-signed-in-user) | Interactive apps where users sign in with GitHub | Yes |
-| [OAuth GitHub App](#oauth-github-app) | Apps acting on behalf of users via OAuth | Yes |
-| [Environment Variables](#environment-variables) | CI/CD, automation, server-to-server | Yes |
-| [BYOK (Bring Your Own Key)](./byok.md) | Using your own API keys (Azure AI Foundry, OpenAI, etc.) | No |
+| Method | Use Case | Copilot Subscription Required |
+| ----------------------------------------------- | -------------------------------------------------------- | ----------------------------- |
+| [GitHub Signed-in User](#github-signed-in-user) | Interactive apps where users sign in with GitHub | Yes |
+| [OAuth GitHub App](#oauth-github-app) | Apps acting on behalf of users via OAuth | Yes |
+| [Environment Variables](#environment-variables) | CI/CD, automation, server-to-server | Yes |
+| [BYOK (Bring Your Own Key)](./byok.md) | Using your own API keys (Azure AI Foundry, OpenAI, etc.) | No |
## GitHub Signed-in User
This is the default authentication method when running the Copilot CLI interactively. Users authenticate via GitHub OAuth device flow, and the SDK uses their stored credentials.
**How it works:**
+
1. User runs `copilot` CLI and signs in via GitHub OAuth
2. Credentials are stored securely in the system keychain
3. SDK automatically uses stored credentials
@@ -51,6 +52,7 @@ await client.start()
Go
+
```go
import copilot "github.com/github/copilot-sdk/go"
@@ -73,6 +75,7 @@ await using var client = new CopilotClient();
**When to use:**
+
- Desktop applications where users interact directly
- Development and testing environments
- Any scenario where a user can sign in interactively
@@ -82,6 +85,7 @@ await using var client = new CopilotClient();
Use an OAuth GitHub App to authenticate users through your application and pass their credentials to the SDK. This enables your application to make Copilot API requests on behalf of users who authorize your app.
**How it works:**
+
1. User authorizes your OAuth GitHub App
2. Your app receives a user access token (`gho_` or `ghu_` prefix)
3. Pass the token to the SDK via `githubToken` option
@@ -95,8 +99,8 @@ Use an OAuth GitHub App to authenticate users through your application and pass
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient({
- githubToken: userAccessToken, // Token from OAuth flow
- useLoggedInUser: false, // Don't use stored CLI credentials
+ githubToken: userAccessToken, // Token from OAuth flow
+ useLoggedInUser: false, // Don't use stored CLI credentials
});
```
@@ -121,11 +125,12 @@ await client.start()
Go
+
```go
import copilot "github.com/github/copilot-sdk/go"
client := copilot.NewClient(&copilot.ClientOptions{
- GithubToken: userAccessToken, // Token from OAuth flow
+ GitHubToken: userAccessToken, // Token from OAuth flow
UseLoggedInUser: copilot.Bool(false), // Don't use stored CLI credentials
})
```
@@ -136,12 +141,13 @@ client := copilot.NewClient(&copilot.ClientOptions{
.NET
+
```csharp
using GitHub.Copilot.SDK;
await using var client = new CopilotClient(new CopilotClientOptions
{
- GithubToken = userAccessToken, // Token from OAuth flow
+ GitHubToken = userAccessToken, // Token from OAuth flow
UseLoggedInUser = false, // Don't use stored CLI credentials
});
```
@@ -149,14 +155,17 @@ await using var client = new CopilotClient(new CopilotClientOptions
**Supported token types:**
+
- `gho_` - OAuth user access tokens
-- `ghu_` - GitHub App user access tokens
+- `ghu_` - GitHub App user access tokens
- `github_pat_` - Fine-grained personal access tokens
**Not supported:**
+
- `ghp_` - Classic personal access tokens (deprecated)
**When to use:**
+
- Web applications where users sign in via GitHub
- SaaS applications building on top of Copilot
- Any multi-user application where you need to make requests on behalf of different users
@@ -166,11 +175,13 @@ await using var client = new CopilotClient(new CopilotClientOptions
For automation, CI/CD pipelines, and server-to-server scenarios, you can authenticate using environment variables.
**Supported environment variables (in priority order):**
+
1. `COPILOT_GITHUB_TOKEN` - Recommended for explicit Copilot usage
2. `GH_TOKEN` - GitHub CLI compatible
3. `GITHUB_TOKEN` - GitHub Actions compatible
**How it works:**
+
1. Set one of the supported environment variables with a valid token
2. The SDK automatically detects and uses the token
@@ -204,6 +215,7 @@ await client.start()
**When to use:**
+
- CI/CD pipelines (GitHub Actions, Jenkins, etc.)
- Automated testing
- Server-side applications with service accounts
@@ -214,12 +226,14 @@ await client.start()
BYOK allows you to use your own API keys from model providers like Azure AI Foundry, OpenAI, or Anthropic. This bypasses GitHub Copilot authentication entirely.
**Key benefits:**
+
- No GitHub Copilot subscription required
- Use enterprise model deployments
- Direct billing with your model provider
- Support for Azure AI Foundry, OpenAI, Anthropic, and OpenAI-compatible endpoints
**See the [BYOK documentation](./byok.md) for complete details**, including:
+
- Azure AI Foundry setup
- Provider configuration options
- Limitations and considerations
@@ -245,7 +259,7 @@ To prevent the SDK from automatically using stored credentials or `gh` CLI auth,
```typescript
const client = new CopilotClient({
- useLoggedInUser: false, // Only use explicit tokens
+ useLoggedInUser: false, // Only use explicit tokens
});
```
@@ -255,6 +269,7 @@ const client = new CopilotClient({
Python
+
```python
client = CopilotClient({
"use_logged_in_user": False, # Only use explicit tokens
@@ -267,6 +282,7 @@ client = CopilotClient({
Go
+
```go
client := copilot.NewClient(&copilot.ClientOptions{
UseLoggedInUser: copilot.Bool(false), // Only use explicit tokens
diff --git a/docs/debugging.md b/docs/debugging.md
index 6183cccd..258d392a 100644
--- a/docs/debugging.md
+++ b/docs/debugging.md
@@ -24,7 +24,7 @@ The first step in debugging is enabling verbose logging to see what's happening
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient({
- logLevel: "debug", // Options: "none", "error", "warning", "info", "debug", "all"
+ logLevel: "debug", // Options: "none", "error", "warning", "info", "debug", "all"
});
```
@@ -45,6 +45,7 @@ client = CopilotClient({"log_level": "debug"})
Go
+
```go
import copilot "github.com/github/copilot-sdk/go"
@@ -59,6 +60,7 @@ client := copilot.NewClient(&copilot.ClientOptions{
.NET
+
```csharp
using GitHub.Copilot.SDK;
using Microsoft.Extensions.Logging;
@@ -111,6 +113,7 @@ const client = new CopilotClient({
Go
+
```go
// The Go SDK does not currently support passing extra CLI arguments.
// For custom log directories, run the CLI manually with --log-dir
@@ -144,6 +147,7 @@ var client = new CopilotClient(new CopilotClientOptions
1. Install the CLI: [Installation guide](https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli)
2. Verify installation:
+
```bash
copilot --version
```
@@ -158,6 +162,7 @@ var client = new CopilotClient(new CopilotClientOptions
cliPath: "/usr/local/bin/copilot",
});
```
+
@@ -166,6 +171,7 @@ var client = new CopilotClient(new CopilotClientOptions
```python
client = CopilotClient({"cli_path": "/usr/local/bin/copilot"})
```
+
@@ -176,6 +182,7 @@ var client = new CopilotClient(new CopilotClientOptions
CLIPath: "/usr/local/bin/copilot",
})
```
+
@@ -187,6 +194,7 @@ var client = new CopilotClient(new CopilotClientOptions
CliPath = "/usr/local/bin/copilot"
});
```
+
### "Not authenticated"
@@ -196,6 +204,7 @@ var client = new CopilotClient(new CopilotClientOptions
**Solution:**
1. Authenticate the CLI:
+
```bash
copilot auth login
```
@@ -210,6 +219,7 @@ var client = new CopilotClient(new CopilotClientOptions
githubToken: process.env.GITHUB_TOKEN,
});
```
+
@@ -219,6 +229,7 @@ var client = new CopilotClient(new CopilotClientOptions
import os
client = CopilotClient({"github_token": os.environ.get("GITHUB_TOKEN")})
```
+
@@ -226,9 +237,10 @@ var client = new CopilotClient(new CopilotClientOptions
```go
client := copilot.NewClient(&copilot.ClientOptions{
- GithubToken: os.Getenv("GITHUB_TOKEN"),
+ GitHubToken: os.Getenv("GITHUB_TOKEN"),
})
```
+
@@ -237,9 +249,10 @@ var client = new CopilotClient(new CopilotClientOptions
```csharp
var client = new CopilotClient(new CopilotClientOptions
{
- GithubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN")
+ GitHubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN")
});
```
+
### "Session not found"
@@ -249,6 +262,7 @@ var client = new CopilotClient(new CopilotClientOptions
**Solution:**
1. Ensure you're not calling methods after `destroy()`:
+
```typescript
await session.destroy();
// Don't use session after this!
@@ -267,11 +281,13 @@ var client = new CopilotClient(new CopilotClientOptions
**Solution:**
1. Check if the CLI runs correctly standalone:
+
```bash
copilot --server --stdio
```
2. Enable auto-restart (enabled by default):
+
```typescript
const client = new CopilotClient({
autoRestart: true,
@@ -282,7 +298,7 @@ var client = new CopilotClient(new CopilotClientOptions
```typescript
const client = new CopilotClient({
useStdio: false,
- port: 0, // Use random available port
+ port: 0, // Use random available port
});
```
@@ -318,42 +334,47 @@ See [MCP Debugging Guide](./mcp/debugging.md) for detailed troubleshooting.
The SDK supports two transport modes:
-| Mode | Description | Use Case |
-|------|-------------|----------|
-| **Stdio** (default) | CLI runs as subprocess, communicates via pipes | Local development, single process |
-| **TCP** | CLI runs separately, communicates via TCP socket | Multiple clients, remote CLI |
+| Mode | Description | Use Case |
+| ------------------- | ------------------------------------------------ | --------------------------------- |
+| **Stdio** (default) | CLI runs as subprocess, communicates via pipes | Local development, single process |
+| **TCP** | CLI runs separately, communicates via TCP socket | Multiple clients, remote CLI |
**Stdio mode (default):**
+
```typescript
const client = new CopilotClient({
- useStdio: true, // This is the default
+ useStdio: true, // This is the default
});
```
**TCP mode:**
+
```typescript
const client = new CopilotClient({
useStdio: false,
- port: 8080, // Or 0 for random port
+ port: 8080, // Or 0 for random port
});
```
**Connect to existing server:**
+
```typescript
const client = new CopilotClient({
- cliUrl: "localhost:8080", // Connect to running server
+ cliUrl: "localhost:8080", // Connect to running server
});
```
### Diagnosing Connection Failures
1. **Check client state:**
+
```typescript
console.log("Connection state:", client.getState());
// Should be "connected" after start()
```
2. **Listen for state changes:**
+
```typescript
client.on("stateChange", (state) => {
console.log("State changed to:", state);
@@ -373,16 +394,18 @@ const client = new CopilotClient({
### Custom Tool Not Being Called
1. **Verify tool registration:**
+
```typescript
const session = await client.createSession({
tools: [myTool],
});
-
+
// Check registered tools
console.log("Registered tools:", session.getTools?.());
```
2. **Check tool schema is valid JSON Schema:**
+
```typescript
const myTool = {
name: "get_weather",
@@ -401,13 +424,14 @@ const client = new CopilotClient({
```
3. **Ensure handler returns valid result:**
+
```typescript
handler: async (args) => {
// Must return something JSON-serializable
return { success: true, data: "result" };
-
+
// Don't return undefined or non-serializable objects
- }
+ };
```
### Tool Errors Not Surfacing
@@ -431,6 +455,7 @@ session.on("error", (event) => {
### Windows
1. **Path separators:** Use raw strings or forward slashes:
+
```csharp
CliPath = @"C:\Program Files\GitHub\copilot.exe"
// or
@@ -438,6 +463,7 @@ session.on("error", (event) => {
```
2. **PATHEXT resolution:** The SDK handles this automatically, but if issues persist:
+
```csharp
// Explicitly specify .exe
Command = "myserver.exe" // Not just "myserver"
@@ -451,6 +477,7 @@ session.on("error", (event) => {
### macOS
1. **Gatekeeper issues:** If CLI is blocked:
+
```bash
xattr -d com.apple.quarantine /path/to/copilot
```
@@ -458,13 +485,14 @@ session.on("error", (event) => {
2. **PATH issues in GUI apps:** GUI applications may not inherit shell PATH:
```typescript
const client = new CopilotClient({
- cliPath: "/opt/homebrew/bin/copilot", // Full path
+ cliPath: "/opt/homebrew/bin/copilot", // Full path
});
```
### Linux
1. **Permission issues:**
+
```bash
chmod +x /path/to/copilot
```
diff --git a/docs/guides/setup/github-oauth.md b/docs/guides/setup/github-oauth.md
index a7aac473..5cb18836 100644
--- a/docs/guides/setup/github-oauth.md
+++ b/docs/guides/setup/github-oauth.md
@@ -34,6 +34,7 @@ sequenceDiagram
```
**Key characteristics:**
+
- Each user authenticates with their own GitHub account
- Copilot usage is billed to each user's subscription
- Supports GitHub organizations and enterprise accounts
@@ -93,21 +94,21 @@ Your application handles the standard GitHub OAuth flow. Here's the server-side
```typescript
// Server-side: Exchange authorization code for user token
async function handleOAuthCallback(code: string): Promise {
- const response = await fetch("https://github.com/login/oauth/access_token", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Accept: "application/json",
- },
- body: JSON.stringify({
- client_id: process.env.GITHUB_CLIENT_ID,
- client_secret: process.env.GITHUB_CLIENT_SECRET,
- code,
- }),
- });
-
- const data = await response.json();
- return data.access_token; // gho_xxxx or ghu_xxxx
+ const response = await fetch("https://github.com/login/oauth/access_token", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Accept: "application/json",
+ },
+ body: JSON.stringify({
+ client_id: process.env.GITHUB_CLIENT_ID,
+ client_secret: process.env.GITHUB_CLIENT_SECRET,
+ code,
+ }),
+ });
+
+ const data = await response.json();
+ return data.access_token; // gho_xxxx or ghu_xxxx
}
```
@@ -123,17 +124,17 @@ import { CopilotClient } from "@github/copilot-sdk";
// Create a client for an authenticated user
function createClientForUser(userToken: string): CopilotClient {
- return new CopilotClient({
- githubToken: userToken,
- useLoggedInUser: false, // Don't fall back to CLI login
- });
+ return new CopilotClient({
+ githubToken: userToken,
+ useLoggedInUser: false, // Don't fall back to CLI login
+ });
}
// Usage
const client = createClientForUser("gho_user_access_token");
const session = await client.createSession({
- sessionId: `user-${userId}-session`,
- model: "gpt-4.1",
+ sessionId: `user-${userId}-session`,
+ model: "gpt-4.1",
});
const response = await session.sendAndWait({ prompt: "Hello!" });
@@ -173,7 +174,7 @@ response = await session.send_and_wait({"prompt": "Hello!"})
```go
func createClientForUser(userToken string) *copilot.Client {
return copilot.NewClient(&copilot.ClientOptions{
- GithubToken: userToken,
+ GitHubToken: userToken,
UseLoggedInUser: copilot.Bool(false),
})
}
@@ -199,7 +200,7 @@ response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"}
CopilotClient CreateClientForUser(string userToken) =>
new CopilotClient(new CopilotClientOptions
{
- GithubToken = userToken,
+ GitHubToken = userToken,
UseLoggedInUser = false,
});
@@ -256,20 +257,20 @@ After OAuth, check that the user belongs to your organization:
```typescript
async function verifyOrgMembership(
- token: string,
- requiredOrg: string
+ token: string,
+ requiredOrg: string,
): Promise {
- const response = await fetch("https://api.github.com/user/orgs", {
- headers: { Authorization: `Bearer ${token}` },
- });
- const orgs = await response.json();
- return orgs.some((org: any) => org.login === requiredOrg);
+ const response = await fetch("https://api.github.com/user/orgs", {
+ headers: { Authorization: `Bearer ${token}` },
+ });
+ const orgs = await response.json();
+ return orgs.some((org: any) => org.login === requiredOrg);
}
// In your auth flow
const token = await handleOAuthCallback(code);
-if (!await verifyOrgMembership(token, "my-company")) {
- throw new Error("User is not a member of the required organization");
+if (!(await verifyOrgMembership(token, "my-company"))) {
+ throw new Error("User is not a member of the required organization");
}
const client = createClientForUser(token);
```
@@ -282,19 +283,19 @@ For GitHub Enterprise Managed Users, the flow is identical — EMU users authent
// No special SDK configuration needed for EMU
// Enterprise policies are enforced server-side by GitHub
const client = new CopilotClient({
- githubToken: emuUserToken, // Works the same as regular tokens
- useLoggedInUser: false,
+ githubToken: emuUserToken, // Works the same as regular tokens
+ useLoggedInUser: false,
});
```
## Supported Token Types
-| Token Prefix | Source | Works? |
-|-------------|--------|--------|
-| `gho_` | OAuth user access token | ✅ |
-| `ghu_` | GitHub App user access token | ✅ |
-| `github_pat_` | Fine-grained personal access token | ✅ |
-| `ghp_` | Classic personal access token | ❌ (deprecated) |
+| Token Prefix | Source | Works? |
+| ------------- | ---------------------------------- | --------------- |
+| `gho_` | OAuth user access token | ✅ |
+| `ghu_` | GitHub App user access token | ✅ |
+| `github_pat_` | Fine-grained personal access token | ✅ |
+| `ghp_` | Classic personal access token | ❌ (deprecated) |
## Token Lifecycle
@@ -319,19 +320,19 @@ flowchart LR
```typescript
async function getOrRefreshToken(userId: string): Promise {
- const stored = await tokenStore.get(userId);
+ const stored = await tokenStore.get(userId);
- if (stored && !isExpired(stored)) {
- return stored.accessToken;
- }
+ if (stored && !isExpired(stored)) {
+ return stored.accessToken;
+ }
- if (stored?.refreshToken) {
- const refreshed = await refreshGitHubToken(stored.refreshToken);
- await tokenStore.set(userId, refreshed);
- return refreshed.accessToken;
- }
+ if (stored?.refreshToken) {
+ const refreshed = await refreshGitHubToken(stored.refreshToken);
+ await tokenStore.set(userId, refreshed);
+ return refreshed.accessToken;
+ }
- throw new Error("User must re-authenticate");
+ throw new Error("User must re-authenticate");
}
```
@@ -345,13 +346,16 @@ Each user gets their own SDK client with their own token. This provides the stro
const clients = new Map();
function getClientForUser(userId: string, token: string): CopilotClient {
- if (!clients.has(userId)) {
- clients.set(userId, new CopilotClient({
- githubToken: token,
- useLoggedInUser: false,
- }));
- }
- return clients.get(userId)!;
+ if (!clients.has(userId)) {
+ clients.set(
+ userId,
+ new CopilotClient({
+ githubToken: token,
+ useLoggedInUser: false,
+ }),
+ );
+ }
+ return clients.get(userId)!;
}
```
@@ -361,20 +365,20 @@ For a lighter resource footprint, you can run a single external CLI server and p
## Limitations
-| Limitation | Details |
-|------------|---------|
-| **Copilot subscription required** | Each user needs an active Copilot subscription |
-| **Token management is your responsibility** | Store, refresh, and handle expiration |
-| **GitHub account required** | Users must have GitHub accounts |
-| **Rate limits per user** | Subject to each user's Copilot rate limits |
+| Limitation | Details |
+| ------------------------------------------- | ---------------------------------------------- |
+| **Copilot subscription required** | Each user needs an active Copilot subscription |
+| **Token management is your responsibility** | Store, refresh, and handle expiration |
+| **GitHub account required** | Users must have GitHub accounts |
+| **Rate limits per user** | Subject to each user's Copilot rate limits |
## When to Move On
-| Need | Next Guide |
-|------|-----------|
-| Users without GitHub accounts | [BYOK](./byok.md) |
-| Run the SDK on servers | [Backend Services](./backend-services.md) |
-| Handle many concurrent users | [Scaling & Multi-Tenancy](./scaling.md) |
+| Need | Next Guide |
+| ----------------------------- | ----------------------------------------- |
+| Users without GitHub accounts | [BYOK](./byok.md) |
+| Run the SDK on servers | [Backend Services](./backend-services.md) |
+| Handle many concurrent users | [Scaling & Multi-Tenancy](./scaling.md) |
## Next Steps
diff --git a/dotnet/README.md b/dotnet/README.md
index d78e7a6b..6aafe211 100644
--- a/dotnet/README.md
+++ b/dotnet/README.md
@@ -68,8 +68,8 @@ new CopilotClient(CopilotClientOptions? options = null)
- `Cwd` - Working directory for the CLI process
- `Environment` - Environment variables to pass to the CLI process
- `Logger` - `ILogger` instance for SDK logging
-- `GithubToken` - GitHub token for authentication. When provided, takes priority over other auth methods.
-- `UseLoggedInUser` - Whether to use logged-in user for authentication (default: true, but false when `GithubToken` is provided). Cannot be used with `CliUrl`.
+- `GitHubToken` - GitHub token for authentication. When provided, takes priority over other auth methods.
+- `UseLoggedInUser` - Whether to use logged-in user for authentication (default: true, but false when `GitHubToken` is provided). Cannot be used with `CliUrl`.
#### Methods
@@ -155,6 +155,7 @@ using var subscription = client.On(SessionLifecycleEventTypes.Foreground, evt =>
```
**Lifecycle Event Types:**
+
- `SessionLifecycleEventTypes.Created` - A new session was created
- `SessionLifecycleEventTypes.Deleted` - A session was deleted
- `SessionLifecycleEventTypes.Updated` - A session was updated
diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs
index 74f1c66f..ad89fac4 100644
--- a/dotnet/src/Client.cs
+++ b/dotnet/src/Client.cs
@@ -96,9 +96,9 @@ public CopilotClient(CopilotClientOptions? options = null)
}
// Validate auth options with external server
- if (!string.IsNullOrEmpty(_options.CliUrl) && (!string.IsNullOrEmpty(_options.GithubToken) || _options.UseLoggedInUser != null))
+ if (!string.IsNullOrEmpty(_options.CliUrl) && (!string.IsNullOrEmpty(_options.GitHubToken) || _options.UseLoggedInUser != null))
{
- throw new ArgumentException("GithubToken and UseLoggedInUser cannot be used with CliUrl (external server manages its own auth)");
+ throw new ArgumentException("GitHubToken and UseLoggedInUser cannot be used with CliUrl (external server manages its own auth)");
}
_logger = _options.Logger ?? NullLogger.Instance;
@@ -895,13 +895,13 @@ private async Task VerifyProtocolVersionAsync(Connection connection, Cancellatio
}
// Add auth-related flags
- if (!string.IsNullOrEmpty(options.GithubToken))
+ if (!string.IsNullOrEmpty(options.GitHubToken))
{
args.AddRange(["--auth-token-env", "COPILOT_SDK_AUTH_TOKEN"]);
}
- // Default UseLoggedInUser to false when GithubToken is provided
- var useLoggedInUser = options.UseLoggedInUser ?? string.IsNullOrEmpty(options.GithubToken);
+ // Default UseLoggedInUser to false when GitHubToken is provided
+ var useLoggedInUser = options.UseLoggedInUser ?? string.IsNullOrEmpty(options.GitHubToken);
if (!useLoggedInUser)
{
args.Add("--no-auto-login");
@@ -933,9 +933,9 @@ private async Task VerifyProtocolVersionAsync(Connection connection, Cancellatio
startInfo.Environment.Remove("NODE_DEBUG");
// Set auth token in environment if provided
- if (!string.IsNullOrEmpty(options.GithubToken))
+ if (!string.IsNullOrEmpty(options.GitHubToken))
{
- startInfo.Environment["COPILOT_SDK_AUTH_TOKEN"] = options.GithubToken;
+ startInfo.Environment["COPILOT_SDK_AUTH_TOKEN"] = options.GitHubToken;
}
var cliProcess = new Process { StartInfo = startInfo };
diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs
index 664b35d9..f4aa02f3 100644
--- a/dotnet/src/Types.cs
+++ b/dotnet/src/Types.cs
@@ -44,13 +44,13 @@ public class CopilotClientOptions
/// When provided, the token is passed to the CLI server via environment variable.
/// This takes priority over other authentication methods.
///
- public string? GithubToken { get; set; }
+ public string? GitHubToken { get; set; }
///
/// Whether to use the logged-in user for authentication.
/// When true, the CLI server will attempt to use stored OAuth tokens or gh CLI auth.
- /// When false, only explicit tokens (GithubToken or environment variables) are used.
- /// Default: true (but defaults to false when GithubToken is provided).
+ /// When false, only explicit tokens (GitHubToken or environment variables) are used.
+ /// Default: true (but defaults to false when GitHubToken is provided).
///
public bool? UseLoggedInUser { get; set; }
}
diff --git a/dotnet/test/ClientTests.cs b/dotnet/test/ClientTests.cs
index e3419f98..12513a27 100644
--- a/dotnet/test/ClientTests.cs
+++ b/dotnet/test/ClientTests.cs
@@ -149,14 +149,14 @@ public async Task Should_List_Models_When_Authenticated()
}
[Fact]
- public void Should_Accept_GithubToken_Option()
+ public void Should_Accept_GitHubToken_Option()
{
var options = new CopilotClientOptions
{
- GithubToken = "gho_test_token"
+ GitHubToken = "gho_test_token"
};
- Assert.Equal("gho_test_token", options.GithubToken);
+ Assert.Equal("gho_test_token", options.GitHubToken);
}
[Fact]
@@ -179,11 +179,11 @@ public void Should_Allow_Explicit_UseLoggedInUser_False()
}
[Fact]
- public void Should_Allow_Explicit_UseLoggedInUser_True_With_GithubToken()
+ public void Should_Allow_Explicit_UseLoggedInUser_True_With_GitHubToken()
{
var options = new CopilotClientOptions
{
- GithubToken = "gho_test_token",
+ GitHubToken = "gho_test_token",
UseLoggedInUser = true
};
@@ -191,14 +191,14 @@ public void Should_Allow_Explicit_UseLoggedInUser_True_With_GithubToken()
}
[Fact]
- public void Should_Throw_When_GithubToken_Used_With_CliUrl()
+ public void Should_Throw_When_GitHubToken_Used_With_CliUrl()
{
Assert.Throws(() =>
{
_ = new CopilotClient(new CopilotClientOptions
{
CliUrl = "localhost:8080",
- GithubToken = "gho_test_token"
+ GitHubToken = "gho_test_token"
});
});
}
diff --git a/dotnet/test/Harness/E2ETestContext.cs b/dotnet/test/Harness/E2ETestContext.cs
index 2518ca69..4ee201a8 100644
--- a/dotnet/test/Harness/E2ETestContext.cs
+++ b/dotnet/test/Harness/E2ETestContext.cs
@@ -93,7 +93,7 @@ public IReadOnlyDictionary GetEnvironment()
{
Cwd = WorkDir,
Environment = GetEnvironment(),
- GithubToken = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI")) ? "fake-token-for-e2e-tests" : null,
+ GitHubToken = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI")) ? "fake-token-for-e2e-tests" : null,
});
public async ValueTask DisposeAsync()
diff --git a/go/README.md b/go/README.md
index 58207101..e3e84d43 100644
--- a/go/README.md
+++ b/go/README.md
@@ -117,8 +117,8 @@ Event types: `SessionLifecycleCreated`, `SessionLifecycleDeleted`, `SessionLifec
- `AutoStart` (\*bool): Auto-start server on first use (default: true). Use `Bool(false)` to disable.
- `AutoRestart` (\*bool): Auto-restart on crash (default: true). Use `Bool(false)` to disable.
- `Env` ([]string): Environment variables for CLI process (default: inherits from current process)
-- `GithubToken` (string): GitHub token for authentication. When provided, takes priority over other auth methods.
-- `UseLoggedInUser` (\*bool): Whether to use logged-in user for authentication (default: true, but false when `GithubToken` is provided). Cannot be used with `CLIUrl`.
+- `GitHubToken` (string): GitHub token for authentication. When provided, takes priority over other auth methods.
+- `UseLoggedInUser` (\*bool): Whether to use logged-in user for authentication (default: true, but false when `GitHubToken` is provided). Cannot be used with `CLIUrl`.
**SessionConfig:**
@@ -419,7 +419,9 @@ session, err := client.CreateSession(context.Background(), &copilot.SessionConfi
},
})
```
+
> **Important notes:**
+>
> - When using a custom provider, the `Model` parameter is **required**. The SDK will return an error if no model is specified.
> - For Azure OpenAI endpoints (`*.openai.azure.com`), you **must** use `Type: "azure"`, not `Type: "openai"`.
> - The `BaseURL` should be just the host (e.g., `https://my-resource.openai.azure.com`). Do **not** include `/openai/v1` in the URL - the SDK handles path construction automatically.
diff --git a/go/client.go b/go/client.go
index 319c6588..f001b3c9 100644
--- a/go/client.go
+++ b/go/client.go
@@ -126,8 +126,8 @@ func NewClient(options *ClientOptions) *Client {
}
// Validate auth options with external server
- if options.CLIUrl != "" && (options.GithubToken != "" || options.UseLoggedInUser != nil) {
- panic("GithubToken and UseLoggedInUser cannot be used with CLIUrl (external server manages its own auth)")
+ if options.CLIUrl != "" && (options.GitHubToken != "" || options.UseLoggedInUser != nil) {
+ panic("GitHubToken and UseLoggedInUser cannot be used with CLIUrl (external server manages its own auth)")
}
// Parse CLIUrl if provided
@@ -166,8 +166,8 @@ func NewClient(options *ClientOptions) *Client {
if options.AutoRestart != nil {
client.autoRestart = *options.AutoRestart
}
- if options.GithubToken != "" {
- opts.GithubToken = options.GithubToken
+ if options.GitHubToken != "" {
+ opts.GitHubToken = options.GitHubToken
}
if options.UseLoggedInUser != nil {
opts.UseLoggedInUser = options.UseLoggedInUser
@@ -1004,14 +1004,14 @@ func (c *Client) startCLIServer(ctx context.Context) error {
}
// Add auth-related flags
- if c.options.GithubToken != "" {
+ if c.options.GitHubToken != "" {
args = append(args, "--auth-token-env", "COPILOT_SDK_AUTH_TOKEN")
}
- // Default useLoggedInUser to false when GithubToken is provided
+ // Default useLoggedInUser to false when GitHubToken is provided
useLoggedInUser := true
if c.options.UseLoggedInUser != nil {
useLoggedInUser = *c.options.UseLoggedInUser
- } else if c.options.GithubToken != "" {
+ } else if c.options.GitHubToken != "" {
useLoggedInUser = false
}
if !useLoggedInUser {
@@ -1035,8 +1035,8 @@ func (c *Client) startCLIServer(ctx context.Context) error {
// Add auth token if needed.
c.process.Env = c.options.Env
- if c.options.GithubToken != "" {
- c.process.Env = append(c.process.Env, "COPILOT_SDK_AUTH_TOKEN="+c.options.GithubToken)
+ if c.options.GitHubToken != "" {
+ c.process.Env = append(c.process.Env, "COPILOT_SDK_AUTH_TOKEN="+c.options.GitHubToken)
}
if c.useStdio {
diff --git a/go/client_test.go b/go/client_test.go
index 176dad8c..8592cad7 100644
--- a/go/client_test.go
+++ b/go/client_test.go
@@ -254,17 +254,17 @@ func TestClient_URLParsing(t *testing.T) {
}
func TestClient_AuthOptions(t *testing.T) {
- t.Run("should accept GithubToken option", func(t *testing.T) {
+ t.Run("should accept GitHubToken option", func(t *testing.T) {
client := NewClient(&ClientOptions{
- GithubToken: "gho_test_token",
+ GitHubToken: "gho_test_token",
})
- if client.options.GithubToken != "gho_test_token" {
- t.Errorf("Expected GithubToken to be 'gho_test_token', got %q", client.options.GithubToken)
+ if client.options.GitHubToken != "gho_test_token" {
+ t.Errorf("Expected GitHubToken to be 'gho_test_token', got %q", client.options.GitHubToken)
}
})
- t.Run("should default UseLoggedInUser to nil when no GithubToken", func(t *testing.T) {
+ t.Run("should default UseLoggedInUser to nil when no GitHubToken", func(t *testing.T) {
client := NewClient(&ClientOptions{})
if client.options.UseLoggedInUser != nil {
@@ -282,9 +282,9 @@ func TestClient_AuthOptions(t *testing.T) {
}
})
- t.Run("should allow explicit UseLoggedInUser true with GithubToken", func(t *testing.T) {
+ t.Run("should allow explicit UseLoggedInUser true with GitHubToken", func(t *testing.T) {
client := NewClient(&ClientOptions{
- GithubToken: "gho_test_token",
+ GitHubToken: "gho_test_token",
UseLoggedInUser: Bool(true),
})
@@ -293,12 +293,12 @@ func TestClient_AuthOptions(t *testing.T) {
}
})
- t.Run("should throw error when GithubToken is used with CLIUrl", func(t *testing.T) {
+ t.Run("should throw error when GitHubToken is used with CLIUrl", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic for auth options with CLIUrl")
} else {
- matched, _ := regexp.MatchString("GithubToken and UseLoggedInUser cannot be used with CLIUrl", r.(string))
+ matched, _ := regexp.MatchString("GitHubToken and UseLoggedInUser cannot be used with CLIUrl", r.(string))
if !matched {
t.Errorf("Expected panic message about auth options, got: %v", r)
}
@@ -307,7 +307,7 @@ func TestClient_AuthOptions(t *testing.T) {
NewClient(&ClientOptions{
CLIUrl: "localhost:8080",
- GithubToken: "gho_test_token",
+ GitHubToken: "gho_test_token",
})
})
@@ -316,7 +316,7 @@ func TestClient_AuthOptions(t *testing.T) {
if r := recover(); r == nil {
t.Error("Expected panic for auth options with CLIUrl")
} else {
- matched, _ := regexp.MatchString("GithubToken and UseLoggedInUser cannot be used with CLIUrl", r.(string))
+ matched, _ := regexp.MatchString("GitHubToken and UseLoggedInUser cannot be used with CLIUrl", r.(string))
if !matched {
t.Errorf("Expected panic message about auth options, got: %v", r)
}
diff --git a/go/internal/e2e/testharness/context.go b/go/internal/e2e/testharness/context.go
index 570594ed..cefb87b5 100644
--- a/go/internal/e2e/testharness/context.go
+++ b/go/internal/e2e/testharness/context.go
@@ -167,7 +167,7 @@ func (c *TestContext) NewClient() *copilot.Client {
// Use fake token in CI to allow cached responses without real auth
if os.Getenv("CI") == "true" {
- options.GithubToken = "fake-token-for-e2e-tests"
+ options.GitHubToken = "fake-token-for-e2e-tests"
}
return copilot.NewClient(options)
diff --git a/go/types.go b/go/types.go
index a3b38ee3..1e7f7a18 100644
--- a/go/types.go
+++ b/go/types.go
@@ -42,14 +42,14 @@ type ClientOptions struct {
// If Env contains duplicate environment keys, only the last value in the
// slice for each duplicate key is used.
Env []string
- // GithubToken is the GitHub token to use for authentication.
+ // GitHubToken is the GitHub token to use for authentication.
// When provided, the token is passed to the CLI server via environment variable.
// This takes priority over other authentication methods.
- GithubToken string
+ GitHubToken string
// UseLoggedInUser controls whether to use the logged-in user for authentication.
// When true, the CLI server will attempt to use stored OAuth tokens or gh CLI auth.
- // When false, only explicit tokens (GithubToken or environment variables) are used.
- // Default: true (but defaults to false when GithubToken is provided).
+ // When false, only explicit tokens (GitHubToken or environment variables) are used.
+ // Default: true (but defaults to false when GitHubToken is provided).
// Use Bool(false) to explicitly disable.
UseLoggedInUser *bool
}