feat: extend AiMetrics, MetricSummary, and TrackMetricsOf#300
Conversation
…alls, duration override, and resumption token
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b2c7bc2. Configure here.
| IReadOnlyList<string> toolCalls; | ||
| lock (_toolCallKeys) | ||
| { | ||
| toolCalls = _toolCallKeys.Count > 0 ? _toolCallKeys.AsReadOnly() : null; |
There was a problem hiding this comment.
Summary ToolCalls live list alias
Medium Severity
Summary assigns ToolCalls from _toolCallKeys.AsReadOnly(), so the returned MetricSummary keeps a live view of the tracker’s internal list. Later TrackToolCall / TrackMetricsOf updates change a previously read summary’s tool list, and concurrent reads while tracking can throw during enumeration.
Triggered by learned rule: Tracker methods must defensive-copy caller-provided collections
Reviewed by Cursor Bugbot for commit b2c7bc2. Configure here.


Summary
Extends
AiMetrics,MetricSummary, andTrackMetricsOfto bring the .NET AI SDK to spec parity with JS, Python, and Java for metric tracking. Addresses AIC-2727.AiMetrics— new optional fieldsToolCallscarries tool keys invoked during the operation (AIRUNNER §1.5.1).DurationMsprovides an explicit duration override — when set,TrackMetricsOfuses it instead of the stopwatch measurement (AITRACK §1.1.13.2).MetricSummary— new optional fieldsToolCallsaccumulates keys fromTrackToolCallinvocations.ResumptionTokensurfaces the tracker's resumption token on the summary (AITRACK §1.1.17.2).TrackMetricsOf— tool call auto-tracking & duration overrideTrackMetricsOfnow extractsToolCallsfromAiMetricsand callsTrackToolCallsautomatically. It also honorsDurationMswhen present, falling back to the stopwatch value when null.The error-handling semantics now match Java: if the operation throws, duration + error are tracked and the exception propagates. If the metrics extractor throws, duration is tracked but error is NOT — the AI operation itself succeeded.
TrackToolCall— accumulates keys on summaryTrackToolCallnow appends to an internal list (lock-guarded) so thatSummary.ToolCallsreflects all tool invocations. The existing per-call$ld:ai:tool_callevent emission is unchanged.How to test
dotnet test pkgs/sdk/server-ai/test/LaunchDarkly.ServerSdk.Ai.Tests.csproj --framework net8.09 new test cases covering backward compat, new field population, auto tool call tracking, duration override vs. stopwatch fallback, extractor failure semantics, and summary accumulation.
Known limitations
None. All changes are additive — existing constructors and call sites compile and behave identically.
Note
Low Risk
Additive SDK telemetry API changes with preserved backward compatibility; behavior shifts only for TrackMetricsOf when the metrics extractor throws (no longer records generation error).
Overview
Brings the .NET server AI tracker in line with JS/Python/Java by extending
AiMetricsandMetricSummary, and tighteningTrackMetricsOfbehavior.AiMetricsgains optionalToolCallsandDurationMs(existing two-arg constructor stays valid).TrackMetricsOfnow emits tool-call events fromToolCalls, usesDurationMswhen set (otherwise stopwatch time captured before the extractor runs), and splits failures: operation exceptions record duration + error; extractor exceptions record duration only and rethrow.MetricSummaryaddsToolCalls(accumulated fromTrackToolCall, lock-protected) andResumptionToken.TrackToolCallappends each key to that list while keeping per-call$ld:ai:tool_calltracking unchanged.Nine new unit tests cover backward compatibility, overrides, extractor semantics, and summary fields.
Reviewed by Cursor Bugbot for commit 1195a2c. Bugbot is set up for automated code reviews on this repo. Configure here.