Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
Expand All @@ -29,6 +30,7 @@ public sealed class GitHubCopilotAgent : AIAgent, IAsyncDisposable
private readonly string _description;
private readonly SessionConfig? _sessionConfig;
private readonly bool _ownsClient;
private readonly JsonSerializerOptions _jsonSerializerOptions;

/// <summary>
/// Initializes a new instance of the <see cref="GitHubCopilotAgent"/> class.
Expand All @@ -39,13 +41,15 @@ public sealed class GitHubCopilotAgent : AIAgent, IAsyncDisposable
/// <param name="id">The unique identifier for the agent.</param>
/// <param name="name">The name of the agent.</param>
/// <param name="description">The description of the agent.</param>
/// <param name="jsonSerializerOptions">Optional JSON serializer options. Defaults to <see cref="GitHubCopilotJsonUtilities.DefaultOptions"/>.</param>
public GitHubCopilotAgent(
CopilotClient copilotClient,
SessionConfig? sessionConfig = null,
bool ownsClient = false,
string? id = null,
string? name = null,
string? description = null)
string? description = null,
JsonSerializerOptions? jsonSerializerOptions = null)
{
_ = Throw.IfNull(copilotClient);

Expand All @@ -55,6 +59,7 @@ public GitHubCopilotAgent(
this._id = id;
this._name = name ?? DefaultName;
this._description = description ?? DefaultDescription;
this._jsonSerializerOptions = jsonSerializerOptions ?? GitHubCopilotJsonUtilities.DefaultOptions;
}

/// <summary>
Expand All @@ -67,21 +72,24 @@ public GitHubCopilotAgent(
/// <param name="description">The description of the agent.</param>
/// <param name="tools">The tools to make available to the agent.</param>
/// <param name="instructions">Optional instructions to append as a system message.</param>
/// <param name="jsonSerializerOptions">Optional JSON serializer options. Defaults to <see cref="GitHubCopilotJsonUtilities.DefaultOptions"/>.</param>
public GitHubCopilotAgent(
CopilotClient copilotClient,
bool ownsClient = false,
string? id = null,
string? name = null,
string? description = null,
IList<AITool>? tools = null,
string? instructions = null)
string? instructions = null,
JsonSerializerOptions? jsonSerializerOptions = null)
: this(
copilotClient,
GetSessionConfig(tools, instructions),
ownsClient,
id,
name,
description)
description,
jsonSerializerOptions)
{
}

Expand Down Expand Up @@ -181,6 +189,14 @@ protected override async IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingA
channel.Writer.TryWrite(this.ConvertToAgentResponseUpdate(assistantMessage));
break;

case ToolExecutionStartEvent toolStart:
channel.Writer.TryWrite(this.ConvertToAgentResponseUpdate(toolStart));
break;

case ToolExecutionCompleteEvent toolComplete:
channel.Writer.TryWrite(this.ConvertToAgentResponseUpdate(toolComplete));
break;
Comment thread
giles17 marked this conversation as resolved.

case AssistantUsageEvent usageEvent:
channel.Writer.TryWrite(this.ConvertToAgentResponseUpdate(usageEvent));
break;
Expand Down Expand Up @@ -341,6 +357,79 @@ internal AgentResponseUpdate ConvertToAgentResponseUpdate(AssistantMessageEvent
};
}

internal AgentResponseUpdate ConvertToAgentResponseUpdate(ToolExecutionStartEvent toolStart)
{
IDictionary<string, object?>? arguments = this.ParseArguments(toolStart.Data?.Arguments);

FunctionCallContent content = new(
toolStart.Data?.ToolCallId ?? string.Empty,
toolStart.Data?.ToolName ?? string.Empty,
arguments)
{
RawRepresentation = toolStart
};

return new AgentResponseUpdate(ChatRole.Assistant, [content])
{
AgentId = this.Id,
CreatedAt = toolStart.Timestamp
};
}

internal AgentResponseUpdate ConvertToAgentResponseUpdate(ToolExecutionCompleteEvent toolComplete)
{
object? result = toolComplete.Data?.Success == true
? toolComplete.Data?.Result?.Content
: toolComplete.Data?.Error?.Message ?? "Tool execution failed";

FunctionResultContent content = new(
toolComplete.Data?.ToolCallId ?? string.Empty,
result)
{
RawRepresentation = toolComplete
};

return new AgentResponseUpdate(ChatRole.Tool, [content])
{
AgentId = this.Id,
CreatedAt = toolComplete.Timestamp
};
}

private IDictionary<string, object?>? ParseArguments(object? arguments)
{
if (arguments is null)
{
return null;
}

if (arguments is JsonElement jsonElement)
{
if (jsonElement.ValueKind == JsonValueKind.Null || jsonElement.ValueKind == JsonValueKind.Undefined)
{
return null;
}

var typeInfo = (JsonTypeInfo<Dictionary<string, object?>>)this._jsonSerializerOptions.GetTypeInfo(typeof(Dictionary<string, object?>));

try
{
return JsonSerializer.Deserialize(jsonElement.GetRawText(), typeInfo);
}
catch (JsonException)
{
return new Dictionary<string, object?> { ["value"] = jsonElement.ToString() };
}
}

if (arguments is IDictionary<string, object?> dict)
{
return dict;
}

return new Dictionary<string, object?> { ["value"] = arguments.ToString() };
}

private AgentResponseUpdate ConvertToAgentResponseUpdate(AssistantUsageEvent usageEvent)
{
UsageDetails usageDetails = new()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Encodings.Web;
using System.Text.Json;
Expand Down Expand Up @@ -43,6 +44,7 @@ private static JsonSerializerOptions CreateDefaultOptions()
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NumberHandling = JsonNumberHandling.AllowReadingFromString)]
[JsonSerializable(typeof(GitHubCopilotAgentSession))]
[JsonSerializable(typeof(Dictionary<string, object?>))]
[ExcludeFromCodeCoverage]
private sealed partial class JsonContext : JsonSerializerContext;
}
Loading
Loading