Skip to content

Add Andes.Extensions.AI.UI status contract and de-dup progress headers - #6

Merged
RorroRojas3 merged 5 commits into
mainfrom
claude/andes-extensions-ai-ui-huyabl
Jul 29, 2026
Merged

Add Andes.Extensions.AI.UI status contract and de-dup progress headers#6
RorroRojas3 merged 5 commits into
mainfrom
claude/andes-extensions-ai-ui-huyabl

Conversation

@RorroRojas3

@RorroRojas3 RorroRojas3 commented Jul 28, 2026

Copy link
Copy Markdown
Member

This pull request adds support for the new Andes.Extensions.AI.UI package across the codebase, introduces per-release documentation requirements, and implements nested tool tracking for agents. It also bumps all package versions to 0.3.0, updates the NuGet publishing workflow to handle four packages, and improves documentation and packaging metadata.

Support for Andes.Extensions.AI.UI and Release Process

  • Added Andes.Extensions.AI.UI as a fourth shipping package throughout documentation and the .github/workflows/nuget.yml workflow, including packaging, validation, and publishing steps. [1] [2] [3] [4] [5]
  • Introduced a releases/ directory for per-release notes and updated project conventions to require a release changelog for every version bump. [1] [2]

Nested Tool Tracking for Agents

  • Implemented nested tool tracking: agent tools invoked within other tools or agents now open their own child tracking scopes, rendering as child activities and attributing usage correctly. This includes changes to AgentTrackingAIFunction and updated XML docs and README. [1] [2] [3] [4]

Version and Packaging Updates

  • Bumped all package versions (Andes.Extensions.AI, .Mcp, .Agent, .UI) to 0.3.0 and added icon.png to the .Agent and .Mcp packages for improved NuGet presentation. [1] [2] [3] [4] [5]

Documentation Improvements

  • Updated project and package documentation to reflect the new package, release process, and nested tracking behavior. [1] [2]

Summary of Most Important Changes

1. Support for Andes.Extensions.AI.UI and Release Process

  • Added Andes.Extensions.AI.UI as a fourth package in all documentation and the NuGet publishing workflow, including validation for four packages and updating related scripts and comments. [1] [2] [3] [4] [5]
  • Introduced a releases/ directory for per-release notes and updated project standards to require a changelog for every version bump. [1] [2]

2. Nested Tool Tracking for Agents

  • Implemented nested tool tracking in AgentTrackingAIFunction, so agent tools invoked within other tools/agents open their own child tracking scopes, with clear usage attribution and activity rendering. [1] [2] [3] [4]

3. Version and Packaging Updates

  • Bumped all package versions to 0.3.0 and added icon.png to .Agent and .Mcp packages for improved NuGet presentation. [1] [2] [3] [4] [5]

4. Documentation Improvements

  • Updated project and package documentation to reflect the new package, release process, and nested tracking behavior. [1] [2]This pull request adds support for the new Andes.Extensions.AI.UI package, updates the project and workflow to handle four shipping packages (instead of three), and introduces nested tool tracking scopes for both Agent and MCP tool invocations. This ensures that when agents or MCP tools are invoked as tools of other agents or tools, their activities and usage are tracked as child activities, improving attribution and reporting. Documentation and versioning are updated to reflect these changes.

Support for Andes.Extensions.AI.UI and Release Process Updates:

  • Added the new Andes.Extensions.AI.UI package to the project, workflow, and documentation, including version lockstep and release notes requirements. (.claude/CLAUDE.md, .github/workflows/nuget.yml) [1] [2] [3] [4] [5] [6] [7] [8]
  • Updated NuGet workflow to pack, validate, and push all four packages (Andes.Extensions.AI, Andes.Extensions.AI.Mcp, Andes.Extensions.AI.Agent, Andes.Extensions.AI.UI). [1] [2] [3]

Nested Tool Tracking Scopes:

  • Agent and MCP tools now open a child tracking scope when invoked as tools of other agents or within tool bodies, ensuring their activities and usage are tracked as nested activities. (Andes.Extensions.AI.Agent/Internal/AgentTrackingAIFunction.cs, Andes.Extensions.AI.Mcp/Internal/McpTrackingAIFunction.cs) [1] [2] [3] [4]
  • Documentation and code comments updated to explain nested scope behavior and its impact on reporting. (Andes.Extensions.AI.Agent/AgentToolTrackingExtensions.cs, Andes.Extensions.AI.Agent/README.md) [1] [2]

Version Bumps:

  • Bumped package versions to 0.3.0 for Andes.Extensions.AI.Agent and Andes.Extensions.AI.Mcp to reflect new features and lockstep versioning. (Andes.Extensions.AI.Agent/Andes.Extensions.AI.Agent.csproj, Andes.Extensions.AI.Mcp/Andes.Extensions.AI.Mcp.csproj) [1] [2]Adds a fourth satellite package, Andes.Extensions.AI.UI, providing a
    serializable, cross-language contract an API streams to a UI to render the
    assistant's live activity hierarchy before its final answer: the assistant's
    own functions, MCP tools, and agents, each with streaming sub-statuses and
    nested children, plus per-activity and total token usage.

  • DTO records (AssistantUiEvent flat delta + AssistantStatusSnapshot folded
    tree, AssistantActivity, SubStatus, UsageSummary) and enums.

  • ChatResponseUiExtensions maps the tracked ChatProgressContent/
    UsageReportContent stream into the contract; AssistantStatusReducer folds
    events into snapshots; AssistantUiJsonContext gives camelCase, string-enum,
    null-omitting JSON.

  • A 1:1 TypeScript file (interfaces + foldAssistantEvents) ships as package
    content so a SPA reconstructs the same tree a Blazor/console client does.

  • Unit tests for the mapper, reducer, and serialization.

Each activity carries a clean DisplayName plus a separate Kind badge instead
of a pre-composed "Calling ... MCP/Agent/Tool" header, so the kind word is
never repeated. Relatedly, the core default header formatter now omits the
kind word when the name already ends with it (case-insensitive), so a server
named "Andes Test MCP" or an agent named "Research Agent" is no longer
doubled. Updated the affected header assertions and added a de-dup theory.

Docs: new docs/ui.md and docs/examples/ui-contract.md (minimal-API, Blazor
WASM, and TypeScript SPA consumers); architecture and README updated.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_019byxhMbTJYVwCtvwWUGZtC

Adds a fourth satellite package, Andes.Extensions.AI.UI, providing a
serializable, cross-language contract an API streams to a UI to render the
assistant's live activity hierarchy before its final answer: the assistant's
own functions, MCP tools, and agents, each with streaming sub-statuses and
nested children, plus per-activity and total token usage.

- DTO records (AssistantUiEvent flat delta + AssistantStatusSnapshot folded
  tree, AssistantActivity, SubStatus, UsageSummary) and enums.
- ChatResponseUiExtensions maps the tracked ChatProgressContent/
  UsageReportContent stream into the contract; AssistantStatusReducer folds
  events into snapshots; AssistantUiJsonContext gives camelCase, string-enum,
  null-omitting JSON.
- A 1:1 TypeScript file (interfaces + foldAssistantEvents) ships as package
  content so a SPA reconstructs the same tree a Blazor/console client does.
- Unit tests for the mapper, reducer, and serialization.

Each activity carries a clean DisplayName plus a separate Kind badge instead
of a pre-composed "Calling ... MCP/Agent/Tool" header, so the kind word is
never repeated. Relatedly, the core default header formatter now omits the
kind word when the name already ends with it (case-insensitive), so a server
named "Andes Test MCP" or an agent named "Research Agent" is no longer
doubled. Updated the affected header assertions and added a de-dup theory.

Docs: new docs/ui.md and docs/examples/ui-contract.md (minimal-API, Blazor
WASM, and TypeScript SPA consumers); architecture and README updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019byxhMbTJYVwCtvwWUGZtC
Copilot AI review requested due to automatic review settings July 28, 2026 00:13
Comment thread tests/Andes.Extensions.AI.UI.Unit.Test/ChatResponseUiExtensionsTests.cs Dismissed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces a new satellite package, Andes.Extensions.AI.UI, that provides a serializable C# + TypeScript contract for streaming an assistant’s live activity hierarchy (tools, MCP servers, agents), including sub-statuses and usage, while also de-duplicating the kind word in the core default progress headers.

Changes:

  • Added Andes.Extensions.AI.UI package (DTOs, JSON source-gen context, mapper/reducer, and shipped TypeScript reducer/types).
  • Updated core default header formatting to avoid repeating kind words (e.g., “MCP MCP”, “Agent Agent”) and updated affected tests/docs.
  • Added documentation and examples for consuming the UI contract via SSE in .NET and TypeScript.

Reviewed changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Andes.Extensions.AI.Unit.Test/ToolClassificationTests.cs Adds theory coverage for header de-dup behavior across tool kinds.
tests/Andes.Extensions.AI.UI.Unit.Test/ChatResponseUiExtensionsTests.cs Verifies UI event mapping and snapshot folding behavior for UI contract.
tests/Andes.Extensions.AI.UI.Unit.Test/AssistantUiJsonContextTests.cs Tests JSON shape (camelCase, string enums, null omission) for UI contract.
tests/Andes.Extensions.AI.UI.Unit.Test/AssistantStatusReducerTests.cs Tests folding logic for nested activities, failure, finished usage, and text accumulation.
tests/Andes.Extensions.AI.UI.Unit.Test/Andes.Extensions.AI.UI.Unit.Test.csproj New unit test project for the UI satellite package.
tests/Andes.Extensions.AI.Mcp.Unit.Test/McpToolClassificationTests.cs Updates MCP header assertion to reflect de-dup behavior.
tests/Andes.Extensions.AI.Mcp.Integration.Test/McpToolTrackingIntegrationTests.cs Updates integration assertion for MCP header de-dup behavior.
tests/Andes.Extensions.AI.Agent.Unit.Test/AgentToolClassificationTests.cs Updates agent header assertion to reflect de-dup behavior.
tests/Andes.Extensions.AI.Agent.Unit.Test/AgentFunctionCallReportingTests.cs Updates agent header assertion for de-dup behavior in nested progress.
tests/Andes.Extensions.AI.Agent.Integration.Test/AgentToolTrackingIntegrationTests.cs Updates integration assertion for agent header de-dup behavior.
README.md Adds top-level README section introducing the new UI package and usage.
docs/ui.md New documentation describing the UI contract, mapper/reducer, TS file, and examples.
docs/getting-started.md Updates header formatter docs to describe kind-word de-dup behavior.
docs/examples/ui-contract.md New end-to-end example: minimal API SSE producer + Blazor WASM + TypeScript SPA consumer.
docs/examples/progress-board.md Updates example output/docs to reflect de-duplicated headers.
docs/architecture.md Documents the new UI satellite package and its relationship to the scope tree.
docs/agents.md Updates agent docs to describe name-ending de-dup behavior.
Andes.Extensions.slnx Adds the new UI project and its unit test project to the solution.
Andes.Extensions.AI/ToolTrackingOptions.cs Updates XML docs to describe kind-word de-dup behavior.
Andes.Extensions.AI/Internal/RequestTracker.cs Implements kind-word de-dup logic in the default header formatter.
Andes.Extensions.AI.UI/UsageSummary.cs Adds flattened, serialization-friendly usage DTO.
Andes.Extensions.AI.UI/typescript/andes-assistant-ui.ts Adds shipped TypeScript contract + folding reducer to mirror C# behavior.
Andes.Extensions.AI.UI/SubStatus.cs Adds sub-status DTO for activity progress lines.
Andes.Extensions.AI.UI/README.md Adds package README describing the contract and how to consume it.
Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs Adds stream-to-contract mapper and snapshot folding pipeline extensions.
Andes.Extensions.AI.UI/AssistantUiJsonContext.cs Adds source-generated System.Text.Json context for the UI contract.
Andes.Extensions.AI.UI/AssistantUiEventKind.cs Adds discriminator enum for UI events.
Andes.Extensions.AI.UI/AssistantUiEvent.cs Adds flat event DTO for streaming deltas.
Andes.Extensions.AI.UI/AssistantStatusSnapshot.cs Adds folded snapshot DTO for UI rendering.
Andes.Extensions.AI.UI/AssistantStatusReducer.cs Adds reducer that folds events into immutable snapshots.
Andes.Extensions.AI.UI/AssistantActivity.cs Adds activity DTO used by folded snapshots (tree structure).
Andes.Extensions.AI.UI/Andes.Extensions.AI.UI.csproj New UI satellite package project + packing the TS file.
Andes.Extensions.AI.UI/ActivityState.cs Adds activity/request lifecycle enum for UI state.
Andes.Extensions.AI.Agent/README.md Updates agent README example header to reflect de-dup behavior.
Comments suppressed due to low confidence (1)

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:172

  • Finished events are emitted without Timestamp, so (like TextDelta) the serialized JSON will include a default timestamp value (year 0001) rather than something meaningful. If clients display timestamps, this looks like bad data. Consider setting Timestamp (and explicitly Depth/ToolKind) when building the finished event.
    private static AssistantUiEvent ToFinishedEvent(ChatUsageReport report)
    {
        return new AssistantUiEvent
        {
            Kind = AssistantUiEventKind.Finished,
            Usage = report.TotalUsage.ToUsageSummary(),
            DurationSeconds = report.Duration.TotalSeconds,
        };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs
Comment thread Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs
Comment thread Andes.Extensions.AI/Internal/RequestTracker.cs
- Introduced interactive console chat in `samples/Andes.Extensions.AI.Demo`
- Implemented `DemoTools`, `DemoAgents`, and `DemoMcpServer` for functionality
- Added `StatusRenderer` for rendering assistant status snapshots
- Included sample configuration file `appsettings.sample.json`
- Updated `.gitignore` and `Directory.Build.props` for demo project settings
Copilot AI review requested due to automatic review settings July 29, 2026 02:53
Comment thread samples/Andes.Extensions.AI.Demo/DemoMcpServer.cs Dismissed
Comment thread samples/Andes.Extensions.AI.Demo/Program.cs Dismissed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 47 out of 48 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

Andes.Extensions.AI/Internal/RequestTracker.cs:356

  • DefaultHeader.Compose trims trailing whitespace only for the EndsWith check, but still emits the original untrimmed name. If a tool/server name has trailing spaces, the header will include those spaces (and may still omit the suffix), producing odd UI/log output.
        {
            return name.TrimEnd().EndsWith(suffix, StringComparison.OrdinalIgnoreCase)
                ? $"Calling {name}"
                : $"Calling {name} {suffix}";
        }

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:114

  • ToUiEvent currently copies ChatProgressUpdate.Message for all event kinds. For ActivityStarted/Completed/Failed this reintroduces the composed English header/status strings (e.g., "Calling … MCP"), which the UI contract docs say should be represented via DisplayName + ToolKind badge (and message reserved for request status / sub-status lines). Consider nulling Message for non-Status and non-ActivityProgress events.
        return new AssistantUiEvent
        {
            Kind = MapKind(update.Kind),
            Message = update.Message,
            ScopeId = update.ScopeId,

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:67

  • TextDelta and Finished events are created without setting Timestamp. Because AssistantUiJsonContext omits only nulls (not default value types), these events will serialize a default timestamp ("0001-01-01…"), which is noisy and can confuse consumers (TypeScript contract also treats timestamp as required). Consider explicitly setting a meaningful timestamp (e.g., UtcNow) for these synthetic events.
            if (update.Text is { Length: > 0 } text)
            {
                yield return new AssistantUiEvent
                {
                    Kind = AssistantUiEventKind.TextDelta,
                    Text = text,
                };
            }

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:173

  • Finished events also omit Timestamp, so they will serialize a default "0001-01-01…" value under the current JsonSourceGenerationOptions. Setting a real timestamp avoids consumers having to special-case the default value.
    private static AssistantUiEvent ToFinishedEvent(ChatUsageReport report)
    {
        return new AssistantUiEvent
        {
            Kind = AssistantUiEventKind.Finished,
            Usage = report.TotalUsage.ToUsageSummary(),
            DurationSeconds = report.Duration.TotalSeconds,
        };
    }

- Introduced `ChatProgressToolScope` to manage nested tool-call scopes and track usage.
- Enhanced `AgentToolTrackingIntegrationTests` to validate nested agent tool invocation and usage attribution.
- Added `FinalSnapshot` class to merge activity snapshots with usage reports.
- Created unit tests for nested agent scopes, ensuring correct tracking and reporting behavior.
- Updated existing tests to cover new functionality and edge cases for nested scopes.
- Implemented `LiveNestedActivityTests` to verify live updates for nested activities.
- Ensured proper handling of tool invocation and usage reporting in various scenarios.
Copilot AI review requested due to automatic review settings July 29, 2026 04:57
Comment thread tests/Andes.Extensions.AI.Agent.Integration.Test/AgentToolTrackingIntegrationTests.cs Dismissed
Comment thread tests/Andes.Extensions.AI.UI.Unit.Test/LiveNestedActivityTests.cs Dismissed
Comment thread tests/Andes.Extensions.AI.Agent.Integration.Test/AgentToolTrackingIntegrationTests.cs Dismissed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 65 out of 66 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

Andes.Extensions.AI/Internal/RequestTracker.cs:357

  • DefaultHeader's Compose() trims the name only for the EndsWith check, but returns the original (potentially trailing-whitespace) name. That can produce headers with unexpected trailing spaces (and suppress the suffix) if a DisplayName/Source accidentally includes whitespace. Trimming once and using the trimmed value for both the check and the output avoids this edge case.
        static string Compose(string name, string suffix)
        {
            return name.TrimEnd().EndsWith(suffix, StringComparison.OrdinalIgnoreCase)
                ? $"Calling {name}"
                : $"Calling {name} {suffix}";
        }

Copilot AI review requested due to automatic review settings July 29, 2026 05:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 67 out of 69 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:68

  • ToUiEventsAsync currently forwards the in-band RequestCompleted progress update as a Status event (via ToUiEvent/MapKind), which overwrites the UI's last meaningful AssistantStatus with the literal "Request completed" right before emitting the final Finished event. Also, TextDelta events leave Timestamp at its default, which will serialize as an invalid-looking year-0001 value.

Consider skipping RequestCompleted progress events here (the Finished event already represents completion) and setting an explicit timestamp for text deltas.

            foreach (AIContent content in update.Contents)
            {
                switch (content)
                {
                    case ChatProgressContent progress:

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:173

  • ToFinishedEvent leaves Depth, ToolKind, and especially Timestamp at their defaults. Because AssistantUiJsonContext only omits nulls (not default values), this will serialize timestamp as the year-0001 default, which is surprising for consumers.

Set explicit values so the wire contract stays consistent and doesn't emit sentinel timestamps.

    private static AssistantUiEvent ToFinishedEvent(ChatUsageReport report)
    {
        return new AssistantUiEvent
        {
            Kind = AssistantUiEventKind.Finished,
            Usage = report.TotalUsage.ToUsageSummary(),
            DurationSeconds = report.Duration.TotalSeconds,
        };
    }

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:189

  • ToActivity uses ScopeId = call.CallId ?? call.ToolName. When CallId is missing (it can be null for nested scopes opened outside a function-invocation loop, or for providers that don't surface call ids), multiple invocations of the same tool will collide on the same ScopeId. That can break UI diffing/keying and any later event association.

Use a guaranteed-unique fallback ID when CallId is null.

    private static AssistantActivity ToActivity(ToolCallUsage call)
    {
        return new AssistantActivity
        {
            ScopeId = call.CallId ?? call.ToolName,

Copilot AI review requested due to automatic review settings July 29, 2026 05:23
@RorroRojas3
RorroRojas3 merged commit 2ab7f3f into main Jul 29, 2026
5 checks passed
@RorroRojas3
RorroRojas3 deleted the claude/andes-extensions-ai-ui-huyabl branch July 29, 2026 05:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 67 out of 69 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

Andes.Extensions.AI.UI/ChatResponseUiExtensions.cs:179

  • ChatUsageReport.ToSnapshot() uses ScopeId = call.CallId ?? call.ToolName, which can collide when the same tool is invoked multiple times with a null CallId (e.g., direct invocation from inside a tool body). Colliding scope IDs can break UI keying and any consumer that expects scope IDs to be unique within a snapshot.
            ScopeId = call.CallId ?? call.ToolName,

Andes.Extensions.AI.UI/AssistantUiEvent.cs:94

  • Timestamp is non-nullable, but TextDelta and Finished events are created without setting it, so serialization will emit the default 0001-01-01... value. Consumers may misinterpret that as a real event time; consider making Timestamp nullable and omitting it when unavailable (and updating the TypeScript contract accordingly), or explicitly setting a meaningful timestamp for those event kinds.
    /// status and activity events; <see cref="AssistantUiEventKind.TextDelta"/> and
    /// <see cref="AssistantUiEventKind.Finished"/> events, which have no source progress event,
    /// leave it at its default. Consume events in stream order rather than sorting by this value.
    /// </summary>
    public DateTimeOffset Timestamp { get; init; }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants