diff --git a/Directory.Packages.props b/Directory.Packages.props index 3b0738f..7f3a6eb 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,6 +1,6 @@ - + diff --git a/src/Squad.SDK.NET/SquadClient.cs b/src/Squad.SDK.NET/SquadClient.cs index 7812f5e..f278fe9 100644 --- a/src/Squad.SDK.NET/SquadClient.cs +++ b/src/Squad.SDK.NET/SquadClient.cs @@ -1,8 +1,7 @@ -using GitHub.Copilot.SDK; +using GitHub.Copilot; using Microsoft.Extensions.Logging; using Squad.SDK.NET.Abstractions; using Squad.SDK.NET.Events; -using SdkConnectionState = GitHub.Copilot.SDK.ConnectionState; namespace Squad.SDK.NET; @@ -34,7 +33,9 @@ public Abstractions.ConnectionState State { get { - var state = MapConnectionState(_copilotClient.State); + var state = _isStarted + ? Abstractions.ConnectionState.Connected + : Abstractions.ConnectionState.Disconnected; _logger.LogDebug("Client state: {State}", state); return state; } @@ -145,11 +146,11 @@ public async Task> ListModelsAsync( /// public IDisposable On(Action handler) { - return _copilotClient.On(evt => + return _copilotClient.OnLifecycle(evt => { handler(new SquadEvent { - Type = MapLifecycleEventType(evt.Type), + Type = MapLifecycleEventType(evt), SessionId = evt.SessionId, Timestamp = DateTimeOffset.UtcNow }); @@ -163,20 +164,11 @@ public async ValueTask DisposeAsync() await _copilotClient.DisposeAsync(); } - private static Abstractions.ConnectionState MapConnectionState(SdkConnectionState state) => state switch + private static SquadEventType MapLifecycleEventType(SessionLifecycleEvent evt) => evt switch { - SdkConnectionState.Disconnected => Abstractions.ConnectionState.Disconnected, - SdkConnectionState.Connecting => Abstractions.ConnectionState.Connecting, - SdkConnectionState.Connected => Abstractions.ConnectionState.Connected, - SdkConnectionState.Error => Abstractions.ConnectionState.Error, - _ => Abstractions.ConnectionState.Disconnected - }; - - private static SquadEventType MapLifecycleEventType(string? type) => type switch - { - SessionLifecycleEventTypes.Created => SquadEventType.SessionCreated, - SessionLifecycleEventTypes.Deleted => SquadEventType.SessionDestroyed, - _ => SquadEventType.SessionCreated + SessionCreatedEvent => SquadEventType.SessionCreated, + SessionDeletedEvent => SquadEventType.SessionDestroyed, + _ => SquadEventType.SessionCreated }; private static SessionConfig MapSessionConfig(SquadSessionConfig? config) diff --git a/src/Squad.SDK.NET/SquadSession.cs b/src/Squad.SDK.NET/SquadSession.cs index e72ea50..b4938ff 100644 --- a/src/Squad.SDK.NET/SquadSession.cs +++ b/src/Squad.SDK.NET/SquadSession.cs @@ -1,7 +1,8 @@ -using GitHub.Copilot.SDK; +using GitHub.Copilot; using Microsoft.Extensions.Logging; using Squad.SDK.NET.Abstractions; using Squad.SDK.NET.Events; +using System.Text.Json; namespace Squad.SDK.NET; @@ -57,14 +58,14 @@ public Task AbortAsync(CancellationToken cancellationToken = default) /// public async Task> GetMessagesAsync(CancellationToken cancellationToken = default) { - var events = await _session.GetMessagesAsync(cancellationToken); + var events = await _session.GetEventsAsync(cancellationToken); return events.Select(MapSessionEvent).ToList(); } /// public IDisposable On(Action handler) { - return _session.On(evt => handler(MapSessionEvent(evt))); + return _session.On(evt => handler(MapSessionEvent(evt))); } /// @@ -135,7 +136,7 @@ e.Data is not null Model = e.Data.Model ?? string.Empty, InputTokens = (int)(e.Data.InputTokens ?? 0), OutputTokens = (int)(e.Data.OutputTokens ?? 0), - EstimatedCost = (decimal)(e.Data.Cost ?? 0) + EstimatedCost = 0m } : null), @@ -187,7 +188,7 @@ private ToolCallPayload MapToolStart(ToolExecutionStartData data) return new ToolCallPayload { ToolName = data.ToolName ?? string.Empty, - Arguments = data.Arguments as IReadOnlyDictionary, + Arguments = MapArguments(data.Arguments), Status = ToolCallStatus.Running }; } @@ -205,4 +206,38 @@ private ToolCallPayload MapToolComplete(ToolExecutionCompleteData data) Status = data.Error is null ? ToolCallStatus.Completed : ToolCallStatus.Error }; } + + private static IReadOnlyDictionary? MapArguments(JsonElement? arguments) + { + if (arguments is not { ValueKind: JsonValueKind.Object } json) + { + return null; + } + + var result = new Dictionary(); + foreach (var property in json.EnumerateObject()) + { + result[property.Name] = MapJsonValue(property.Value); + } + + return result; + } + + private static object? MapJsonValue(JsonElement value) => value.ValueKind switch + { + JsonValueKind.String => value.GetString(), + JsonValueKind.Number => value.TryGetInt64(out var longValue) + ? longValue + : value.TryGetDouble(out var doubleValue) + ? doubleValue + : value.GetRawText(), + JsonValueKind.True => true, + JsonValueKind.False => false, + JsonValueKind.Null => null, + JsonValueKind.Object => value.EnumerateObject().ToDictionary( + property => property.Name, + property => MapJsonValue(property.Value)), + JsonValueKind.Array => value.EnumerateArray().Select(MapJsonValue).ToList(), + _ => value.GetRawText() + }; }