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
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,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 on lines +184 to +190

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

private AgentResponseUpdate ConvertToAgentResponseUpdate(ToolExecutionStartEvent toolStart)
{
Dictionary<string, object?>? arguments = ParseToolArguments(toolStart.Data?.Arguments as string);

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

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

private AgentResponseUpdate ConvertToAgentResponseUpdate(ToolExecutionCompleteEvent toolComplete)
{
string? result = toolComplete.Data?.Success == true
? toolComplete.Data?.Result?.Content
: toolComplete.Data?.Error?.Message;

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

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

private AgentResponseUpdate ConvertToAgentResponseUpdate(AssistantUsageEvent usageEvent)
{
UsageDetails usageDetails = new()
Expand Down Expand Up @@ -415,6 +458,45 @@ private AgentResponseUpdate ConvertToAgentResponseUpdate(AssistantUsageEvent usa
return additionalCounts;
}

private static Dictionary<string, object?>? ParseToolArguments(string? argumentsJson)
{
if (string.IsNullOrEmpty(argumentsJson))
{
return null;
}

try
{
using var doc = JsonDocument.Parse(argumentsJson);
if (doc.RootElement.ValueKind != JsonValueKind.Object)
{
return new Dictionary<string, object?> { ["_raw"] = argumentsJson };
}

var result = new Dictionary<string, object?>();
foreach (var property in doc.RootElement.EnumerateObject())
{
result[property.Name] = property.Value.ValueKind switch
{
JsonValueKind.String => property.Value.GetString(),
JsonValueKind.Number => property.Value.GetRawText() is string raw && double.TryParse(raw, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double d) ? d : (object)property.Value.GetRawText(),
JsonValueKind.True => true,
JsonValueKind.False => false,
JsonValueKind.Null => null,
_ => property.Value.GetRawText()
};
}

return result;
}
catch (Exception)
{
// Gracefully fall back for any parsing failure (malformed JSON, non-object root,
// unexpected element types, etc.) to avoid breaking the streaming pipeline.
return new Dictionary<string, object?> { ["_raw"] = argumentsJson };
}
Comment on lines +468 to +497
}

private AgentResponseUpdate ConvertToAgentResponseUpdate(SessionEvent sessionEvent)
{
// Handle arbitrary events by storing as RawRepresentation
Expand Down
Loading
Loading