Skip to content

Commit bc990b4

Browse files
Test updates
1 parent ac170ea commit bc990b4

14 files changed

+129
-84
lines changed

dotnet/src/Client.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig config, Cance
395395
config.OnUserInputRequest != null ? true : null,
396396
hasHooks ? true : null,
397397
config.WorkingDirectory,
398-
config.Streaming == true ? true : null,
398+
config.Streaming is true ? true : null,
399399
config.McpServers,
400400
"direct",
401401
config.CustomAgents,
@@ -487,8 +487,8 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
487487
hasHooks ? true : null,
488488
config.WorkingDirectory,
489489
config.ConfigDir,
490-
config.DisableResume == true ? true : null,
491-
config.Streaming == true ? true : null,
490+
config.DisableResume is true ? true : null,
491+
config.Streaming is true ? true : null,
492492
config.McpServers,
493493
"direct",
494494
config.CustomAgents,

dotnet/test/PermissionTests.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public async Task Should_Deny_Permission_When_Handler_Returns_Denied()
5050
{
5151
return Task.FromResult(new PermissionRequestResult
5252
{
53-
Kind = "denied-interactively-by-user"
53+
Kind = "denied-no-approval-rule-and-could-not-request-from-user"
5454
});
5555
}
5656
});
@@ -71,9 +71,13 @@ await session.SendAsync(new MessageOptions
7171
}
7272

7373
[Fact]
74-
public async Task Should_Deny_Tool_Operations_By_Default_When_No_Handler_Is_Provided()
74+
public async Task Should_Deny_Tool_Operations_When_Handler_Explicitly_Denies()
7575
{
76-
var session = await CreateSessionAsync(new SessionConfig());
76+
var session = await CreateSessionAsync(new SessionConfig
77+
{
78+
OnPermissionRequest = (_, _) =>
79+
Task.FromResult(new PermissionRequestResult { Kind = "denied-no-approval-rule-and-could-not-request-from-user" })
80+
});
7781
var permissionDenied = false;
7882

7983
session.On(evt =>
@@ -95,9 +99,8 @@ await session.SendAndWaitAsync(new MessageOptions
9599
}
96100

97101
[Fact]
98-
public async Task Should_Work_Without_Permission_Handler__Default_Behavior_()
102+
public async Task Should_Work_With_Approve_All_Permission_Handler()
99103
{
100-
// Create session without permission handler
101104
var session = await CreateSessionAsync(new SessionConfig());
102105

103106
await session.SendAsync(new MessageOptions
@@ -186,7 +189,7 @@ await session.SendAsync(new MessageOptions
186189
}
187190

188191
[Fact]
189-
public async Task Should_Deny_Tool_Operations_By_Default_When_No_Handler_Is_Provided_After_Resume()
192+
public async Task Should_Deny_Tool_Operations_When_Handler_Explicitly_Denies_After_Resume()
190193
{
191194
var session1 = await CreateSessionAsync(new SessionConfig
192195
{
@@ -195,7 +198,11 @@ public async Task Should_Deny_Tool_Operations_By_Default_When_No_Handler_Is_Prov
195198
var sessionId = session1.SessionId;
196199
await session1.SendAndWaitAsync(new MessageOptions { Prompt = "What is 1+1?" });
197200

198-
var session2 = await ResumeSessionAsync(sessionId);
201+
var session2 = await ResumeSessionAsync(sessionId, new ResumeSessionConfig
202+
{
203+
OnPermissionRequest = (_, _) =>
204+
Task.FromResult(new PermissionRequestResult { Kind = "denied-no-approval-rule-and-could-not-request-from-user" })
205+
});
199206
var permissionDenied = false;
200207

201208
session2.On(evt =>

go/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ That's it! When your application calls `copilot.NewClient` without a `CLIPath` n
9999
- `Stop() error` - Stop the CLI server
100100
- `ForceStop()` - Forcefully stop without graceful cleanup
101101
- `CreateSession(config *SessionConfig) (*Session, error)` - Create a new session
102-
- `ResumeSession(sessionID string) (*Session, error)` - Resume an existing session
102+
- `ResumeSession(sessionID string, config *ResumeSessionConfig) (*Session, error)` - Resume an existing session
103103
- `ResumeSessionWithOptions(sessionID string, config *ResumeSessionConfig) (*Session, error)` - Resume with additional configuration
104104
- `ListSessions(filter *SessionListFilter) ([]SessionMetadata, error)` - List sessions (with optional filter)
105105
- `DeleteSession(sessionID string) error` - Delete a session permanently

go/client.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -426,17 +426,20 @@ func (c *Client) ensureConnected() error {
426426
// If the client is not connected and AutoStart is enabled, this will automatically
427427
// start the connection.
428428
//
429-
// The config parameter is optional; pass nil for default settings.
429+
// The config parameter is required and must include an OnPermissionRequest handler.
430430
//
431431
// Returns the created session or an error if session creation fails.
432432
//
433433
// Example:
434434
//
435435
// // Basic session
436-
// session, err := client.CreateSession(context.Background(), nil)
436+
// session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{
437+
// OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
438+
// })
437439
//
438440
// // Session with model and tools
439441
// session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{
442+
// OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
440443
// Model: "gpt-4",
441444
// Tools: []copilot.Tool{
442445
// {
@@ -518,15 +521,18 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
518521
return session, nil
519522
}
520523

521-
// ResumeSession resumes an existing conversation session by its ID using default options.
524+
// ResumeSession resumes an existing conversation session by its ID.
522525
//
523-
// This is a convenience method that calls [Client.ResumeSessionWithOptions] with nil config.
526+
// This is a convenience method that calls [Client.ResumeSessionWithOptions].
527+
// The config must include an OnPermissionRequest handler.
524528
//
525529
// Example:
526530
//
527-
// session, err := client.ResumeSession(context.Background(), "session-123")
528-
func (c *Client) ResumeSession(ctx context.Context, sessionID string) (*Session, error) {
529-
return c.ResumeSessionWithOptions(ctx, sessionID, nil)
531+
// session, err := client.ResumeSession(context.Background(), "session-123", &copilot.ResumeSessionConfig{
532+
// OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
533+
// })
534+
func (c *Client) ResumeSession(ctx context.Context, sessionID string, config *ResumeSessionConfig) (*Session, error) {
535+
return c.ResumeSessionWithOptions(ctx, sessionID, config)
530536
}
531537

532538
// ResumeSessionWithOptions resumes an existing conversation session with additional configuration.
@@ -537,6 +543,7 @@ func (c *Client) ResumeSession(ctx context.Context, sessionID string) (*Session,
537543
// Example:
538544
//
539545
// session, err := client.ResumeSessionWithOptions(context.Background(), "session-123", &copilot.ResumeSessionConfig{
546+
// OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
540547
// Tools: []copilot.Tool{myNewTool},
541548
// })
542549
func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, config *ResumeSessionConfig) (*Session, error) {

go/internal/e2e/permissions_test.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func TestPermissions(t *testing.T) {
117117
ctx.ConfigureForTest(t)
118118

119119
onPermissionRequest := func(request copilot.PermissionRequest, invocation copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
120-
return copilot.PermissionRequestResult{Kind: "denied-interactively-by-user"}, nil
120+
return copilot.PermissionRequestResult{Kind: "denied-no-approval-rule-and-could-not-request-from-user"}, nil
121121
}
122122

123123
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
@@ -157,10 +157,14 @@ func TestPermissions(t *testing.T) {
157157
}
158158
})
159159

160-
t.Run("should deny tool operations by default when no handler is provided", func(t *testing.T) {
160+
t.Run("should deny tool operations when handler explicitly denies", func(t *testing.T) {
161161
ctx.ConfigureForTest(t)
162162

163-
session, err := client.CreateSession(t.Context(), nil)
163+
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
164+
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.ToolInvocation) (copilot.PermissionRequestResult, error) {
165+
return copilot.PermissionRequestResult{Kind: "denied-no-approval-rule-and-could-not-request-from-user"}, nil
166+
},
167+
})
164168
if err != nil {
165169
t.Fatalf("Failed to create session: %v", err)
166170
}
@@ -192,7 +196,7 @@ func TestPermissions(t *testing.T) {
192196
}
193197
})
194198

195-
t.Run("should deny tool operations by default when no handler is provided after resume", func(t *testing.T) {
199+
t.Run("should deny tool operations when handler explicitly denies after resume", func(t *testing.T) {
196200
ctx.ConfigureForTest(t)
197201

198202
session1, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
@@ -206,7 +210,11 @@ func TestPermissions(t *testing.T) {
206210
t.Fatalf("Failed to send message: %v", err)
207211
}
208212

209-
session2, err := client.ResumeSession(t.Context(), sessionID)
213+
session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
214+
OnPermissionRequest: func(request copilot.PermissionRequest, invocation copilot.ToolInvocation) (copilot.PermissionRequestResult, error) {
215+
return copilot.PermissionRequestResult{Kind: "denied-no-approval-rule-and-could-not-request-from-user"}, nil
216+
},
217+
})
210218
if err != nil {
211219
t.Fatalf("Failed to resume session: %v", err)
212220
}
@@ -238,10 +246,12 @@ func TestPermissions(t *testing.T) {
238246
}
239247
})
240248

241-
t.Run("without permission handler", func(t *testing.T) {
249+
t.Run("should work with approve-all permission handler", func(t *testing.T) {
242250
ctx.ConfigureForTest(t)
243251

244-
session, err := client.CreateSession(t.Context(), nil)
252+
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
253+
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
254+
})
245255
if err != nil {
246256
t.Fatalf("Failed to create session: %v", err)
247257
}

go/internal/e2e/session_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,9 @@ func TestSession(t *testing.T) {
344344
}
345345

346346
// Resume using the same client
347-
session2, err := client.ResumeSession(t.Context(), sessionID)
347+
session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
348+
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
349+
})
348350
if err != nil {
349351
t.Fatalf("Failed to resume session: %v", err)
350352
}
@@ -391,7 +393,9 @@ func TestSession(t *testing.T) {
391393
newClient := ctx.NewClient()
392394
defer newClient.ForceStop()
393395

394-
session2, err := newClient.ResumeSession(t.Context(), sessionID)
396+
session2, err := newClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
397+
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
398+
})
395399
if err != nil {
396400
t.Fatalf("Failed to resume session: %v", err)
397401
}
@@ -428,7 +432,9 @@ func TestSession(t *testing.T) {
428432
t.Run("should throw error when resuming non-existent session", func(t *testing.T) {
429433
ctx.ConfigureForTest(t)
430434

431-
_, err := client.ResumeSession(t.Context(), "non-existent-session-id")
435+
_, err := client.ResumeSession(t.Context(), "non-existent-session-id", &copilot.ResumeSessionConfig{
436+
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
437+
})
432438
if err == nil {
433439
t.Error("Expected error when resuming non-existent session")
434440
}
@@ -881,7 +887,9 @@ func TestSession(t *testing.T) {
881887
}
882888

883889
// Verify we cannot resume the deleted session
884-
_, err = client.ResumeSession(t.Context(), sessionID)
890+
_, err = client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
891+
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
892+
})
885893
if err == nil {
886894
t.Error("Expected error when resuming deleted session")
887895
}

nodejs/src/client.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -494,10 +494,11 @@ export class CopilotClient {
494494
* @example
495495
* ```typescript
496496
* // Basic session
497-
* const session = await client.createSession();
497+
* const session = await client.createSession({ onPermissionRequest: approveAll });
498498
*
499499
* // Session with model and tools
500500
* const session = await client.createSession({
501+
* onPermissionRequest: approveAll,
501502
* model: "gpt-4",
502503
* tools: [{
503504
* name: "get_weather",
@@ -557,9 +558,7 @@ export class CopilotClient {
557558
};
558559
const session = new CopilotSession(sessionId, this.connection!, workspacePath);
559560
session.registerTools(config.tools);
560-
if (config.onPermissionRequest) {
561-
session.registerPermissionHandler(config.onPermissionRequest);
562-
}
561+
session.registerPermissionHandler(config.onPermissionRequest);
563562
if (config.onUserInputRequest) {
564563
session.registerUserInputHandler(config.onUserInputRequest);
565564
}
@@ -586,10 +585,11 @@ export class CopilotClient {
586585
* @example
587586
* ```typescript
588587
* // Resume a previous session
589-
* const session = await client.resumeSession("session-123");
588+
* const session = await client.resumeSession("session-123", { onPermissionRequest: approveAll });
590589
*
591590
* // Resume with new tools
592591
* const session = await client.resumeSession("session-123", {
592+
* onPermissionRequest: approveAll,
593593
* tools: [myNewTool]
594594
* });
595595
* ```
@@ -644,9 +644,7 @@ export class CopilotClient {
644644
};
645645
const session = new CopilotSession(resumedSessionId, this.connection!, workspacePath);
646646
session.registerTools(config.tools);
647-
if (config.onPermissionRequest) {
648-
session.registerPermissionHandler(config.onPermissionRequest);
649-
}
647+
session.registerPermissionHandler(config.onPermissionRequest);
650648
if (config.onUserInputRequest) {
651649
session.registerUserInputHandler(config.onUserInputRequest);
652650
}

nodejs/test/e2e/permissions.test.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,14 @@ describe("Permission callbacks", async () => {
6464
await session.destroy();
6565
});
6666

67-
it("should deny tool operations by default when no handler is provided", async () => {
67+
it("should deny tool operations when handler explicitly denies", async () => {
6868
let permissionDenied = false;
6969

70-
const session = await client.createSession({ onPermissionRequest: approveAll });
70+
const session = await client.createSession({
71+
onPermissionRequest: () => ({
72+
kind: "denied-no-approval-rule-and-could-not-request-from-user",
73+
}),
74+
});
7175
session.on((event) => {
7276
if (
7377
event.type === "tool.execution_complete" &&
@@ -85,12 +89,16 @@ describe("Permission callbacks", async () => {
8589
await session.destroy();
8690
});
8791

88-
it("should deny tool operations by default when no handler is provided after resume", async () => {
92+
it("should deny tool operations when handler explicitly denies after resume", async () => {
8993
const session1 = await client.createSession({ onPermissionRequest: approveAll });
9094
const sessionId = session1.sessionId;
9195
await session1.sendAndWait({ prompt: "What is 1+1?" });
9296

93-
const session2 = await client.resumeSession(sessionId, { onPermissionRequest: approveAll });
97+
const session2 = await client.resumeSession(sessionId, {
98+
onPermissionRequest: () => ({
99+
kind: "denied-no-approval-rule-and-could-not-request-from-user",
100+
}),
101+
});
94102
let permissionDenied = false;
95103
session2.on((event) => {
96104
if (
@@ -109,8 +117,7 @@ describe("Permission callbacks", async () => {
109117
await session2.destroy();
110118
});
111119

112-
it("should work without permission handler (default behavior)", async () => {
113-
// Create session without onPermissionRequest handler
120+
it("should work with approve-all permission handler", async () => {
114121
const session = await client.createSession({ onPermissionRequest: approveAll });
115122

116123
const message = await session.sendAndWait({
@@ -147,7 +154,7 @@ describe("Permission callbacks", async () => {
147154
it("should resume session with permission handler", async () => {
148155
const permissionRequests: PermissionRequest[] = [];
149156

150-
// Create session without permission handler
157+
// Create initial session
151158
const session1 = await client.createSession({ onPermissionRequest: approveAll });
152159
const sessionId = session1.sessionId;
153160
await session1.sendAndWait({ prompt: "What is 1+1?" });

python/copilot/client.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,11 @@ async def create_session(self, config: SessionConfig) -> CopilotSession:
434434
435435
Example:
436436
>>> # Basic session
437-
>>> session = await client.create_session()
437+
>>> session = await client.create_session({"on_permission_request": PermissionHandler.approve_all})
438438
>>>
439439
>>> # Session with model and streaming
440440
>>> session = await client.create_session({
441+
... "on_permission_request": PermissionHandler.approve_all,
441442
... "model": "gpt-4",
442443
... "streaming": True
443444
... })
@@ -575,8 +576,7 @@ async def create_session(self, config: SessionConfig) -> CopilotSession:
575576
workspace_path = response.get("workspacePath")
576577
session = CopilotSession(session_id, self._client, workspace_path)
577578
session._register_tools(tools)
578-
if on_permission_request:
579-
session._register_permission_handler(on_permission_request)
579+
session._register_permission_handler(on_permission_request)
580580
if on_user_input_request:
581581
session._register_user_input_handler(on_user_input_request)
582582
if hooks:
@@ -606,10 +606,11 @@ async def resume_session(self, session_id: str, config: ResumeSessionConfig) ->
606606
607607
Example:
608608
>>> # Resume a previous session
609-
>>> session = await client.resume_session("session-123")
609+
>>> session = await client.resume_session("session-123", {"on_permission_request": PermissionHandler.approve_all})
610610
>>>
611611
>>> # Resume with new tools
612612
>>> session = await client.resume_session("session-123", {
613+
... "on_permission_request": PermissionHandler.approve_all,
613614
... "tools": [my_new_tool]
614615
... })
615616
"""
@@ -756,8 +757,7 @@ async def resume_session(self, session_id: str, config: ResumeSessionConfig) ->
756757
workspace_path = response.get("workspacePath")
757758
session = CopilotSession(resumed_session_id, self._client, workspace_path)
758759
session._register_tools(cfg.get("tools"))
759-
if on_permission_request:
760-
session._register_permission_handler(on_permission_request)
760+
session._register_permission_handler(on_permission_request)
761761
if on_user_input_request:
762762
session._register_user_input_handler(on_user_input_request)
763763
if hooks:

0 commit comments

Comments
 (0)