Update .NET Copilot SDK recipes for explicit permission (fix for SDK v0.1.28) (#1033)

* Update .NET Copilot SDK recipes for explicit permission handling (fix breaking change in SDK v0.1.28)

* Update .NET Copilot SDK recipes for explicit permission handling
This commit is contained in:
Jon Galloway
2026-03-16 18:49:03 -07:00
committed by GitHub
parent 99e00272f8
commit e2c763df88
14 changed files with 78 additions and 26 deletions

View File

@@ -64,6 +64,7 @@ await using var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "claude-opus-4.6", Model = "claude-opus-4.6",
Streaming = true, Streaming = true,
OnPermissionRequest = PermissionHandler.ApproveAll,
McpServers = new Dictionary<string, object>() McpServers = new Dictionary<string, object>()
{ {
["playwright"] = ["playwright"] =
@@ -207,6 +208,7 @@ if (generateTests == "y" || generateTests == "yes")
The recipe configures a local MCP server that runs alongside the session: The recipe configures a local MCP server that runs alongside the session:
```csharp ```csharp
OnPermissionRequest = PermissionHandler.ApproveAll,
McpServers = new Dictionary<string, object>() McpServers = new Dictionary<string, object>()
{ {
["playwright"] = new McpLocalServerConfig ["playwright"] = new McpLocalServerConfig

View File

@@ -24,7 +24,8 @@ try
await client.StartAsync(); await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "gpt-5" Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
}); });
var done = new TaskCompletionSource<string>(); var done = new TaskCompletionSource<string>();
@@ -76,7 +77,11 @@ catch (Exception ex)
## Timeout handling ## Timeout handling
```csharp ```csharp
var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" }); var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
try try
{ {
@@ -106,7 +111,11 @@ catch (OperationCanceledException)
## Aborting a request ## Aborting a request
```csharp ```csharp
var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" }); var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
// Start a request // Start a request
await session.SendAsync(new MessageOptions { Prompt = "Write a very long story..." }); await session.SendAsync(new MessageOptions { Prompt = "Write a very long story..." });
@@ -141,7 +150,11 @@ Console.CancelKeyPress += async (sender, e) =>
await using var client = new CopilotClient(); await using var client = new CopilotClient();
await client.StartAsync(); await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" }); var session = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
// ... do work ... // ... do work ...
@@ -150,6 +163,8 @@ var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5
## Best practices ## Best practices
Starting with Copilot SDK v0.1.28, permission handling is opt-in. If a session may need tool, file, or system access, set `OnPermissionRequest` explicitly when creating it.
1. **Always clean up**: Use try-finally or `await using` to ensure `StopAsync()` is called 1. **Always clean up**: Use try-finally or `await using` to ensure `StopAsync()` is called
2. **Handle connection errors**: The CLI might not be installed or running 2. **Handle connection errors**: The CLI might not be installed or running
3. **Set appropriate timeouts**: Use `CancellationToken` for long-running requests 3. **Set appropriate timeouts**: Use `CancellationToken` for long-running requests

View File

@@ -6,6 +6,7 @@ Use Copilot to intelligently organize files in a folder based on their metadata.
> >
> ```bash > ```bash
> dotnet run recipe/managing-local-files.cs > dotnet run recipe/managing-local-files.cs
> dotnet run recipe/managing-local-files.cs -- /path/to/folder
> ``` > ```
## Example scenario ## Example scenario
@@ -24,7 +25,8 @@ await client.StartAsync();
// Define tools for file operations // Define tools for file operations
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "gpt-5" Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
}); });
// Wait for completion // Wait for completion
@@ -49,8 +51,8 @@ session.On(evt =>
} }
}); });
// Ask Copilot to organize files // Use an explicit folder or default to the current directory
var targetFolder = @"C:\Users\Me\Downloads"; var targetFolder = args.FirstOrDefault() ?? Environment.CurrentDirectory;
await session.SendAsync(new MessageOptions await session.SendAsync(new MessageOptions
{ {

View File

@@ -12,7 +12,7 @@ Manage multiple independent conversations simultaneously.
You need to run multiple conversations in parallel, each with its own context and history. You need to run multiple conversations in parallel, each with its own context and history.
## C# ## C #
```csharp ```csharp
using GitHub.Copilot.SDK; using GitHub.Copilot.SDK;
@@ -21,9 +21,21 @@ await using var client = new CopilotClient();
await client.StartAsync(); await client.StartAsync();
// Create multiple independent sessions // Create multiple independent sessions
var session1 = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" }); var session1 = await client.CreateSessionAsync(new SessionConfig
var session2 = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" }); {
var session3 = await client.CreateSessionAsync(new SessionConfig { Model = "claude-sonnet-4.5" }); Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
var session2 = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
var session3 = await client.CreateSessionAsync(new SessionConfig
{
Model = "claude-sonnet-4.5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
// Each session maintains its own conversation history // Each session maintains its own conversation history
await session1.SendAsync(new MessageOptions { Prompt = "You are helping with a Python project" }); await session1.SendAsync(new MessageOptions { Prompt = "You are helping with a Python project" });
@@ -49,7 +61,8 @@ Use custom IDs for easier tracking:
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
SessionId = "user-123-chat", SessionId = "user-123-chat",
Model = "gpt-5" Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
}); });
Console.WriteLine(session.SessionId); // "user-123-chat" Console.WriteLine(session.SessionId); // "user-123-chat"

View File

@@ -25,7 +25,8 @@ await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
SessionId = "user-123-conversation", SessionId = "user-123-conversation",
Model = "gpt-5" Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
}); });
await session.SendAsync(new MessageOptions { Prompt = "Let's discuss TypeScript generics" }); await session.SendAsync(new MessageOptions { Prompt = "Let's discuss TypeScript generics" });

View File

@@ -165,6 +165,7 @@ await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "gpt-5", Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll,
SystemMessage = new SystemMessageConfig SystemMessage = new SystemMessageConfig
{ {
Content = $""" Content = $"""

View File

@@ -58,7 +58,11 @@ try
// Fresh session each iteration — context isolation is the point // Fresh session each iteration — context isolation is the point
var session = await client.CreateSessionAsync( var session = await client.CreateSessionAsync(
new SessionConfig { Model = "gpt-5.1-codex-mini" }); new SessionConfig
{
Model = "gpt-5.1-codex-mini",
OnPermissionRequest = PermissionHandler.ApproveAll
});
try try
{ {
var done = new TaskCompletionSource<string>(); var done = new TaskCompletionSource<string>();
@@ -125,8 +129,7 @@ try
// Pin the agent to the project directory // Pin the agent to the project directory
WorkingDirectory = Environment.CurrentDirectory, WorkingDirectory = Environment.CurrentDirectory,
// Auto-approve tool calls for unattended operation // Auto-approve tool calls for unattended operation
OnPermissionRequest = (_, _) => Task.FromResult( OnPermissionRequest = PermissionHandler.ApproveAll,
new PermissionRequestResult { Kind = "approved" }),
}); });
try try
{ {

View File

@@ -32,6 +32,7 @@ await using var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "claude-opus-4.6", Model = "claude-opus-4.6",
Streaming = true, Streaming = true,
OnPermissionRequest = PermissionHandler.ApproveAll,
McpServers = new Dictionary<string, object>() McpServers = new Dictionary<string, object>()
{ {
["playwright"] = ["playwright"] =

View File

@@ -10,7 +10,8 @@ try
await client.StartAsync(); await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "gpt-5" Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
}); });
var done = new TaskCompletionSource<string>(); var done = new TaskCompletionSource<string>();

View File

@@ -10,7 +10,8 @@ await client.StartAsync();
// Define tools for file operations // Define tools for file operations
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "gpt-5" Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
}); });
// Wait for completion // Wait for completion
@@ -36,8 +37,7 @@ session.On(evt =>
}); });
// Ask Copilot to organize files // Ask Copilot to organize files
// Change this to your target folder var targetFolder = args.FirstOrDefault() ?? Environment.CurrentDirectory;
var targetFolder = @"C:\Users\Me\Downloads";
await session.SendAsync(new MessageOptions await session.SendAsync(new MessageOptions
{ {

View File

@@ -7,9 +7,21 @@ await using var client = new CopilotClient();
await client.StartAsync(); await client.StartAsync();
// Create multiple independent sessions // Create multiple independent sessions
var session1 = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" }); var session1 = await client.CreateSessionAsync(new SessionConfig
var session2 = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" }); {
var session3 = await client.CreateSessionAsync(new SessionConfig { Model = "claude-sonnet-4.5" }); Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
var session2 = await client.CreateSessionAsync(new SessionConfig
{
Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
var session3 = await client.CreateSessionAsync(new SessionConfig
{
Model = "claude-sonnet-4.5",
OnPermissionRequest = PermissionHandler.ApproveAll
});
Console.WriteLine("Created 3 independent sessions"); Console.WriteLine("Created 3 independent sessions");

View File

@@ -10,7 +10,8 @@ await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
SessionId = "user-123-conversation", SessionId = "user-123-conversation",
Model = "gpt-5" Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll
}); });
await session.SendAsync(new MessageOptions { Prompt = "Let's discuss TypeScript generics" }); await session.SendAsync(new MessageOptions { Prompt = "Let's discuss TypeScript generics" });

View File

@@ -132,6 +132,7 @@ await client.StartAsync();
var session = await client.CreateSessionAsync(new SessionConfig var session = await client.CreateSessionAsync(new SessionConfig
{ {
Model = "gpt-5", Model = "gpt-5",
OnPermissionRequest = PermissionHandler.ApproveAll,
SystemMessage = new SystemMessageConfig SystemMessage = new SystemMessageConfig
{ {
Content = $""" Content = $"""

View File

@@ -48,8 +48,7 @@ try
// Pin the agent to the project directory // Pin the agent to the project directory
WorkingDirectory = Environment.CurrentDirectory, WorkingDirectory = Environment.CurrentDirectory,
// Auto-approve tool calls for unattended operation // Auto-approve tool calls for unattended operation
OnPermissionRequest = (_, _) => Task.FromResult( OnPermissionRequest = PermissionHandler.ApproveAll,
new PermissionRequestResult { Kind = "approved" }),
}); });
try try