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

@@ -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