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 API and observability behavior in the AI metrics SDK; the main behavioral change is clearer TrackMetricsOf error/duration semantics, which aligns with other language SDKs rather than changing security or data paths.
Overview
Brings the .NET server AI tracker in line with other SDKs by extending
AiMetricswith optionalToolCallsandDurationMs, andMetricSummarywithToolCallsandResumptionToken.TrackMetricsOfnow stops the timer before running the metrics extractor (so slow extractors do not inflate duration), usesDurationMswhen provided, auto-emits tool-call events fromAiMetrics.ToolCalls, and adjusts failure semantics: operation failures still record duration + generation error; extractor failures record duration only (no error), matching Java.TrackToolCallappends keys to a lock-protected list soSummary.ToolCallsreflects all invocations; existing per-call$ld:ai:tool_callevents are unchanged. Changes are additive for existing call sites; tests cover the new fields and behaviors.Reviewed by Cursor Bugbot for commit b2c7bc2. Bugbot is set up for automated code reviews on this repo. Configure here.