Skip to content
Closed
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
4 changes: 4 additions & 0 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig config, Cance
config.AvailableTools,
config.ExcludedTools,
config.Provider,
config.EnableSessionTelemetry,
(bool?)true,
config.OnUserInputRequest != null ? true : null,
hasHooks ? true : null,
Expand Down Expand Up @@ -694,6 +695,7 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
config.AvailableTools,
config.ExcludedTools,
config.Provider,
config.EnableSessionTelemetry,
(bool?)true,
config.OnUserInputRequest != null ? true : null,
hasHooks ? true : null,
Expand Down Expand Up @@ -1781,6 +1783,7 @@ internal record CreateSessionRequest(
IList<string>? AvailableTools,
IList<string>? ExcludedTools,
ProviderConfig? Provider,
bool? EnableSessionTelemetry,
bool? RequestPermission,
bool? RequestUserInput,
bool? Hooks,
Expand Down Expand Up @@ -1837,6 +1840,7 @@ internal record ResumeSessionRequest(
IList<string>? AvailableTools,
IList<string>? ExcludedTools,
ProviderConfig? Provider,
bool? EnableSessionTelemetry,
bool? RequestPermission,
bool? RequestUserInput,
bool? Hooks,
Expand Down
24 changes: 24 additions & 0 deletions dotnet/src/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1849,6 +1849,7 @@ protected SessionConfig(SessionConfig? other)
OnPermissionRequest = other.OnPermissionRequest;
OnUserInputRequest = other.OnUserInputRequest;
Provider = other.Provider;
EnableSessionTelemetry = other.EnableSessionTelemetry;
ReasoningEffort = other.ReasoningEffort;
CreateSessionFsHandler = other.CreateSessionFsHandler;
GitHubToken = other.GitHubToken;
Expand Down Expand Up @@ -1930,6 +1931,17 @@ protected SessionConfig(SessionConfig? other)
/// </summary>
public ProviderConfig? Provider { get; set; }

/// <summary>
/// Enables or disables internal session telemetry for this session.
/// When <c>false</c>, disables session telemetry. When <c>null</c> (the default) or <c>true</c>,
/// telemetry is enabled for GitHub-authenticated sessions.
/// When a custom <see cref="Provider"/> (BYOK) is configured, session telemetry is
/// always disabled regardless of this setting.
/// This is independent of <see cref="CopilotClientOptions.Telemetry"/>, which configures
/// OpenTelemetry export for observability.
/// </summary>
public bool? EnableSessionTelemetry { get; set; }

/// <summary>
/// Handler for permission requests from the server.
/// When provided, the server will call this handler to request permission for operations.
Expand Down Expand Up @@ -2114,6 +2126,7 @@ protected ResumeSessionConfig(ResumeSessionConfig? other)
OnPermissionRequest = other.OnPermissionRequest;
OnUserInputRequest = other.OnUserInputRequest;
Provider = other.Provider;
EnableSessionTelemetry = other.EnableSessionTelemetry;
ReasoningEffort = other.ReasoningEffort;
CreateSessionFsHandler = other.CreateSessionFsHandler;
GitHubToken = other.GitHubToken;
Expand Down Expand Up @@ -2164,6 +2177,17 @@ protected ResumeSessionConfig(ResumeSessionConfig? other)
/// </summary>
public ProviderConfig? Provider { get; set; }

/// <summary>
/// Enables or disables internal session telemetry for this session.
/// When <c>false</c>, disables session telemetry. When <c>null</c> (the default) or <c>true</c>,
/// telemetry is enabled for GitHub-authenticated sessions.
/// When a custom <see cref="Provider"/> (BYOK) is configured, session telemetry is
/// always disabled regardless of this setting.
/// This is independent of <see cref="CopilotClientOptions.Telemetry"/>, which configures
/// OpenTelemetry export for observability.
/// </summary>
public bool? EnableSessionTelemetry { get; set; }

/// <summary>
/// Reasoning effort level for models that support it.
/// Valid values: "low", "medium", "high", "xhigh".
Expand Down
57 changes: 57 additions & 0 deletions dotnet/test/E2E/ClientOptionsE2ETests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,63 @@ public async Task Should_Propagate_Process_Options_To_Spawned_Cli()
await session.DisposeAsync();
}

[Fact]
public async Task Should_Forward_EnableSessionTelemetry_In_Wire_Request()
{
var (cliPath, capturePath) = await CreateFakeCliCaptureAsync();

await using var client = Ctx.CreateClient(options: new CopilotClientOptions
{
AutoStart = false,
CliPath = cliPath,
CliArgs = ["--capture-file", capturePath],
UseLoggedInUser = false,
});

await client.StartAsync();

// When explicitly set to false, it should appear in the wire request
var session = await client.CreateSessionAsync(new SessionConfig
{
EnableSessionTelemetry = false,
OnPermissionRequest = PermissionHandler.ApproveAll,
});

using var capture = JsonDocument.Parse(await File.ReadAllTextAsync(capturePath));
var createRequest = GetCapturedRequestParams(capture.RootElement, "session.create");
Assert.False(createRequest.GetProperty("enableSessionTelemetry").GetBoolean());

await session.DisposeAsync();
}

[Fact]
public async Task Should_Omit_EnableSessionTelemetry_When_Not_Set()
{
var (cliPath, capturePath) = await CreateFakeCliCaptureAsync();

await using var client = Ctx.CreateClient(options: new CopilotClientOptions
{
AutoStart = false,
CliPath = cliPath,
CliArgs = ["--capture-file", capturePath],
UseLoggedInUser = false,
});

await client.StartAsync();

// When omitted (null/default), the field should not be present in the wire request
var session = await client.CreateSessionAsync(new SessionConfig
{
OnPermissionRequest = PermissionHandler.ApproveAll,
});

using var capture = JsonDocument.Parse(await File.ReadAllTextAsync(capturePath));
var createRequest = GetCapturedRequestParams(capture.RootElement, "session.create");
Assert.False(createRequest.TryGetProperty("enableSessionTelemetry", out _));

await session.DisposeAsync();
}
Comment thread
stephentoub marked this conversation as resolved.

[Fact]
public async Task Should_Propagate_Activity_TraceContext_To_Session_Create_And_Send()
{
Expand Down
35 changes: 35 additions & 0 deletions dotnet/test/Unit/CloneTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public void SessionConfig_Clone_CopiesAllProperties()
ExcludedTools = ["tool3"],
WorkingDirectory = "/workspace",
Streaming = true,
EnableSessionTelemetry = false,
IncludeSubAgentStreamingEvents = false,
McpServers = new Dictionary<string, McpServerConfig> { ["server1"] = new McpStdioServerConfig { Command = "echo" } },
CustomAgents = [new CustomAgentConfig { Name = "agent1" }],
Expand All @@ -111,6 +112,7 @@ public void SessionConfig_Clone_CopiesAllProperties()
Assert.Equal(original.ExcludedTools, clone.ExcludedTools);
Assert.Equal(original.WorkingDirectory, clone.WorkingDirectory);
Assert.Equal(original.Streaming, clone.Streaming);
Assert.Equal(original.EnableSessionTelemetry, clone.EnableSessionTelemetry);
Assert.Equal(original.IncludeSubAgentStreamingEvents, clone.IncludeSubAgentStreamingEvents);
Assert.Equal(original.McpServers.Count, clone.McpServers!.Count);
Assert.Equal(original.CustomAgents.Count, clone.CustomAgents!.Count);
Expand Down Expand Up @@ -315,6 +317,19 @@ public void ResumeSessionConfig_Clone_PreservesIncludeSubAgentStreamingEventsDef
Assert.True(clone.IncludeSubAgentStreamingEvents);
}

[Fact]
public void ResumeSessionConfig_Clone_CopiesEnableSessionTelemetry()
{
var original = new ResumeSessionConfig
{
EnableSessionTelemetry = false,
};

var clone = original.Clone();

Assert.False(clone.EnableSessionTelemetry);
}

[Fact]
public void ResumeSessionConfig_Clone_CopiesContinuePendingWork()
{
Expand All @@ -337,4 +352,24 @@ public void ResumeSessionConfig_Clone_PreservesContinuePendingWorkDefault()

Assert.Null(clone.ContinuePendingWork);
}

[Fact]
public void SessionConfig_Clone_PreservesEnableSessionTelemetryDefault()
{
var original = new SessionConfig();

var clone = original.Clone();

Assert.Null(clone.EnableSessionTelemetry);
}

[Fact]
public void ResumeSessionConfig_Clone_PreservesEnableSessionTelemetryDefault()
{
var original = new ResumeSessionConfig();

var clone = original.Clone();

Assert.Null(clone.EnableSessionTelemetry);
}
}
Comment thread
Davsterl marked this conversation as resolved.
32 changes: 32 additions & 0 deletions dotnet/test/Unit/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,38 @@ public void ResumeSessionRequest_CanSerializeInstructionDirectories_WithSdkOptio
Assert.Equal("C:\\resume-instructions", root.GetProperty("instructionDirectories")[0].GetString());
}

[Fact]
public void CreateSessionRequest_CanSerializeEnableSessionTelemetry_WithSdkOptions()
{
var options = GetSerializerOptions();
var requestType = GetNestedType(typeof(CopilotClient), "CreateSessionRequest");
var request = CreateInternalRequest(
requestType,
("SessionId", "session-id"),
("EnableSessionTelemetry", false));

var json = JsonSerializer.Serialize(request, requestType, options);
using var document = JsonDocument.Parse(json);
var root = document.RootElement;
Assert.False(root.GetProperty("enableSessionTelemetry").GetBoolean());
}

[Fact]
public void ResumeSessionRequest_CanSerializeEnableSessionTelemetry_WithSdkOptions()
{
var options = GetSerializerOptions();
var requestType = GetNestedType(typeof(CopilotClient), "ResumeSessionRequest");
var request = CreateInternalRequest(
requestType,
("SessionId", "session-id"),
("EnableSessionTelemetry", false));

var json = JsonSerializer.Serialize(request, requestType, options);
using var document = JsonDocument.Parse(json);
var root = document.RootElement;
Assert.False(root.GetProperty("enableSessionTelemetry").GetBoolean());
}

[Fact]
public void McpHttpServerConfig_CanSerializeOauthOptions_WithSdkOptions()
{
Expand Down
2 changes: 2 additions & 0 deletions go/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
req.AvailableTools = config.AvailableTools
req.ExcludedTools = config.ExcludedTools
req.Provider = config.Provider
req.EnableSessionTelemetry = config.EnableSessionTelemetry
req.ModelCapabilities = config.ModelCapabilities
req.WorkingDirectory = config.WorkingDirectory
req.MCPServers = config.MCPServers
Expand Down Expand Up @@ -789,6 +790,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
req.SystemMessage = wireSystemMessage
req.Tools = config.Tools
req.Provider = config.Provider
req.EnableSessionTelemetry = config.EnableSessionTelemetry
req.ModelCapabilities = config.ModelCapabilities
req.AvailableTools = config.AvailableTools
req.ExcludedTools = config.ExcludedTools
Expand Down
59 changes: 59 additions & 0 deletions go/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,35 @@ func TestResumeSessionRequest_ContinuePendingWork(t *testing.T) {
})
}

func TestCreateSessionRequest_EnableSessionTelemetry(t *testing.T) {
t.Run("forwards enableSessionTelemetry when false", func(t *testing.T) {
req := createSessionRequest{
EnableSessionTelemetry: 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["enableSessionTelemetry"] != false {
t.Errorf("Expected enableSessionTelemetry to be false, got %v", m["enableSessionTelemetry"])
}
})

t.Run("omits enableSessionTelemetry when not set", func(t *testing.T) {
req := createSessionRequest{}
data, _ := json.Marshal(req)
var m map[string]any
json.Unmarshal(data, &m)
if _, ok := m["enableSessionTelemetry"]; ok {
t.Error("Expected enableSessionTelemetry to be omitted when not set")
}
})
}

func TestCreateSessionRequest_IncludeSubAgentStreamingEvents(t *testing.T) {
t.Run("defaults to true when nil", func(t *testing.T) {
req := createSessionRequest{
Expand Down Expand Up @@ -1026,6 +1055,36 @@ func TestCreateSessionRequest_IncludeSubAgentStreamingEvents(t *testing.T) {
})
}

func TestResumeSessionRequest_EnableSessionTelemetry(t *testing.T) {
t.Run("forwards enableSessionTelemetry when false", func(t *testing.T) {
req := resumeSessionRequest{
SessionID: "s1",
EnableSessionTelemetry: 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["enableSessionTelemetry"] != false {
t.Errorf("Expected enableSessionTelemetry to be false, got %v", m["enableSessionTelemetry"])
}
})

t.Run("omits enableSessionTelemetry when not set", func(t *testing.T) {
req := resumeSessionRequest{SessionID: "s1"}
data, _ := json.Marshal(req)
var m map[string]any
json.Unmarshal(data, &m)
if _, ok := m["enableSessionTelemetry"]; ok {
t.Error("Expected enableSessionTelemetry to be omitted when not set")
}
})
}

func TestResumeSessionRequest_IncludeSubAgentStreamingEvents(t *testing.T) {
t.Run("defaults to true when nil", func(t *testing.T) {
req := resumeSessionRequest{
Expand Down
16 changes: 16 additions & 0 deletions go/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,13 @@ type SessionConfig struct {
IncludeSubAgentStreamingEvents *bool
// Provider configures a custom model provider (BYOK)
Provider *ProviderConfig
// EnableSessionTelemetry enables or disables internal session telemetry.
// When false, disables session telemetry. When nil (the default) or true,
// telemetry is enabled for GitHub-authenticated sessions. When a custom
// Provider (BYOK) is configured, session telemetry is always disabled
// regardless of this setting. This is independent of the OpenTelemetry
// configuration in CopilotClientOptions.
EnableSessionTelemetry *bool
// ModelCapabilities overrides individual model capabilities resolved by the runtime.
// Only non-nil fields are applied over the runtime-resolved capabilities.
ModelCapabilities *rpc.ModelCapabilitiesOverride
Expand Down Expand Up @@ -760,6 +767,13 @@ type ResumeSessionConfig struct {
ExcludedTools []string
// Provider configures a custom model provider
Provider *ProviderConfig
// EnableSessionTelemetry enables or disables internal session telemetry.
// When false, disables session telemetry. When nil (the default) or true,
// telemetry is enabled for GitHub-authenticated sessions. When a custom
// Provider (BYOK) is configured, session telemetry is always disabled
// regardless of this setting. This is independent of the OpenTelemetry
// configuration in CopilotClientOptions.
EnableSessionTelemetry *bool
// ModelCapabilities overrides individual model capabilities resolved by the runtime.
// Only non-nil fields are applied over the runtime-resolved capabilities.
ModelCapabilities *rpc.ModelCapabilitiesOverride
Expand Down Expand Up @@ -1039,6 +1053,7 @@ type createSessionRequest struct {
AvailableTools []string `json:"availableTools"`
ExcludedTools []string `json:"excludedTools,omitempty"`
Provider *ProviderConfig `json:"provider,omitempty"`
EnableSessionTelemetry *bool `json:"enableSessionTelemetry,omitempty"`
ModelCapabilities *rpc.ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"`
RequestPermission *bool `json:"requestPermission,omitempty"`
RequestUserInput *bool `json:"requestUserInput,omitempty"`
Expand Down Expand Up @@ -1088,6 +1103,7 @@ type resumeSessionRequest struct {
AvailableTools []string `json:"availableTools"`
ExcludedTools []string `json:"excludedTools,omitempty"`
Provider *ProviderConfig `json:"provider,omitempty"`
EnableSessionTelemetry *bool `json:"enableSessionTelemetry,omitempty"`
ModelCapabilities *rpc.ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"`
RequestPermission *bool `json:"requestPermission,omitempty"`
RequestUserInput *bool `json:"requestUserInput,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions nodejs/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ export class CopilotClient {
availableTools: config.availableTools,
excludedTools: config.excludedTools,
provider: config.provider ? toWireProviderConfig(config.provider) : undefined,
enableSessionTelemetry: config.enableSessionTelemetry,
modelCapabilities: config.modelCapabilities,
requestPermission: true,
requestUserInput: !!config.onUserInputRequest,
Expand Down Expand Up @@ -932,6 +933,7 @@ export class CopilotClient {
systemMessage: wireSystemMessage,
availableTools: config.availableTools,
excludedTools: config.excludedTools,
enableSessionTelemetry: config.enableSessionTelemetry,
tools: config.tools?.map((tool) => ({
name: tool.name,
description: tool.description,
Expand Down
Loading
Loading