Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 86 additions & 2 deletions dotnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ using GitHub.Copilot.SDK;
await using var client = new CopilotClient();
await client.StartAsync();

// Create a session
// Create a session (OnPermissionRequest is required)
await using var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5"
Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll,
});

// Wait for response using session.idle event
Expand Down Expand Up @@ -110,13 +111,18 @@ Create a new conversation session.
- `Provider` - Custom API provider configuration (BYOK)
- `Streaming` - Enable streaming of response chunks (default: false)
- `InfiniteSessions` - Configure automatic context compaction (see below)
- `OnPermissionRequest` - **Required.** Handler called before each tool execution to approve or deny it. Use `PermissionHandler.ApproveAll` to allow everything, or provide a custom function for fine-grained control. See [Permission Handling](#permission-handling) section.
- `OnUserInputRequest` - Handler for user input requests from the agent (enables ask_user tool). See [User Input Requests](#user-input-requests) section.
- `Hooks` - Hook handlers for session lifecycle events. See [Session Hooks](#session-hooks) section.

##### `ResumeSessionAsync(string sessionId, ResumeSessionConfig? config = null): Task<CopilotSession>`

Resume an existing session. Returns the session with `WorkspacePath` populated if infinite sessions were enabled.

**ResumeSessionConfig:**

- `OnPermissionRequest` - **Required.** Handler called before each tool execution to approve or deny it. See [Permission Handling](#permission-handling) section.

##### `PingAsync(string? message = null): Task<PingResponse>`

Ping the server to check connectivity.
Expand Down Expand Up @@ -573,6 +579,84 @@ Trace context (`traceparent`/`tracestate`) is automatically propagated between t

No extra dependencies — uses built-in `System.Diagnostics.Activity`.

## Permission Handling

An `OnPermissionRequest` handler is **required** whenever you create or resume a session. The handler is called before the agent executes each tool (file writes, shell commands, custom tools, etc.) and must return a decision.

### Approve All (simplest)

Use the built-in `PermissionHandler.ApproveAll` helper to allow every tool call without any checks:

```csharp
using GitHub.Copilot.SDK;

var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll,
});
```

### Custom Permission Handler

Provide your own `PermissionRequestHandler` delegate to inspect each request and apply custom logic:

```csharp
var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
OnPermissionRequest = async (request, invocation) =>
{
// request.Kind — string discriminator for the type of operation being requested:
// "shell" — executing a shell command
// "write" — writing or editing a file
// "read" — reading a file
// "mcp" — calling an MCP tool
// "custom_tool" — calling one of your registered tools
// "url" — fetching a URL
// "memory" — accessing or modifying assistant memory
// "hook" — invoking a registered hook
// request.ToolCallId — the tool call that triggered this request
// request.ToolName — name of the tool (for custom-tool / mcp)
// request.FileName — file being written (for write)
// request.FullCommandText — full shell command text (for shell)

if (request.Kind == "shell")
{
// Deny shell commands
return new PermissionRequestResult { Kind = PermissionRequestResultKind.DeniedInteractivelyByUser };
}

return new PermissionRequestResult { Kind = PermissionRequestResultKind.Approved };
}
});
```

### Permission Result Kinds

| Value | Meaning |
|-------|---------|
| `PermissionRequestResultKind.Approved` | Allow the tool to run |
| `PermissionRequestResultKind.DeniedInteractivelyByUser` | User explicitly denied the request |
| `PermissionRequestResultKind.DeniedCouldNotRequestFromUser` | No approval rule matched and user could not be asked |
| `PermissionRequestResultKind.DeniedByRules` | Denied by a policy rule |
| `PermissionRequestResultKind.NoResult` | Leave the permission request unanswered (the SDK returns without calling the RPC). Not allowed for protocol v2 permission requests (will be rejected). |

### Resuming Sessions

Pass `OnPermissionRequest` when resuming a session too — it is required:

```csharp
var session = await client.ResumeSessionAsync("session-id", new ResumeSessionConfig
{
OnPermissionRequest = PermissionHandler.ApproveAll,
});
```

### Per-Tool Skip Permission

To let a specific custom tool bypass the permission prompt entirely, set `skip_permission = true` in the tool's `AdditionalProperties`. See [Skipping Permission Prompts](#skipping-permission-prompts) under Tools.

## User Input Requests

Enable the agent to ask questions to the user using the `ask_user` tool by providing an `OnUserInputRequest` handler:
Expand Down
78 changes: 76 additions & 2 deletions go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ func main() {
}
defer client.Stop()

// Create a session
// Create a session (OnPermissionRequest is required)
session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{
Model: "gpt-5",
Model: "gpt-5",
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
log.Fatal(err)
Expand Down Expand Up @@ -153,11 +154,13 @@ Event types: `SessionLifecycleCreated`, `SessionLifecycleDeleted`, `SessionLifec
- `Provider` (\*ProviderConfig): Custom API provider configuration (BYOK). See [Custom Providers](#custom-providers) section.
- `Streaming` (bool): Enable streaming delta events
- `InfiniteSessions` (\*InfiniteSessionConfig): Automatic context compaction configuration
- `OnPermissionRequest` (PermissionHandlerFunc): **Required.** Handler called before each tool execution to approve or deny it. Use `copilot.PermissionHandler.ApproveAll` to allow everything, or provide a custom function for fine-grained control. See [Permission Handling](#permission-handling) section.
- `OnUserInputRequest` (UserInputHandler): Handler for user input requests from the agent (enables ask_user tool). See [User Input Requests](#user-input-requests) section.
- `Hooks` (\*SessionHooks): Hook handlers for session lifecycle events. See [Session Hooks](#session-hooks) section.

**ResumeSessionConfig:**

- `OnPermissionRequest` (PermissionHandlerFunc): **Required.** Handler called before each tool execution to approve or deny it. See [Permission Handling](#permission-handling) section.
- `Tools` ([]Tool): Tools to expose when resuming
- `ReasoningEffort` (string): Reasoning effort level for models that support it
- `Provider` (\*ProviderConfig): Custom API provider configuration (BYOK). See [Custom Providers](#custom-providers) section.
Expand Down Expand Up @@ -499,6 +502,77 @@ Trace context (`traceparent`/`tracestate`) is automatically propagated between t

Dependency: `go.opentelemetry.io/otel`

## Permission Handling

An `OnPermissionRequest` handler is **required** whenever you create or resume a session. The handler is called before the agent executes each tool (file writes, shell commands, custom tools, etc.) and must return a decision.

### Approve All (simplest)

Use the built-in `PermissionHandler.ApproveAll` helper to allow every tool call without any checks:

```go
session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{
Model: "gpt-5",
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
```

### Custom Permission Handler

Provide your own `PermissionHandlerFunc` to inspect each request and apply custom logic:

```go
session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{
Model: "gpt-5",
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
// request.Kind — what type of operation is being requested:
// copilot.KindShell — executing a shell command
// copilot.Write — writing or editing a file
// copilot.Read — reading a file
// copilot.MCP — calling an MCP tool
// copilot.CustomTool — calling one of your registered tools
// copilot.URL — fetching a URL
// copilot.Memory — accessing or updating Copilot-managed memory
// copilot.Hook — invoking a registered hook
// request.ToolCallID — pointer to the tool call that triggered this request
// request.ToolName — pointer to the name of the tool (for custom-tool / mcp)
// request.FileName — pointer to the file being written (for write)
// request.FullCommandText — pointer to the full shell command (for shell)

if request.Kind == copilot.KindShell {
// Deny shell commands
return copilot.PermissionRequestResult{Kind: copilot.PermissionRequestResultKindDeniedInteractivelyByUser}, nil
}

return copilot.PermissionRequestResult{Kind: copilot.PermissionRequestResultKindApproved}, nil
},
})
```

### Permission Result Kinds

| Constant | Meaning |
|----------|---------|
| `PermissionRequestResultKindApproved` | Allow the tool to run |
| `PermissionRequestResultKindDeniedInteractivelyByUser` | User explicitly denied the request |
| `PermissionRequestResultKindDeniedCouldNotRequestFromUser` | No approval rule matched and user could not be asked |
| `PermissionRequestResultKindDeniedByRules` | Denied by a policy rule |
| `PermissionRequestResultKindNoResult` | Leave the permission request unanswered (protocol v1 only; not allowed for protocol v2) |

### Resuming Sessions

Pass `OnPermissionRequest` when resuming a session too — it is required:

```go
session, err := client.ResumeSession(context.Background(), sessionID, &copilot.ResumeSessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
```

### Per-Tool Skip Permission

To let a specific custom tool bypass the permission prompt entirely, set `SkipPermission = true` on the tool. See [Skipping Permission Prompts](#skipping-permission-prompts) under Tools.

## User Input Requests

Enable the agent to ask questions to the user using the `ask_user` tool by providing an `OnUserInputRequest` handler:
Expand Down
84 changes: 81 additions & 3 deletions nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@ npm start
## Quick Start

```typescript
import { CopilotClient } from "@github/copilot-sdk";
import { CopilotClient, approveAll } from "@github/copilot-sdk";

// Create and start client
const client = new CopilotClient();
await client.start();

// Create a session
// Create a session (onPermissionRequest is required)
const session = await client.createSession({
model: "gpt-5",
onPermissionRequest: approveAll,
});

// Wait for response using typed event handlers
Expand All @@ -59,7 +60,7 @@ await client.stop();
Sessions also support `Symbol.asyncDispose` for use with [`await using`](https://github.com/tc39/proposal-explicit-resource-management) (TypeScript 5.2+/Node.js 18.0+):

```typescript
await using session = await client.createSession({ model: "gpt-5" });
await using session = await client.createSession({ model: "gpt-5", onPermissionRequest: approveAll });
// session is automatically disconnected when leaving scope
```

Expand Down Expand Up @@ -114,6 +115,7 @@ Create a new conversation session.
- `systemMessage?: SystemMessageConfig` - System message customization (see below)
- `infiniteSessions?: InfiniteSessionConfig` - Configure automatic context compaction (see below)
- `provider?: ProviderConfig` - Custom API provider configuration (BYOK - Bring Your Own Key). See [Custom Providers](#custom-providers) section.
- `onPermissionRequest: PermissionHandler` - **Required.** Handler called before each tool execution to approve or deny it. Use `approveAll` to allow everything, or provide a custom function for fine-grained control. See [Permission Handling](#permission-handling) section.
- `onUserInputRequest?: UserInputHandler` - Handler for user input requests from the agent. Enables the `ask_user` tool. See [User Input Requests](#user-input-requests) section.
- `hooks?: SessionHooks` - Hook handlers for session lifecycle events. See [Session Hooks](#session-hooks) section.

Expand Down Expand Up @@ -648,6 +650,82 @@ const client = new CopilotClient({

Inbound trace context from the CLI is available on the `ToolInvocation` object passed to tool handlers as `traceparent` and `tracestate` fields. See the [OpenTelemetry guide](../docs/observability/opentelemetry.md) for a full wire-up example.

## Permission Handling

An `onPermissionRequest` handler is **required** whenever you create or resume a session. The handler is called before the agent executes each tool (file writes, shell commands, custom tools, etc.) and must return a decision.

### Approve All (simplest)

Use the built-in `approveAll` helper to allow every tool call without any checks:

```typescript
import { CopilotClient, approveAll } from "@github/copilot-sdk";

const session = await client.createSession({
model: "gpt-5",
onPermissionRequest: approveAll,
});
```

### Custom Permission Handler

Provide your own function to inspect each request and apply custom logic:

```typescript
import type { PermissionRequest, PermissionRequestResult } from "@github/copilot-sdk";

const session = await client.createSession({
model: "gpt-5",
onPermissionRequest: (request: PermissionRequest, invocation): PermissionRequestResult => {
// request.kind — what type of operation is being requested:
// "shell" — executing a shell command
// "write" — writing or editing a file
// "read" — reading a file
// "mcp" — calling an MCP tool
// "custom-tool" — calling one of your registered tools
// "url" — fetching a URL
// "memory" — storing or retrieving persistent session memory
// "hook" — invoking a server-side hook or integration
// (additional kinds may be added; include a default case in handlers)
// request.toolCallId — the tool call that triggered this request
// request.toolName — name of the tool (for custom-tool / mcp)
// request.fileName — file being written (for write)
// request.fullCommandText — full shell command (for shell)

if (request.kind === "shell") {
// Deny shell commands
return { kind: "denied-interactively-by-user" };
}

return { kind: "approved" };
},
});
```

### Permission Result Kinds

| Kind | Meaning |
|------|---------|
| `"approved"` | Allow the tool to run |
| `"denied-interactively-by-user"` | User explicitly denied the request |
| `"denied-no-approval-rule-and-could-not-request-from-user"` | No approval rule matched and user could not be asked |
| `"denied-by-rules"` | Denied by a policy rule |
| `"denied-by-content-exclusion-policy"` | Denied due to a content exclusion policy |
| `"no-result"` | Leave the request unanswered (only valid with protocol v1; rejected by protocol v2 servers) |
### Resuming Sessions

Pass `onPermissionRequest` when resuming a session too — it is required:

```typescript
const session = await client.resumeSession("session-id", {
onPermissionRequest: approveAll,
});
```

### Per-Tool Skip Permission

To let a specific custom tool bypass the permission prompt entirely, set `skipPermission: true` on the tool definition. See [Skipping Permission Prompts](#skipping-permission-prompts) under Tools.

## User Input Requests

Enable the agent to ask questions to the user using the `ask_user` tool by providing an `onUserInputRequest` handler:
Expand Down
Loading