Skip to content
Draft
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
42 changes: 34 additions & 8 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Extensions.Logging.Abstractions;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
Expand Down Expand Up @@ -1033,7 +1034,8 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig config, Cance
Providers: config.Providers,
Models: config.Models,
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence,
ExpAssignments: config.ExpAssignments);
ExpAssignments: config.ExpAssignments,
EnableGitHubTelemetryRedirection: _options.OnGitHubTelemetry != null ? true : null);

var rpcTimestamp = Stopwatch.GetTimestamp();

Expand Down Expand Up @@ -1235,7 +1237,8 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
Providers: config.Providers,
Models: config.Models,
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence,
ExpAssignments: config.ExpAssignments);
ExpAssignments: config.ExpAssignments,
EnableGitHubTelemetryRedirection: _options.OnGitHubTelemetry != null ? true : null);

var rpcTimestamp = Stopwatch.GetTimestamp();
var response = await InvokeRpcAsync<ResumeSessionResponse>(
Expand Down Expand Up @@ -1708,21 +1711,24 @@ await Rpc.SessionFs.SetProviderAsync(
}

/// <summary>
/// Builds the client-global RPC handler bag at construction time. Currently
/// only the LLM inference provider adapter is registered; returns null when no
/// Builds the client-global RPC handler bag at construction time. Registers
/// the LLM inference provider adapter and/or the GitHub telemetry adapter
/// depending on which options are configured; returns null when no
/// client-global API is configured so the registration is skipped entirely.
/// </summary>
private ClientGlobalApiHandlers? BuildClientGlobalApis()
{
var handler = _options.RequestHandler;
if (handler is null)
var onGitHubTelemetry = _options.OnGitHubTelemetry;
if (handler is null && onGitHubTelemetry is null)
{
return null;
}

return new ClientGlobalApiHandlers
{
LlmInference = new LlmInferenceAdapter(handler, () => _serverRpc),
LlmInference = handler is null ? null : new LlmInferenceAdapter(handler, () => _serverRpc),
GitHubTelemetry = onGitHubTelemetry is null ? null : new GitHubTelemetryAdapter(onGitHubTelemetry),
};
}

Expand Down Expand Up @@ -2476,7 +2482,8 @@ internal record CreateSessionRequest(
IList<NamedProviderConfig>? Providers = null,
IList<ProviderModelConfig>? Models = null,
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null,
[property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null);
[property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null,
bool? EnableGitHubTelemetryRedirection = null);
#pragma warning restore GHCP001

internal record ToolDefinition(
Expand Down Expand Up @@ -2572,7 +2579,8 @@ internal record ResumeSessionRequest(
IList<NamedProviderConfig>? Providers = null,
IList<ProviderModelConfig>? Models = null,
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null,
[property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null);
[property: JsonPropertyName("expAssignments")] JsonElement? ExpAssignments = null,
bool? EnableGitHubTelemetryRedirection = null);
#pragma warning restore GHCP001

internal record ResumeSessionResponse(
Expand Down Expand Up @@ -2690,3 +2698,21 @@ public sealed class ToolResultAIContent(ToolResultObject toolResult) : AIContent
/// </summary>
public ToolResultObject Result => toolResult;
}

/// <summary>
/// Bridges the generated <see cref="Rpc.IGitHubTelemetryHandler"/> client-global handler to
/// the public <c>OnGitHubTelemetry</c> callback, forwarding the generated
/// <see cref="Rpc.GitHubTelemetryNotification"/> payload unchanged.
/// </summary>
[Experimental(Diagnostics.Experimental)]
internal sealed class GitHubTelemetryAdapter(Action<Rpc.GitHubTelemetryNotification> callback) : Rpc.IGitHubTelemetryHandler
{
private readonly Action<Rpc.GitHubTelemetryNotification> _callback = callback ?? throw new ArgumentNullException(nameof(callback));

public Task EventAsync(Rpc.GitHubTelemetryNotification request, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(request);
_callback(request);
return Task.CompletedTask;
}
}
128 changes: 128 additions & 0 deletions dotnet/src/Generated/Rpc.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions dotnet/src/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ private CopilotClientOptions(CopilotClientOptions? other)
OnListModels = other.OnListModels;
SessionFs = other.SessionFs;
RequestHandler = other.RequestHandler;
OnGitHubTelemetry = other.OnGitHubTelemetry;
SessionIdleTimeoutSeconds = other.SessionIdleTimeoutSeconds;
EnableRemoteSessions = other.EnableRemoteSessions;
Mode = other.Mode;
Expand Down Expand Up @@ -378,6 +379,14 @@ private CopilotClientOptions(CopilotClientOptions? other)
[Experimental(Diagnostics.Experimental)]
public CopilotRequestHandler? RequestHandler { get; set; }

/// <summary>
/// Experimental. Receives GitHub telemetry events the runtime forwards to this
/// connection; setting a handler opts created/resumed sessions into redirection.
/// </summary>
[Experimental(Diagnostics.Experimental)]
[EditorBrowsable(EditorBrowsableState.Never)]
public Action<Rpc.GitHubTelemetryNotification>? OnGitHubTelemetry { get; set; }

/// <summary>
/// OpenTelemetry configuration for the runtime.
/// When set to a non-<see langword="null"/> instance, the runtime is started with OpenTelemetry instrumentation enabled.
Expand Down
Loading
Loading