Skip to content

Releases: Andes-Software-Solutions/Andes.Extensions.AI

v0.9.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 03 Sep 04:15
9bd8d21

What's Changed

  • Update package versions and dependencies to latest stable by @RorroRojas3 in #17

Full Changelog: v0.8.0...v0.9.0

v0.8.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 20 Aug 05:38
06e9aba

What's Changed

  • Add application-supplied Metadata to the UI contract (0.8.0) by @RorroRojas3 in #15

Full Changelog: v0.7.0...v0.8.0

v0.7.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 18 Aug 21:16
c407205

What's Changed

  • Bump version to 0.7.0 and update UI contract for MCP tool by @RorroRojas3 in #13

Full Changelog: v0.6.0...v0.7.0

v0.6.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 18 Aug 04:10
db0bb8c

What's Changed

  • Add ToolCallUsage.Iteration for per-tool prompt-cost attribution; bump to 0.6.0 by @RorroRojas3 in #11

The usage report learns which model turn issued each tool call: ToolCallUsage.Iteration (#10) correlates the ToolCalls tree with the per-turn Turns breakdown, closing the gap that made exact per-tool prompt-cost attribution impossible — the cost of a tool's arguments and result is billed in the next iteration's prompt, and until now nothing said which calls sat between two turns. Dependency floors move to Microsoft.Extensions.AI 10.9.0 and ModelContextProtocol.Core 2.2.0.

Added

  • ToolCallUsage.Iteration (Andes.Extensions.AI/Usage/ToolCallUsage.cs, #10): the zero-based model iteration of the function-invocation loop that issued the call, corresponding to AssistantTurnUsage.Iteration. When streaming, the value is stamped the moment the tool's scope opens, so it always names the issuing turn — including when one turn issues several calls, which timing alone could never disambiguate (with the default serial invocation, N calls from one turn are indistinguishable from N single-call turns). Nested calls (the Children of another call — an agent's own tools, or a nested agent/MCP child card) report the iteration of the outer request's model turn that issued the enclosing root call. On the non-streaming path the value is always 0, consistent with ChatUsageReport.Turns being populated only when streaming.
    • Why (from the issue): per-tool prompt-cost attribution. A tool — an MCP tool especially — consumes no tokens directly, but its arguments and result enter the next iteration's prompt and are billed there. With the per-turn breakdown that cost is recoverable exactly, from provider-reported integers rather than a tokenizer estimate — input(N+1) − input(N) − output(N) — and Iteration is the missing piece that tells you which calls sit between turn N and turn N+1. The library reports the facts; the delta arithmetic stays with the consumer (reasoning tokens bill as output but are usually not replayed into the next prompt, and cached input bills at a discount, so the subtraction is an attribution model, not an invoice).
    • The property is required with an init setter. Impact is compile-time only, and only for code constructing ToolCallUsage directly via an object initializer — the library's sole construction site is the internal RequestTracker, and code that reads reports is unaffected.

Changed

  • Dependency pins (Directory.Packages.props) — the consumer-visible floors: Microsoft.Extensions.AI (the core package's dependency) and Microsoft.Extensions.AI.Abstractions (the UI package's dependency) 10.8.3 → 10.9.0, and ModelContextProtocol.Core (the MCP satellite's dependency) 2.1.0 → 2.2.0. The Agent satellite's floor is unchanged (Microsoft.Agents.AI stays 1.17.0). OpenAI deliberately stays 2.12.0: Microsoft.Extensions.AI.OpenAI 10.9.0 constrains it to >= 2.12.0 && < 2.13.0. Test- and sample-only bumps ride along, none of them shipped to NuGet: Microsoft.Extensions.AI.OpenAI 10.8.3 → 10.9.0, ModelContextProtocol (the full package) 2.1.0 → 2.2.0, Microsoft.Extensions.Configuration.Binder/.Json and Microsoft.Extensions.Hosting 10.0.10 → 10.0.11, Microsoft.NET.Test.Sdk 18.8.1 → 18.9.0, and xunit.runner.visualstudio 3.1.5 → 4.0.0.
  • Docs updated for the new member: Getting started adds Iteration to the usage-report member notes; Architecture adds it to the report shape and gains a correlation paragraph under Usage attribution explaining the delta formula and its caveats; MCP tool tracking and Agent tool tracking note the nested-child semantics where the child ToolCallUsage is discussed; and the satellite prerequisites reflect the new floors.
  • All four packages version in lockstep at 0.6.0; the satellites depend on core >= 0.6.0.

Full Changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 06 Aug 05:33
616fc51

0.5.0

Tag: v0.5.0 · Date: 2026-08-06

The middleware stops guessing: the auto-emitted "Starting request"/"Thinking..." statuses are gone, replaced by a detection-driven Reasoning/ReasoningCompleted status pair that fires only when the model actually streams reasoning content — opened the moment reasoning is detected, closed (with the elapsed reasoning time) the moment the answer or the next tool call starts — plus a public Custom status factory so applications emit their own request-level statuses — in the exact synthetic shape the middleware uses. The UI package gains a reasoning-text surface (ReasoningDelta events folding into AssistantStatusSnapshot.ReasoningText), and a new sample runs the whole pipeline over the Azure OpenAI Responses API with stable packages only.

Breaking changes

  • ChatProgressKind.Thinking is renamed to ChatProgressKind.Reasoning (Andes.Extensions.AI/Progress/ChatProgressKind.cs; the underlying value 1 is preserved). Consumers switching on the enum rename ThinkingReasoning; persisted numeric values are unaffected.
  • ChatProgressKind.RequestStarted is renamed to ChatProgressKind.Custom (same file; the underlying value 0 is preserved): a developer-constructed status carrying any application-supplied message, never emitted by the middleware. Its factory is ChatProgressUpdate.CreateCustom(string message) — the message is required (ArgumentException.ThrowIfNullOrEmpty: ArgumentNullException on null, ArgumentException on empty), replacing the interim CreateRequestStarted(string? message = null) from earlier drafts of this release. The interim CreateReasoning(...) factory is removed without replacement: Reasoning is strictly detection-driven (model-only), so applications can never emit it via a factory.
  • The middleware no longer auto-emits request-level statuses. Previous versions opened every request (both call styles) with a "Starting request" status and a Thinking ("Thinking...") status, and re-emitted "Thinking..." after each tool round-trip. Those emissions are removed — RequestTracker.EmitRequestStarted/EmitThinking are deleted, and AdvanceIteration now only advances the turn counter and re-arms reasoning detection — so the first in-band event of a tool-calling request is now the ToolInvoking header.
    • Migration: UIs that relied on the automatic opening status prepend their own — yield return ChatProgressUpdate.CreateCustom("Starting request").ToResponseUpdate(); ahead of streaming the tracked response (see Added below) — or handle the absence (the UI package's AssistantStatusSnapshot.AssistantStatus now stays null until the first request-level event arrives).

Added

  • Detection-driven Reasoning status. ToolTrackingChatClient.Inspect watches the stream for Microsoft.Extensions.AI.TextReasoningContent and calls the new RequestTracker.OnReasoningDetected(), which emits one Reasoning event per model turn (message "Reasoning...", root scope, depth 0), re-armed after each tool round-trip. Updates are inspected before they are forwarded, so the status enters the channel ahead of the update carrying the reasoning content. Detection is content-based and therefore provider-agnostic: the OpenAI Responses API produces TextReasoningContent today, while plain Chat Completions never streams reasoning — chat pipelines simply never see the status. Non-streaming GetResponseAsync mirrors this post-hoc: if any response message contains TextReasoningContent, at most one Reasoning event is raised (observers only — turns are indistinguishable in an aggregated response). The event never carries the reasoning text itself (privacy invariant unchanged), and with no public factory for the kind, it only ever originates from this detection.
  • ChatProgressKind.ReasoningCompleted closes each detected reasoning turn. New enum member (ReasoningCompleted = 8, Andes.Extensions.AI/Progress/ChatProgressKind.cs), raised at most once per model turn by a RequestTracker.OnReasoningCompleted() latch — re-armed alongside detection by AdvanceIteration() after each tool round-trip — when the first answer text (non-empty TextContent) or FunctionCallContent follows detected reasoning, or when the stream ends on a reasoning-only final turn. The function-call hook fires before OnFunctionCall, so the close precedes any ToolInvoking header; the stream-end close happens in PumpAsync before the channel completes, so the event stays in-band ahead of the trailing RequestCompleted. Message "Reasoning completed", root scope, depth 0. ChatProgressUpdate.Duration carries the elapsed reasoning time — first detection to the first completion trigger — when streaming; the non-streaming post-hoc mirror passes measured: false, so Duration stays null there while observers now receive a balanced Reasoning + ReasoningCompleted pair per request. Like Reasoning, the kind has no public factory and never carries reasoning text (privacy invariant unchanged), and the failure path is untouched — a request that faults after detection raises RequestFailed with no reasoning completion. The UI package needed zero code changes: MapKind collapses the new kind to AssistantUiEventKind.Status (status line "Reasoning completed") and ToUiEvent already maps DurationDurationSeconds generically, so UIs receive the reasoning duration on that Status event — the shipped TypeScript contract is untouched (ChatProgressKind never crosses the wire). Visible in the Responses demo: the header now flips from "Reasoning..." to "Reasoning completed" the moment the answer (or the next tool call) starts, instead of "Reasoning..." lingering until the next event.
  • Developer-owned request statuses. The public static factory ChatProgressUpdate.CreateCustom(string message) constructs a request-level Custom update carrying any application-supplied message, stamped with the new public constant ChatProgressUpdate.ExternalScopeId ("scope-external" — never collides with the middleware's per-request scope identifiers), depth 0, and the current UTC time. The new extension ChatProgressUpdateExtensions.ToResponseUpdate() (Andes.Extensions.AI/Progress/ChatProgressUpdateExtensions.cs) wraps an update into a role-less ChatResponseUpdate carrying a single ChatProgressContent — the exact synthetic shape the middleware emits — so apps can prepend or interleave their own statuses into the stream a UI consumes (for example, ahead of ToStatusSnapshotsAsync()). Both sample apps demonstrate the prepend pattern with CreateCustom("Starting request") in their StreamTurn local function.
  • Andes.Extensions.AI.UI: the model's reasoning summary text now propagates through the UI contract. New AssistantUiEventKind.ReasoningDelta (between TextDelta and Finished): ChatResponseUiExtensions.ToUiEventsAsync emits one per in-band TextReasoningContent with non-empty text — encrypted-only reasoning items (empty text) carry nothing renderable and are skipped — with the chunk in AssistantUiEvent.Text. AssistantStatusReducer accumulates the deltas into the new AssistantStatusSnapshot.ReasoningText: verbatim concatenation across the whole request, including tool round-trips, with no synthetic separators. The shipped TypeScript mirror (typescript/andes-assistant-ui.ts) gains the "ReasoningDelta" union member, reasoningText?: string, and the matching foldAssistantEvents case. The privacy boundary holds: reasoning text is sourced only from in-band model content the stream already carries — core progress events remain text-free.
  • New sample: samples/Andes.Extensions.AI.Demo.Responses. A console chat over the Azure OpenAI Responses API with stable packages only: the plain OpenAIClient (stable OpenAI 2.12.0) targets the OpenAI-v1-compatible endpoint ({endpoint}/openai/v1) — the stable Azure.AI.OpenAI 2.1.0 has no Responses surface, which is why the plain-client route is used — and GetResponsesClient().AsIChatClient(deployment) adapts it to the tracked pipeline. ChatOptions.Reasoning = new ReasoningOptions { Output = ReasoningOutput.Full } makes reasoning summaries stream back as TextReasoningContent, lighting up the live Reasoning status (see Fixed for why Summary does not work on gpt-5-series deployments), and the demo's StatusRenderer shows the accumulating AssistantStatusSnapshot.ReasoningText in a dimmed "reasoning" panel — the last six lines while the Live frame streams, and the full text in the persistent final frame (and on failures), with the total reasoning time in the panel header summed from the recorded ReasoningCompleted statuses' Duration. Requires a reasoning-capable deployment (gpt-5 family / o-series); builds with NoWarn OPENAI001 because the Responses surface is still [Experimental] in OpenAI 2.12.0. Registered in Andes.Extensions.slnx; IsPackable=false like the existing sample — it never ships to NuGet.
  • New optional integration setting AzureOpenAI:ResponsesDeployment, gating the new [SkippableFact] suite tests/Andes.Extensions.AI.Integration.Test/ResponsesStreamingIntegrationTests.cs: end to end against the Responses API, it asserts that no Custom status appears (the middleware never emits one), that exactly one "Reasoning..." status is raised for a single-turn request, that the status precedes the first reasoning content, and that a single ReasoningCompleted with a non-null Duration follows it — pair ordering rather than fixed positions, since real turn structure varies by deployment. When the setting is absent those tests skip cleanly while the chat-deployment tests still run.
  • Root README badges — NuGet version badges for all four packages, the NuGet Publish workflow status, the MIT license, and .NET 10.

Changed

  • Dependency pins (`Director...
Read more

v0.4.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 31 Jul 19:41
3b8ddb1

What's Changed

  • Bump package versions to 0.4.0 and update release notes by @RorroRojas3 in #8
  • Andes.Extensions.AI.Mcp now requires ModelContextProtocol.Core >= 2.0.0 (was >= 1.4.1) — a major release of the MCP C# SDK, published 2026-07-28 and aligned with the MCP 2026-07-28 specification (see the SDK release notes). MCP 2.0 carries its own breaking changes and deprecations for consumers (stateless-by-default HTTP; Roots, Sampling, and Logging obsoleted), which is why this is a minor bump (0.3.1 → 0.4.0) rather than a patch despite no code changes in this repository.
    • The Andes.Extensions.AI.Mcp source itself compiled against MCP 2.0 with zero warnings (warnings are errors) and required no migration — it uses none of the APIs MCP 2.0 deprecates (Roots/Sampling/Logging).
  • Core now floors Microsoft.Extensions.AI >= 10.8.3 and Andes.Extensions.AI.UI floors Microsoft.Extensions.AI.Abstractions >= 10.8.3 (both were >= 10.8.1).
  • Andes.Extensions.AI.Agent now floors Microsoft.Agents.AI >= 1.16.0 (was >= 1.15.0).
  • The remaining pin updates — ModelContextProtocol 1.4.1 → 2.0.0 and Microsoft.Extensions.AI.OpenAI 10.8.1 → 10.8.3 — are consumed only by the tests, the test MCP server, and the demo sample, none of which ship to NuGet.
  • All four packages version in lockstep at 0.4.0; the satellites depend on core >= 0.4.0.

Full Changelog: v0.3.1...v0.4.0

v0.3.1

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 29 Jul 23:49
1995247

What's Changed

  • Bump version to 0.3.1 and update repository links by @RorroRojas3 in #7

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 29 Jul 05:27
2ab7f3f

What's Changed

  • Add Andes.Extensions.AI.UI status contract and de-dup progress headers by @RorroRojas3 in #6

Full Changelog: v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@RorroRojas3 RorroRojas3 released this 25 Jul 06:17
93240b3

What's Changed

  • Enhance MCP progress reporting, handling, and documentation by @RorroRojas3 in #1
  • Add integration and unit tests for MCP tool tracking and classification by @RorroRojas3 in #2
  • Add Andes.Extensions.AI.Agent package and enhance documentation by @RorroRojas3 in #3
  • Enhance GitHub Actions with efficiency and security skills by @RorroRojas3 in #4
  • Update CODEOWNERS and nuget.yml for policy clarity by @RorroRojas3 in #5

New Contributors

Full Changelog: https://github.com/Andes-Software-Solutions/Andes.Extensions.AI/commits/v0.2.0