Skip to content
Merged
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
12 changes: 3 additions & 9 deletions go/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,9 +607,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
req.ReasoningSummary = config.ReasoningSummary
req.ContextTier = config.ContextTier
req.ConfigDir = config.ConfigDirectory
if config.EnableConfigDiscovery {
req.EnableConfigDiscovery = Bool(true)
}
req.EnableConfigDiscovery = config.EnableConfigDiscovery
req.SkipEmbeddingRetrieval = config.SkipEmbeddingRetrieval
req.EmbeddingCacheStorage = config.EmbeddingCacheStorage
req.OrganizationCustomInstructions = config.OrganizationCustomInstructions
Expand Down Expand Up @@ -960,9 +958,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
}
req.WorkingDirectory = config.WorkingDirectory
req.ConfigDir = config.ConfigDirectory
if config.EnableConfigDiscovery {
req.EnableConfigDiscovery = Bool(true)
}
req.EnableConfigDiscovery = config.EnableConfigDiscovery
req.SkipEmbeddingRetrieval = config.SkipEmbeddingRetrieval
req.EmbeddingCacheStorage = config.EmbeddingCacheStorage
req.OrganizationCustomInstructions = config.OrganizationCustomInstructions
Expand All @@ -974,9 +970,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
if config.SuppressResumeEvent {
req.DisableResume = Bool(true)
}
if config.ContinuePendingWork {
req.ContinuePendingWork = Bool(true)
}
req.ContinuePendingWork = config.ContinuePendingWork
req.MCPServers = config.MCPServers
req.MCPOAuthTokenStorage = config.MCPOAuthTokenStorage
req.EnvValueMode = "direct"
Expand Down
85 changes: 85 additions & 0 deletions go/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,73 @@ func TestSessionRequests_ContextTier(t *testing.T) {
})
}

func TestSessionRequests_EnableConfigDiscovery(t *testing.T) {
t.Run("create includes enableConfigDiscovery when true", func(t *testing.T) {
req := createSessionRequest{EnableConfigDiscovery: Bool(true)}
data, err := json.Marshal(req)
if err != nil {
t.Fatalf("Failed to marshal: %v", err)
}
var m map[string]any
if err := json.Unmarshal(data, &m); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if m["enableConfigDiscovery"] != true {
t.Errorf("Expected enableConfigDiscovery to be true, got %v", m["enableConfigDiscovery"])
}
})

t.Run("create includes enableConfigDiscovery when false", func(t *testing.T) {
req := createSessionRequest{EnableConfigDiscovery: Bool(false)}
data, err := json.Marshal(req)
if err != nil {
t.Fatalf("Failed to marshal: %v", err)
}
var m map[string]any
if err := json.Unmarshal(data, &m); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if m["enableConfigDiscovery"] != false {
t.Errorf("Expected enableConfigDiscovery to be false, got %v", m["enableConfigDiscovery"])
}
})

t.Run("create omits enableConfigDiscovery when unset", func(t *testing.T) {
req := createSessionRequest{}
data, _ := json.Marshal(req)
var m map[string]any
json.Unmarshal(data, &m)
if _, ok := m["enableConfigDiscovery"]; ok {
t.Error("Expected enableConfigDiscovery to be omitted when unset")
}
})
Comment on lines +500 to +508

t.Run("resume includes enableConfigDiscovery when false", func(t *testing.T) {
req := resumeSessionRequest{SessionID: "s1", EnableConfigDiscovery: Bool(false)}
data, err := json.Marshal(req)
if err != nil {
t.Fatalf("Failed to marshal: %v", err)
}
var m map[string]any
if err := json.Unmarshal(data, &m); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if m["enableConfigDiscovery"] != false {
t.Errorf("Expected enableConfigDiscovery to be false, got %v", m["enableConfigDiscovery"])
}
})

t.Run("resume omits enableConfigDiscovery when unset", func(t *testing.T) {
req := resumeSessionRequest{SessionID: "s1"}
data, _ := json.Marshal(req)
var m map[string]any
json.Unmarshal(data, &m)
if _, ok := m["enableConfigDiscovery"]; ok {
t.Error("Expected enableConfigDiscovery to be omitted when unset")
}
})
Comment on lines +525 to +533
}

func TestSessionRequests_PluginDirectoriesAndLargeOutput(t *testing.T) {
pluginDirs := []string{"/tmp/plugins/a", "/tmp/plugins/b"}
enabled := true
Expand Down Expand Up @@ -1333,6 +1400,24 @@ func TestResumeSessionRequest_ContinuePendingWork(t *testing.T) {
}
})

t.Run("forwards continuePendingWork when false", func(t *testing.T) {
req := resumeSessionRequest{
SessionID: "s1",
ContinuePendingWork: Bool(false),
}
data, err := json.Marshal(req)
if err != nil {
t.Fatalf("Failed to marshal: %v", err)
}
var m map[string]any
if err := json.Unmarshal(data, &m); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if m["continuePendingWork"] != false {
t.Errorf("Expected continuePendingWork to be false, got %v", m["continuePendingWork"])
}
})

t.Run("omits continuePendingWork when not set", func(t *testing.T) {
req := resumeSessionRequest{SessionID: "s1"}
data, _ := json.Marshal(req)
Expand Down
2 changes: 1 addition & 1 deletion go/internal/e2e/client_options_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func TestClientOptionsE2E(t *testing.T) {
}

session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
EnableConfigDiscovery: true,
EnableConfigDiscovery: copilot.Bool(true),
EnableOnDemandInstructionDiscovery: copilot.Bool(true),
IncludeSubAgentStreamingEvents: copilot.Bool(false),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Expand Down
12 changes: 6 additions & 6 deletions go/internal/e2e/pending_work_resume_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Cleanup(func() { resumedClient.ForceStop() })

session2, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
ContinuePendingWork: true,
ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: func(_ copilot.PermissionRequest, _ copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
return &rpc.PermissionDecisionNoResult{}, nil
},
Expand Down Expand Up @@ -200,7 +200,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Cleanup(func() { resumedClient.ForceStop() })

session2, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
ContinuePendingWork: true,
ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
Expand Down Expand Up @@ -305,7 +305,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Cleanup(func() { resumedClient.ForceStop() })

session2, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
ContinuePendingWork: true,
ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
Expand Down Expand Up @@ -379,7 +379,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Cleanup(func() { resumedClient.ForceStop() })

resumedSession, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
ContinuePendingWork: true,
ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
Expand Down Expand Up @@ -482,7 +482,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
// to assert the runtime doesn't re-invoke the tool on resume (orphan
// auto-completion happens internally).
resumeConfig := &copilot.ResumeSessionConfig{
ContinuePendingWork: false,
ContinuePendingWork: copilot.Bool(false),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
}
if scenario.disconnectOriginalClient {
Expand Down Expand Up @@ -600,7 +600,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Cleanup(func() { resumedClient.ForceStop() })

resumedSession, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
ContinuePendingWork: true,
ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go/internal/e2e/rpc_server_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ func TestRPCServerE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
SessionID: sessionID,
WorkingDirectory: workingDirectory,
EnableConfigDiscovery: false,
EnableConfigDiscovery: copilot.Bool(false),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions go/internal/e2e/skills_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func TestSkillsE2E(t *testing.T) {
disabledSession, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
WorkingDirectory: projectDir,
EnableConfigDiscovery: false,
EnableConfigDiscovery: copilot.Bool(false),
})
if err != nil {
t.Fatalf("CreateSession (disabled) failed: %v", err)
Expand All @@ -278,7 +278,7 @@ func TestSkillsE2E(t *testing.T) {
enabledSession, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
WorkingDirectory: projectDir,
EnableConfigDiscovery: true,
EnableConfigDiscovery: copilot.Bool(true),
})
if err != nil {
t.Fatalf("CreateSession (enabled) failed: %v", err)
Expand Down
4 changes: 2 additions & 2 deletions go/samples/manual_tool_resume/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func main() {
}
session2, err := client2.ResumeSession(ctx, sessionID, &copilot.ResumeSessionConfig{
Tools: []copilot.Tool{tool},
ContinuePendingWork: true,
ContinuePendingWork: copilot.Bool(true),
})
if err != nil {
panic(err)
Expand Down Expand Up @@ -177,7 +177,7 @@ func main() {
}
session3, err := client3.ResumeSession(ctx, sessionID, &copilot.ResumeSessionConfig{
Tools: []copilot.Tool{tool},
ContinuePendingWork: true,
ContinuePendingWork: copilot.Bool(true),
})
if err != nil {
panic(err)
Expand Down
19 changes: 11 additions & 8 deletions go/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -901,13 +901,14 @@ type SessionConfig struct {
// ConfigDirectory overrides the default configuration directory location.
// When specified, the session will use this directory for storing config and state.
ConfigDirectory string
// EnableConfigDiscovery, when true, automatically discovers MCP server configurations
// EnableConfigDiscovery, when non-nil, controls automatic discovery of MCP server configurations
// (e.g. .mcp.json, .vscode/mcp.json) and skill directories from the working directory
// and merges them with any explicitly provided MCPServers and SkillDirectories, with
// explicit values taking precedence on name collision.
// Nil leaves the runtime default unchanged; use Bool(false) to explicitly disable discovery.
// Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) are
// always loaded from the working directory regardless of this setting.
EnableConfigDiscovery bool
EnableConfigDiscovery *bool
Comment on lines +904 to +911
// SkipEmbeddingRetrieval, when non-nil, controls embedding-based retrieval
// for this session. Use in multitenant deployments to prevent cross-session
// information leakage through the shared embedding cache.
Expand Down Expand Up @@ -1314,13 +1315,14 @@ type ResumeSessionConfig struct {
WorkingDirectory string
// ConfigDirectory overrides the default configuration directory location.
ConfigDirectory string
// EnableConfigDiscovery, when true, automatically discovers MCP server configurations
// EnableConfigDiscovery, when non-nil, controls automatic discovery of MCP server configurations
// (e.g. .mcp.json, .vscode/mcp.json) and skill directories from the working directory
// and merges them with any explicitly provided MCPServers and SkillDirectories, with
// explicit values taking precedence on name collision.
// Nil leaves the runtime default unchanged; use Bool(false) to explicitly disable discovery.
// Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) are
// always loaded from the working directory regardless of this setting.
EnableConfigDiscovery bool
EnableConfigDiscovery *bool
// SkipEmbeddingRetrieval, when non-nil, controls embedding-based retrieval
// for this session. Use in multitenant deployments to prevent cross-session
// information leakage through the shared embedding cache.
Expand Down Expand Up @@ -1399,15 +1401,16 @@ type ResumeSessionConfig struct {
// SuppressResumeEvent, when true, skips emitting the session.resume event.
// Useful for reconnecting to a session without triggering resume-related side effects.
SuppressResumeEvent bool
// ContinuePendingWork, when true, instructs the runtime to continue any tool calls
// or permission prompts that were still pending when the session was last suspended.
// When false (the default), the runtime treats pending work as interrupted on resume.
// ContinuePendingWork, when non-nil, controls whether the runtime continues any
// tool calls or permission prompts that were still pending when the session was
// last suspended. Nil leaves the runtime default unchanged; use Bool(false) to
// explicitly treat pending work as interrupted on resume.
//
// For permission requests, the runtime re-emits permission.requested so the
// registered OnPermissionRequest handler can re-prompt; for external tool calls,
// the consumer is expected to supply the result via the corresponding low-level
// RPC method.
ContinuePendingWork bool
ContinuePendingWork *bool
// OnEvent is an optional event handler registered before the session.resume RPC
// is issued, ensuring early events are delivered. See SessionConfig.OnEvent.
OnEvent SessionEventHandler
Expand Down
Loading