Skip to content

Commit 64256b9

Browse files
refactor: add PermissionHandlers.approveAll helper, remove verbose README sections
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7ba9d36 commit 64256b9

27 files changed

+76
-210
lines changed

dotnet/README.md

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -495,43 +495,6 @@ var session = await client.CreateSessionAsync(new SessionConfig
495495
});
496496
```
497497

498-
## Permission Requests
499-
500-
The SDK uses a **deny-by-default** permission model. When the Copilot agent needs to perform privileged operations (file writes, shell commands, URL fetches, etc.), it sends a permission request to the SDK. If no `OnPermissionRequest` handler is registered, all such requests are **automatically denied**.
501-
502-
To allow operations, provide an `OnPermissionRequest` handler when creating a session:
503-
504-
```csharp
505-
var session = await client.CreateSessionAsync(new SessionConfig
506-
{
507-
OnPermissionRequest = async (request, invocation) =>
508-
{
509-
// request.Kind - The type of operation: "shell", "write", "read", "url", or "mcp"
510-
511-
// Approve everything (equivalent to --yolo mode in the CLI)
512-
return new PermissionRequestResult { Kind = "approved" };
513-
514-
// Or implement fine-grained policy:
515-
// if (request.Kind == "shell")
516-
// return new PermissionRequestResult { Kind = "denied-interactively-by-user" };
517-
// return new PermissionRequestResult { Kind = "approved" };
518-
}
519-
});
520-
```
521-
522-
**Permission request kinds:**
523-
- `"shell"` — Execute a shell command
524-
- `"write"` — Write to a file
525-
- `"read"` — Read a file
526-
- `"url"` — Fetch a URL
527-
- `"mcp"` — Call an MCP server tool
528-
529-
**Permission result kinds:**
530-
- `"approved"` — Allow the operation
531-
- `"denied-interactively-by-user"` — User explicitly denied
532-
- `"denied-by-rules"` — Denied by policy rules
533-
- `"denied-no-approval-rule-and-could-not-request-from-user"` — Default deny (no handler)
534-
535498
## User Input Requests
536499

537500
Enable the agent to ask questions to the user using the `ask_user` tool by providing an `OnUserInputRequest` handler:

dotnet/samples/Chat.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@
33
await using var client = new CopilotClient();
44
await using var session = await client.CreateSessionAsync(new SessionConfig
55
{
6-
// Permission requests are denied by default. Provide a handler to approve operations.
7-
OnPermissionRequest = (request, invocation) =>
8-
{
9-
// Approve all permission requests. Customize this to implement your own policy.
10-
return Task.FromResult(new PermissionRequestResult { Kind = "approved" });
11-
}
6+
OnPermissionRequest = PermissionHandlers.ApproveAll
127
});
138

149
using var _ = session.On(evt =>

dotnet/src/PermissionHandlers.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
namespace GitHub.Copilot.SDK;
6+
7+
/// <summary>Provides pre-built <see cref="PermissionHandler"/> implementations.</summary>
8+
public static class PermissionHandlers
9+
{
10+
/// <summary>A <see cref="PermissionHandler"/> that approves all permission requests.</summary>
11+
public static PermissionHandler ApproveAll { get; } =
12+
(_, _) => Task.FromResult(new PermissionRequestResult { Kind = "approved" });
13+
}

dotnet/test/HooksTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public async Task Should_Invoke_PreToolUse_Hook_When_Model_Runs_A_Tool()
1717
CopilotSession? session = null;
1818
session = await Client.CreateSessionAsync(new SessionConfig
1919
{
20-
OnPermissionRequest = (request, invocation) => Task.FromResult(new PermissionRequestResult { Kind = "approved" }),
20+
OnPermissionRequest = PermissionHandlers.ApproveAll,
2121
Hooks = new SessionHooks
2222
{
2323
OnPreToolUse = (input, invocation) =>
@@ -53,7 +53,7 @@ public async Task Should_Invoke_PostToolUse_Hook_After_Model_Runs_A_Tool()
5353
CopilotSession? session = null;
5454
session = await Client.CreateSessionAsync(new SessionConfig
5555
{
56-
OnPermissionRequest = (request, invocation) => Task.FromResult(new PermissionRequestResult { Kind = "approved" }),
56+
OnPermissionRequest = PermissionHandlers.ApproveAll,
5757
Hooks = new SessionHooks
5858
{
5959
OnPostToolUse = (input, invocation) =>
@@ -91,7 +91,7 @@ public async Task Should_Invoke_Both_PreToolUse_And_PostToolUse_Hooks_For_Single
9191

9292
var session = await Client.CreateSessionAsync(new SessionConfig
9393
{
94-
OnPermissionRequest = (request, invocation) => Task.FromResult(new PermissionRequestResult { Kind = "approved" }),
94+
OnPermissionRequest = PermissionHandlers.ApproveAll,
9595
Hooks = new SessionHooks
9696
{
9797
OnPreToolUse = (input, invocation) =>
@@ -133,7 +133,7 @@ public async Task Should_Deny_Tool_Execution_When_PreToolUse_Returns_Deny()
133133

134134
var session = await Client.CreateSessionAsync(new SessionConfig
135135
{
136-
OnPermissionRequest = (request, invocation) => Task.FromResult(new PermissionRequestResult { Kind = "approved" }),
136+
OnPermissionRequest = PermissionHandlers.ApproveAll,
137137
Hooks = new SessionHooks
138138
{
139139
OnPreToolUse = (input, invocation) =>

dotnet/test/McpAndAgentsTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ public async Task Should_Pass_Literal_Env_Values_To_Mcp_Server_Subprocess()
280280
var session = await Client.CreateSessionAsync(new SessionConfig
281281
{
282282
McpServers = mcpServers,
283-
OnPermissionRequest = (request, invocation) => Task.FromResult(new PermissionRequestResult { Kind = "approved" }),
283+
OnPermissionRequest = PermissionHandlers.ApproveAll,
284284
});
285285

286286
Assert.Matches(@"^[a-f0-9-]+$", session.SessionId);

dotnet/test/SessionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ public async Task Send_Returns_Immediately_While_Events_Stream_In_Background()
335335
{
336336
var session = await Client.CreateSessionAsync(new SessionConfig
337337
{
338-
OnPermissionRequest = (request, invocation) => Task.FromResult(new PermissionRequestResult { Kind = "approved" }),
338+
OnPermissionRequest = PermissionHandlers.ApproveAll,
339339
});
340340
var events = new List<string>();
341341

dotnet/test/ToolsTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ await File.WriteAllTextAsync(
2323

2424
var session = await Client.CreateSessionAsync(new SessionConfig
2525
{
26-
OnPermissionRequest = (request, invocation) => Task.FromResult(new PermissionRequestResult { Kind = "approved" }),
26+
OnPermissionRequest = PermissionHandlers.ApproveAll,
2727
});
2828

2929
await session.SendAsync(new MessageOptions

go/README.md

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -445,42 +445,6 @@ session, err := client.CreateSession(context.Background(), &copilot.SessionConfi
445445
> - For Azure OpenAI endpoints (`*.openai.azure.com`), you **must** use `Type: "azure"`, not `Type: "openai"`.
446446
> - 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.
447447
448-
## Permission Requests
449-
450-
The SDK uses a **deny-by-default** permission model. When the Copilot agent needs to perform privileged operations (file writes, shell commands, URL fetches, etc.), it sends a permission request to the SDK. If no `OnPermissionRequest` handler is registered, all such requests are **automatically denied**.
451-
452-
To allow operations, provide an `OnPermissionRequest` handler when creating a session:
453-
454-
```go
455-
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
456-
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
457-
// request.Kind - The type of operation: "shell", "write", "read", "url", or "mcp"
458-
459-
// Approve everything (equivalent to --yolo mode in the CLI)
460-
return copilot.PermissionRequestResult{Kind: "approved"}, nil
461-
462-
// Or implement fine-grained policy:
463-
// if request.Kind == "shell" {
464-
// return copilot.PermissionRequestResult{Kind: "denied-interactively-by-user"}, nil
465-
// }
466-
// return copilot.PermissionRequestResult{Kind: "approved"}, nil
467-
},
468-
})
469-
```
470-
471-
**Permission request kinds:**
472-
- `"shell"` — Execute a shell command
473-
- `"write"` — Write to a file
474-
- `"read"` — Read a file
475-
- `"url"` — Fetch a URL
476-
- `"mcp"` — Call an MCP server tool
477-
478-
**Permission result kinds:**
479-
- `"approved"` — Allow the operation
480-
- `"denied-interactively-by-user"` — User explicitly denied
481-
- `"denied-by-rules"` — Denied by policy rules
482-
- `"denied-no-approval-rule-and-could-not-request-from-user"` — Default deny (no handler)
483-
484448
## User Input Requests
485449

486450
Enable the agent to ask questions to the user using the `ask_user` tool by providing an `OnUserInputRequest` handler:

go/internal/e2e/hooks_test.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ func TestHooks(t *testing.T) {
2222
var mu sync.Mutex
2323

2424
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
25-
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
26-
return copilot.PermissionRequestResult{Kind: "approved"}, nil
27-
},
25+
OnPermissionRequest: copilot.PermissionHandlers.ApproveAll,
2826
Hooks: &copilot.SessionHooks{
2927
OnPreToolUse: func(input copilot.PreToolUseHookInput, invocation copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {
3028
mu.Lock()
@@ -83,9 +81,7 @@ func TestHooks(t *testing.T) {
8381
var mu sync.Mutex
8482

8583
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
86-
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
87-
return copilot.PermissionRequestResult{Kind: "approved"}, nil
88-
},
84+
OnPermissionRequest: copilot.PermissionHandlers.ApproveAll,
8985
Hooks: &copilot.SessionHooks{
9086
OnPostToolUse: func(input copilot.PostToolUseHookInput, invocation copilot.HookInvocation) (*copilot.PostToolUseHookOutput, error) {
9187
mu.Lock()
@@ -151,9 +147,7 @@ func TestHooks(t *testing.T) {
151147
var mu sync.Mutex
152148

153149
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
154-
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
155-
return copilot.PermissionRequestResult{Kind: "approved"}, nil
156-
},
150+
OnPermissionRequest: copilot.PermissionHandlers.ApproveAll,
157151
Hooks: &copilot.SessionHooks{
158152
OnPreToolUse: func(input copilot.PreToolUseHookInput, invocation copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {
159153
mu.Lock()
@@ -223,9 +217,7 @@ func TestHooks(t *testing.T) {
223217
var mu sync.Mutex
224218

225219
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
226-
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
227-
return copilot.PermissionRequestResult{Kind: "approved"}, nil
228-
},
220+
OnPermissionRequest: copilot.PermissionHandlers.ApproveAll,
229221
Hooks: &copilot.SessionHooks{
230222
OnPreToolUse: func(input copilot.PreToolUseHookInput, invocation copilot.HookInvocation) (*copilot.PreToolUseHookOutput, error) {
231223
mu.Lock()

go/internal/e2e/mcp_and_agents_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,7 @@ func TestMCPServers(t *testing.T) {
127127

128128
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
129129
MCPServers: mcpServers,
130-
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
131-
return copilot.PermissionRequestResult{Kind: "approved"}, nil
132-
},
130+
OnPermissionRequest: copilot.PermissionHandlers.ApproveAll,
133131
})
134132
if err != nil {
135133
t.Fatalf("Failed to create session: %v", err)

0 commit comments

Comments
 (0)