mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Cleanup
This commit is contained in:
@@ -1,390 +0,0 @@
|
||||
# Design for Blazor Agent UI
|
||||
This document covers the design of the Microsoft.AspNetCore.Components.AI library for apps that interact with AI agents. Below we enumerate the general design patterns that we aim to provide in this area
|
||||
|
||||
## Scenario 1 - Include an agent on the UI
|
||||
|
||||
```html
|
||||
<AgentBoundary Agent="@myAgent">
|
||||
</AgentBoundary>
|
||||
```
|
||||
|
||||
AgentBoundary is responsible for "connecting the UI to the agent.
|
||||
|
||||
It keeps track of the messages back and forth between the agent and the UI.
|
||||
|
||||
It provides an AgentBoundaryContext cascading value that other children component can use to:
|
||||
* Listen for new messages
|
||||
* The context exposes an `IAsyncEnumerable<ChatMessage>` Messages stream of messages (including past messages and future messages, this is a "cold" enumerable)
|
||||
* The context exposes an `IAsyncEnumerable<IAsyncEnumerable<ChatResponseUpdate>>` stream of updates per turn.
|
||||
* The outer IEnumerable represents all the turns between the user and the LLM.
|
||||
* The inner IEnumerable represents the updates for the current run.
|
||||
* This is a "hot" enumerable, meaning that you don't get past updates, only new ones.
|
||||
* The context exposes a T State property that represents any state associated with the agent.
|
||||
* The context exposes an IAsyncEnumerable<T> stream that represents state updates if there is state attached to the Agent.
|
||||
* The context exposes a `SendAsync` method to trigger an interaction with the agent, which might include new messages as well as state.
|
||||
* The context exposes a CancellationToken tied to the lifetime of the AgentBoundary
|
||||
|
||||
AgentBoundary doesn't have any UI, it's all about managing the interaction with the agent. This gives users the freedom to implement other parts of their agentic UI as they see fit.
|
||||
|
||||
That said, we provide components to render a default input box as well as components to render the list of messages.
|
||||
|
||||
Here is a more complete example:
|
||||
```html
|
||||
<AgentBoundary Agent="@myAgent">
|
||||
<Messages />
|
||||
<AgentInput />
|
||||
</AgentBoundary>
|
||||
```
|
||||
|
||||
The snippet above will render the default Chat like UI that we are all used to seeing and using.
|
||||
|
||||
## Messages Component
|
||||
|
||||
The messages component is responsible for the bulk of functionality in rendering messages from the agent. It's responsible for subscribing to the AgentBoundaryContext update stream and making sure that messages are rendered as they arrive. It holds the list of messages in memory and re-renders as new messages arrive.
|
||||
|
||||
Our default Messages component supports customizing the way messages are rendered via templates. Users can define custom content templates to control how messages are rendered. These templates reflect the different content types that are available on Microsoft.Extensions.AI. There is a default template class for each content type and a general fallback template that can be used to provide a fallback for any unknown content.
|
||||
|
||||
Some templates can have additional parameters. For example, the DataContentTemplate can specify a mime type to filter on and only render data messages that match that mime type. Similarly, the ToolCallContentTemplate can specify a tool name to filter on.
|
||||
|
||||
The content templates provide a context object that includes two properties:
|
||||
* Message: That gives access to the completed message (if available)
|
||||
* Updates: That gives access to the list of updates being rendered for the current incoming message.
|
||||
|
||||
The Messages component provides a default rendering template for TextContent. Any other content type will just not be rendered unless the developer provides a custom template for it.
|
||||
|
||||
Here is a list of all the available content templates:
|
||||
|
||||
* CodeInterpreterToolCallTemplate
|
||||
* CodeInterpreterToolResultTemplate
|
||||
* DataTemplate
|
||||
* ErrorTemplate
|
||||
* FunctionCallTemplate
|
||||
* FunctionResultTemplate
|
||||
* FunctionApprovalRequestTemplate
|
||||
* FunctionApprovalResponseTemplate
|
||||
* HostedFileTemplate
|
||||
* HostedVectorStoreTemplate
|
||||
* ImageGenerationToolCallTemplate
|
||||
* ImageGenerationToolResultTemplate
|
||||
* McpServerToolCallTemplate
|
||||
* McpServerToolResultTemplate
|
||||
* TextTemplate
|
||||
* TextReasoningTemplate
|
||||
* UriTemplate
|
||||
* UsageTemplate
|
||||
* UserInputRequestTemplate
|
||||
* UserInputResponseTemplate
|
||||
|
||||
MessageModifiers can be used to modify the way messages are rendered. For example, a MessageModifier can be used to customize the "frame" around a message, so that ContentTemplates can focus on rendering the content itself. At the same time, MessageModifiers can be used to add additional UI elements around the message or provide overrides for specific AI contents.
|
||||
|
||||
All ContentTemplates and MessageModifiers extend a base class ContentTemplateBase or MessageModifierBase respectively. They expose a "When" parameter that receives the message and returns a boolean indicating whether the template/modifier should be applied to that message/update.
|
||||
|
||||
The MessageModifiers that exist by default are:
|
||||
* UserMessageModifier
|
||||
* SystemMessageModifier
|
||||
* AssistantMessageModifier
|
||||
* ToolMessageModifier
|
||||
|
||||
Internally the Messages component follows this algorithm to render messages:
|
||||
1. For any given message: It first tries to match against an existing WellKnown MessageModifier (User, System, Assistant, Tool). If it matches a well known MessageModifier, it uses that one to render the message.
|
||||
- We do this to avoid having to iterate over all MessageModifiers for the most common cases.
|
||||
- Well known MessageModifiers take more precedence than custom message modifiers.
|
||||
2. If no well known MessageModifier matches, it iterates over all custom MessageModifiers in the order they were defined and uses the first one that matches.
|
||||
3. If no MessageModifier matches, it uses the DefaultMessageModifier to render the message.
|
||||
|
||||
4. We merge the list of default content renderers with the content renderers in the modifier (if applicable) and then we proceed to find the right content template for each content in the message:
|
||||
- For any given content in the message, we first try to match against well known ContentTemplates in the merged set.
|
||||
- We do this to avoid having to iterate over all ContentTemplates for the most common cases.
|
||||
- Well known ContentTemplates take more precedence than custom content templates.
|
||||
- If no well known ContentTemplate matches, we iterate over all custom ContentTemplates in the merged set in the order they were defined and use the first one that matches.
|
||||
- If no matching ContentTemplate is found, we don't render any content.
|
||||
- If no content is rendered for a message, we skip rendering the message entirely.
|
||||
|
||||
By default we render each message inside a `div` with CSS classes that reflect the role of the message (user, system, assistant, tool) as well as whether or not the message is complete. This can be customized by providing custom MessageModifiers. The modifier context provides access to a RenderContents method that can be used to render the contents of the message using the content templates.
|
||||
|
||||
With this in mind, let's walk through some very common scenarios:
|
||||
|
||||
### Customizing messages based on role
|
||||
|
||||
```html
|
||||
<AgentBoundary Agent="@myAgent">
|
||||
<Messages>
|
||||
<MessageModifiers>
|
||||
<UserMessageModifier>
|
||||
<div class="message user-message" style="background-color: lightblue; padding: 10px; border-radius: 5px; margin: 5px;">
|
||||
@context.RenderContents()
|
||||
</div>
|
||||
</UserMessageModifier>
|
||||
<AssistantMessageModifier>
|
||||
<div class="message assistant-message" style="background-color: lightgreen; padding: 10px; border-radius: 5px; margin: 5px;">
|
||||
@context.RenderContents()
|
||||
</div>
|
||||
</AssistantMessageModifier>
|
||||
</MessageModifiers>
|
||||
</Messages>
|
||||
<AgentInput />
|
||||
</AgentBoundary>
|
||||
```
|
||||
|
||||
### Rendering tool calls
|
||||
|
||||
```html
|
||||
<AgentBoundary Agent="@myAgent">
|
||||
<Messages>
|
||||
<ContentTemplates>
|
||||
<ToolCallContentTemplate ToolName="get_weather">
|
||||
<Map Location="@context.GetArgument<string>("location")" />
|
||||
</ToolCallContentTemplate>
|
||||
</ContentTemplates>
|
||||
</Messages>
|
||||
<AgentInput />
|
||||
</AgentBoundary>
|
||||
```
|
||||
|
||||
### Rendering tool results
|
||||
<!-- TODO: Consider an InvocationContext or similar capable of matching results to function calls -->
|
||||
```html
|
||||
<AgentBoundary Agent="@myAgent">
|
||||
<Messages>
|
||||
<ContentTemplates>
|
||||
<ToolResultContentTemplate ToolName="get_weather">
|
||||
<div class="weather-result">
|
||||
Weather in @context.GetArgument<string>("location"): @context.GetArgument<string>("weather_description"), Temperature: @context.GetArgument<double>("temperature") °C
|
||||
</div>
|
||||
</ToolResultContentTemplate>
|
||||
</ContentTemplates>
|
||||
</Messages>
|
||||
<AgentInput />
|
||||
</AgentBoundary>
|
||||
```
|
||||
|
||||
### Rendering approvals
|
||||
|
||||
```html
|
||||
<AgentBoundary Agent="@myAgent">
|
||||
<Messages>
|
||||
<ContentTemplates>
|
||||
<FunctionApprovalRequestTemplate>
|
||||
<div class="approval-request">
|
||||
<p>Function: @context.FunctionName</p>
|
||||
<p>Details: @context.Details</p>
|
||||
<button @onclick="() => context.AgentContext.Approve(context.Request)">Approve</button>
|
||||
<button @onclick="() => context.AgentContext.Reject(context.Request)">Reject</button>
|
||||
</div>
|
||||
</FunctionApprovalRequestTemplate>
|
||||
</ContentTemplates>
|
||||
</Messages>
|
||||
<AgentInput />
|
||||
</AgentBoundary>
|
||||
```
|
||||
|
||||
### Rendering images
|
||||
|
||||
```html
|
||||
<AgentBoundary Agent="@myAgent">
|
||||
<Messages>
|
||||
<ContentTemplates>
|
||||
<ImageGenerationToolResultTemplate>
|
||||
<img src="@context.ImageUrl" alt="Generated Image" />
|
||||
</ImageGenerationToolResultTemplate>
|
||||
</ContentTemplates>
|
||||
</Messages>
|
||||
<AgentInput />
|
||||
</AgentBoundary>
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
```csharp
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.Extensions.AI;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Components.AI;
|
||||
|
||||
// Main boundary component that connects UI to agent
|
||||
public class AgentBoundary : IComponent
|
||||
{
|
||||
[Parameter] public IAgent Agent { get; set; }
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
|
||||
public void Attach(RenderHandle renderHandle) => throw new NotImplementedException();
|
||||
public Task SetParametersAsync(ParameterView parameters) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Non-generic context provided by AgentBoundary
|
||||
public abstract class AgentBoundaryContext
|
||||
{
|
||||
IAsyncEnumerable<ChatMessage> Messages { get; }
|
||||
IAsyncEnumerable<IAsyncEnumerable<ChatResponseUpdate>> UpdateStreams { get; }
|
||||
object GetState();
|
||||
IAsyncEnumerable<object> GetStateUpdates();
|
||||
Task SendAsync(object state, params Span<ChatMessage> newMessages);
|
||||
CancellationToken CancellationToken { get; }
|
||||
|
||||
// Methods for approval scenarios
|
||||
Task Approve(FunctionApprovalRequest request);
|
||||
Task Reject(FunctionApprovalRequest request);
|
||||
}
|
||||
|
||||
// Generic context with typed state
|
||||
public abstract class AgentBoundaryContext<TState> : AgentBoundaryContext
|
||||
{
|
||||
public abstract TState State { get; }
|
||||
public abstract IAsyncEnumerable<TState> StateUpdates { get; }
|
||||
public abstract Task SendAsync(TState state, params Span<ChatMessage> newMessages);
|
||||
}
|
||||
|
||||
// Main messages display component
|
||||
public class Messages : IComponent
|
||||
{
|
||||
[Parameter] public RenderFragment MessageModifiers { get; set; }
|
||||
[Parameter] public RenderFragment ContentTemplates { get; set; }
|
||||
[CascadingParameter] public IAgentBoundaryContext AgentContext { get; set; }
|
||||
|
||||
public void Attach(RenderHandle renderHandle) => throw new NotImplementedException();
|
||||
public Task SetParametersAsync(ParameterView parameters) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Input component for user interactions
|
||||
public class AgentInput : IComponent
|
||||
{
|
||||
[CascadingParameter] public IAgentBoundaryContext AgentContext { get; set; }
|
||||
|
||||
public void Attach(RenderHandle renderHandle) => throw new NotImplementedException();
|
||||
public Task SetParametersAsync(ParameterView parameters) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Base classes for templates and modifiers
|
||||
public abstract class MessageModifierBase : IComponent
|
||||
{
|
||||
[Parameter] public Func<ChatMessage, bool> When { get; set; }
|
||||
[Parameter] public RenderFragment<MessageModifierContext> ChildContent { get; set; }
|
||||
|
||||
public void Attach(RenderHandle renderHandle) => throw new NotImplementedException();
|
||||
public Task SetParametersAsync(ParameterView parameters) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public abstract class ContentTemplateBase : IComponent
|
||||
{
|
||||
[Parameter] public Func<AIContent, bool> When { get; set; }
|
||||
[Parameter] public RenderFragment<ContentTemplateContext> ChildContent { get; set; }
|
||||
|
||||
public void Attach(RenderHandle renderHandle) => throw new NotImplementedException();
|
||||
public Task SetParametersAsync(ParameterView parameters) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Context types for templates
|
||||
public class MessageModifierContext
|
||||
{
|
||||
public ChatMessage Message { get; set; }
|
||||
public IEnumerable<ChatResponseUpdate> Updates { get; set; }
|
||||
public RenderFragment RenderContents() => default;
|
||||
}
|
||||
|
||||
public class ContentTemplateContext
|
||||
{
|
||||
public ChatMessage Message { get; set; }
|
||||
public IReadOnlyList<ChatResponseUpdate> Updates { get; set; }
|
||||
public IAgentBoundaryContext AgentContext { get; set; }
|
||||
public T GetArgument<T>(string name) => default;
|
||||
}
|
||||
|
||||
// Specialized context for approval scenarios
|
||||
public class FunctionApprovalContext : ContentTemplateContext
|
||||
{
|
||||
public string FunctionName { get; set; }
|
||||
public string Details { get; set; }
|
||||
public FunctionApprovalRequest Request { get; set; }
|
||||
}
|
||||
|
||||
// Message modifiers for different roles
|
||||
public class UserMessageModifier : MessageModifierBase { }
|
||||
public class SystemMessageModifier : MessageModifierBase { }
|
||||
public class AssistantMessageModifier : MessageModifierBase { }
|
||||
public class ToolMessageModifier : MessageModifierBase { }
|
||||
public class DefaultMessageModifier : MessageModifierBase { }
|
||||
|
||||
// Content templates for different content types
|
||||
public class TextTemplate : ContentTemplateBase { }
|
||||
|
||||
public class TextReasoningTemplate : ContentTemplateBase { }
|
||||
|
||||
public class DataTemplate : ContentTemplateBase
|
||||
{
|
||||
[Parameter] public string MimeType { get; set; }
|
||||
}
|
||||
|
||||
public class ImageTemplate : ContentTemplateBase { }
|
||||
|
||||
public class UriTemplate : ContentTemplateBase { }
|
||||
|
||||
public class UsageTemplate : ContentTemplateBase { }
|
||||
|
||||
public class ErrorTemplate : ContentTemplateBase { }
|
||||
|
||||
public class HostedFileTemplate : ContentTemplateBase { }
|
||||
|
||||
public class HostedVectorStoreTemplate : ContentTemplateBase { }
|
||||
|
||||
// Function/Tool related templates
|
||||
public class FunctionCallTemplate : ContentTemplateBase { }
|
||||
|
||||
public class FunctionResultTemplate : ContentTemplateBase { }
|
||||
|
||||
public class ToolCallContentTemplate : ContentTemplateBase
|
||||
{
|
||||
[Parameter] public string ToolName { get; set; }
|
||||
}
|
||||
|
||||
public class ToolResultContentTemplate : ContentTemplateBase
|
||||
{
|
||||
[Parameter] public string ToolName { get; set; }
|
||||
}
|
||||
|
||||
// Approval templates
|
||||
public class FunctionApprovalRequestTemplate : ContentTemplateBase
|
||||
{
|
||||
[Parameter] public new RenderFragment<FunctionApprovalContext> ChildContent { get; set; }
|
||||
}
|
||||
|
||||
public class FunctionApprovalResponseTemplate : ContentTemplateBase { }
|
||||
|
||||
// User input templates
|
||||
public class UserInputRequestTemplate : ContentTemplateBase { }
|
||||
|
||||
public class UserInputResponseTemplate : ContentTemplateBase { }
|
||||
|
||||
// Specialized tool templates
|
||||
public class CodeInterpreterToolCallTemplate : ContentTemplateBase { }
|
||||
|
||||
public class CodeInterpreterToolResultTemplate : ContentTemplateBase { }
|
||||
|
||||
public class ImageGenerationToolCallTemplate : ContentTemplateBase { }
|
||||
|
||||
public class ImageGenerationToolResultTemplate : ContentTemplateBase
|
||||
{
|
||||
public string ImageUrl => default;
|
||||
}
|
||||
|
||||
public class McpServerToolCallTemplate : ContentTemplateBase { }
|
||||
|
||||
public class McpServerToolResultTemplate : ContentTemplateBase { }
|
||||
|
||||
// Supporting types
|
||||
public class FunctionApprovalRequest
|
||||
{
|
||||
public string FunctionName { get; set; }
|
||||
public IDictionary<string, object> Arguments { get; set; }
|
||||
}
|
||||
|
||||
// Agent interface (assumed from Microsoft.Extensions.AI)
|
||||
public interface IAgent
|
||||
{
|
||||
// Agent interface members would be defined in Microsoft.Extensions.AI
|
||||
}
|
||||
```
|
||||
@@ -1,497 +0,0 @@
|
||||
# AG-UI Blazor Dojo - Implementation Plan
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document outlines the plan to transform the AGUIDojoClient from a simple chat application into a comprehensive AG-UI Dojo - a simplified Blazor version of [dojo.ag-ui.com/microsoft-agent-framework-dotnet](https://dojo.ag-ui.com/microsoft-agent-framework-dotnet). The dojo will showcase various AG-UI scenarios and features through an interactive demonstration platform.
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### Existing Components
|
||||
|
||||
**AGUIDojoServer** provides seven AG-UI endpoints:
|
||||
1. `/agentic_chat` - Basic chat with frontend tools
|
||||
2. `/backend_tool_rendering` - Backend tool demonstrations
|
||||
3. `/human_in_the_loop` - Human approval workflows
|
||||
4. `/tool_based_generative_ui` - Tool-based generative UI
|
||||
5. `/agentic_generative_ui` - Agentic generative UI
|
||||
6. `/shared_state` - Shared state management
|
||||
7. `/predictive_state_updates` - Predictive state updates
|
||||
|
||||
**AGUIDojoClient** currently has:
|
||||
- Basic chat interface components (Chat.razor, ChatInput.razor, ChatMessageList.razor, etc.)
|
||||
- Layout components (MainLayout.razor)
|
||||
- AG-UI client integration via `AGUIChatClient`
|
||||
|
||||
## Target Architecture
|
||||
|
||||
### Dojo Website Structure (from analysis)
|
||||
|
||||
The dojo website has the following structure:
|
||||
- **Left Sidebar**: Lists all available demo scenarios with descriptions and tags
|
||||
- **Main Content Area**: Contains three tabs
|
||||
- **Preview Tab**: Interactive demo of the selected scenario
|
||||
- **Code Tab**: Shows relevant code files for the scenario
|
||||
- **Docs Tab**: Documentation for the scenario
|
||||
- **No Integration Selector**: We'll skip the integration dropdown since we're focused on Microsoft Agent Framework (.NET)
|
||||
|
||||
### Demo Scenarios
|
||||
|
||||
Based on the dojo website analysis, we need to support these scenarios:
|
||||
|
||||
1. **Agentic Chat**
|
||||
- Description: Chat with your Copilot and call frontend tools
|
||||
- Tags: Chat, Tools, Streaming
|
||||
- Endpoint: `/agentic_chat`
|
||||
|
||||
2. **Backend Tool Rendering**
|
||||
- Description: Render and stream your backend tools to the frontend
|
||||
- Tags: Agent State, Collaborating
|
||||
- Endpoint: `/backend_tool_rendering`
|
||||
|
||||
3. **Human in the Loop**
|
||||
- Description: Plan a task together and direct the Copilot to take the right steps
|
||||
- Tags: HITL, Interactivity
|
||||
- Endpoint: `/human_in_the_loop`
|
||||
|
||||
4. **Agentic Generative UI**
|
||||
- Description: Assign a long running task to your Copilot and see how it performs!
|
||||
- Tags: Generative UI (agent), Long running task
|
||||
- Endpoint: `/agentic_generative_ui`
|
||||
|
||||
5. **Tool Based Generative UI**
|
||||
- Description: Haiku generator that uses tool based generative UI
|
||||
- Tags: Generative UI (action), Tools
|
||||
- Endpoint: `/tool_based_generative_ui`
|
||||
|
||||
6. **Shared State between Agent and UI**
|
||||
- Description: A recipe Copilot which reads and updates collaboratively
|
||||
- Tags: Agent State, Collaborating
|
||||
- Endpoint: `/shared_state`
|
||||
|
||||
7. **Predictive State Updates**
|
||||
- Description: Use collaboration to edit a document in real time with your Copilot
|
||||
- Tags: State, Streaming, Tools
|
||||
- Endpoint: `/predictive_state_updates`
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Project Structure & Routing
|
||||
|
||||
#### 1.1 Create New Component Structure
|
||||
|
||||
```
|
||||
Components/
|
||||
Layout/
|
||||
MainLayout.razor (Update existing)
|
||||
DemoSidebar.razor (New - left sidebar with demo list)
|
||||
DemoViewTabs.razor (New - Preview/Code/Docs tabs)
|
||||
|
||||
Pages/
|
||||
Index.razor (New - redirects to first demo)
|
||||
Demo.razor (New - main demo container with routing)
|
||||
|
||||
Demos/
|
||||
AgenticChat/
|
||||
AgenticChatDemo.razor (Chat UI for this scenario)
|
||||
BackendToolRendering/
|
||||
BackendToolRenderingDemo.razor
|
||||
HumanInLoop/
|
||||
HumanInLoopDemo.razor
|
||||
AgenticGenerativeUI/
|
||||
AgenticGenerativeUIDemo.razor
|
||||
ToolBasedGenerativeUI/
|
||||
ToolBasedGenerativeUIDemo.razor
|
||||
SharedState/
|
||||
SharedStateDemo.razor
|
||||
PredictiveStateUpdates/
|
||||
PredictiveStateUpdatesDemo.razor
|
||||
|
||||
Shared/
|
||||
DemoScenario.cs (Model for demo metadata)
|
||||
DemoService.cs (Service to manage demo scenarios)
|
||||
Chat/ (Move existing chat components here)
|
||||
ChatHeader.razor
|
||||
ChatInput.razor
|
||||
ChatMessageList.razor
|
||||
ChatMessageItem.razor
|
||||
ChatSuggestions.razor
|
||||
ChatCitation.razor
|
||||
```
|
||||
|
||||
#### 1.2 Update Routing
|
||||
|
||||
- Use Blazor's `@page` directive with route parameters: `@page "/microsoft-agent-framework/feature/{scenarioId}"`
|
||||
- Default route `/` redirects to first scenario
|
||||
- Each scenario accessible via `/microsoft-agent-framework/feature/agentic_chat`, `/microsoft-agent-framework/feature/backend_tool_rendering`, etc.
|
||||
- Scenario IDs use underscores to match server endpoints and dojo convention
|
||||
|
||||
### Phase 2: Core Components
|
||||
|
||||
#### 2.1 DemoSidebar Component
|
||||
|
||||
**Purpose**: Display list of demo scenarios in left sidebar
|
||||
|
||||
**Features**:
|
||||
- List all available scenarios
|
||||
- Show title, description, and tags for each scenario
|
||||
- Highlight currently selected scenario
|
||||
- Navigate to scenario on click
|
||||
- Responsive design (collapsible on mobile)
|
||||
|
||||
**Data Structure**:
|
||||
```csharp
|
||||
public record DemoScenario(
|
||||
string Id, // e.g., "agentic_chat", "backend_tool_rendering"
|
||||
string Title,
|
||||
string Description,
|
||||
string[] Tags,
|
||||
string Endpoint, // e.g., "/agentic_chat"
|
||||
string Icon = "💬"
|
||||
);
|
||||
```
|
||||
|
||||
#### 2.2 DemoViewTabs Component
|
||||
|
||||
**Purpose**: Tab control for Preview/Code/Docs views
|
||||
|
||||
**Features**:
|
||||
- Three tabs: Preview, Code, Docs
|
||||
- Smooth tab transitions
|
||||
- State persistence (current tab stays active when switching demos)
|
||||
- Blazor Interactive Server rendering for tab switching
|
||||
|
||||
**Implementation Approach**:
|
||||
- Use Blazor's `@rendermode InteractiveServer` for tab interactivity
|
||||
- Tab state managed via component parameter
|
||||
- CSS for tab styling similar to dojo website
|
||||
|
||||
#### 2.3 Demo.razor (Main Container)
|
||||
|
||||
**Purpose**: Container page that hosts the demo experience
|
||||
|
||||
**Features**:
|
||||
- Route parameter for scenario selection: `@page "/microsoft-agent-framework/feature/{scenarioId}"`
|
||||
- Loads appropriate demo component based on scenarioId
|
||||
- Manages tab state
|
||||
- Dynamically loads code/docs content
|
||||
|
||||
**Structure**:
|
||||
```razor
|
||||
@page "/microsoft-agent-framework/feature/{scenarioId}"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<div class="dojo-container">
|
||||
<DemoSidebar CurrentScenarioId="@ScenarioId" />
|
||||
<div class="dojo-main">
|
||||
<DemoViewTabs CurrentTab="@currentTab" OnTabChanged="@OnTabChanged">
|
||||
<PreviewContent>
|
||||
@RenderScenarioDemo()
|
||||
</PreviewContent>
|
||||
<CodeContent>
|
||||
<CodeViewer Files="@GetCodeFiles()" />
|
||||
</CodeContent>
|
||||
<DocsContent>
|
||||
<DocsViewer Content="@GetDocsContent()" />
|
||||
</DocsContent>
|
||||
</DemoViewTabs>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Phase 3: Demo Scenario Components
|
||||
|
||||
#### 3.1 Base Pattern for Demo Components
|
||||
|
||||
Each demo component should:
|
||||
- Accept configuration (endpoint URL, server URL)
|
||||
- Use existing chat components where applicable
|
||||
- Implement scenario-specific features
|
||||
- Handle AG-UI client connection
|
||||
- Display scenario-specific UI elements
|
||||
|
||||
#### 3.2 Reusable Chat Components
|
||||
|
||||
Move existing chat components to `Components/Shared/Chat/`:
|
||||
- `ChatHeader.razor` - Header with new chat button
|
||||
- `ChatInput.razor` - Message input with send button
|
||||
- `ChatMessageList.razor` - Message display container
|
||||
- `ChatMessageItem.razor` - Individual message rendering
|
||||
- `ChatSuggestions.razor` - Suggested prompts
|
||||
- `ChatCitation.razor` - Citation display
|
||||
|
||||
#### 3.3 Scenario-Specific Components
|
||||
|
||||
**AgenticChat**: Can largely reuse existing Chat.razor
|
||||
- Configure to use `/agentic_chat` endpoint
|
||||
- Add example prompts specific to frontend tools
|
||||
|
||||
**BackendToolRendering**: Similar to AgenticChat
|
||||
- Configure to use `/backend_tool_rendering` endpoint
|
||||
- Display backend tool execution results
|
||||
- Show tool rendering in UI
|
||||
|
||||
**HumanInLoop**: Add approval UI
|
||||
- Configure to use `/human_in_the_loop` endpoint
|
||||
- Display approval requests
|
||||
- Add approve/reject buttons
|
||||
- Show approval workflow state
|
||||
|
||||
**AgenticGenerativeUI**:
|
||||
- Configure to use `/agentic_generative_ui` endpoint
|
||||
- Display agent's plan/steps
|
||||
- Show generative UI components
|
||||
- Render dynamic UI elements
|
||||
|
||||
**ToolBasedGenerativeUI**:
|
||||
- Configure to use `/tool_based_generative_ui` endpoint
|
||||
- Haiku-specific UI
|
||||
- Display generated UI components
|
||||
|
||||
**SharedState**:
|
||||
- Configure to use `/shared_state` endpoint
|
||||
- Display recipe state
|
||||
- Show collaborative state updates
|
||||
- Render ingredient lists, recipe steps
|
||||
|
||||
**PredictiveStateUpdates**:
|
||||
- Configure to use `/predictive_state_updates` endpoint
|
||||
- Document editing UI
|
||||
- Real-time state synchronization display
|
||||
- Show predictive updates as they occur
|
||||
|
||||
### Phase 4: Code & Documentation Views
|
||||
|
||||
#### 4.1 Code Viewer Component
|
||||
|
||||
**Purpose**: Display code files for each scenario
|
||||
|
||||
**Features**:
|
||||
- File selector (tabs or dropdown for multiple files)
|
||||
- Syntax highlighting (use a Blazor-compatible syntax highlighter)
|
||||
- Copy to clipboard button
|
||||
- Line numbers
|
||||
- Responsive design
|
||||
|
||||
**Code Files per Scenario**:
|
||||
- Server-side C# files from AGUIDojoServer
|
||||
- Client-side Razor files
|
||||
- Shared models/types
|
||||
|
||||
**Implementation Options**:
|
||||
- Embed code as string resources
|
||||
- Load from embedded resources
|
||||
- Use `@@preservewhitespace` directive
|
||||
- Consider using BlazorMonaco or similar for code display
|
||||
|
||||
#### 4.2 Docs Viewer Component
|
||||
|
||||
**Purpose**: Display documentation for each scenario
|
||||
|
||||
**Features**:
|
||||
- Markdown rendering (use Markdig or similar)
|
||||
- Links to external documentation
|
||||
- Responsive design
|
||||
- Code examples within docs
|
||||
|
||||
**Documentation Content**:
|
||||
- Overview of the scenario
|
||||
- Key concepts
|
||||
- How to use the demo
|
||||
- Links to related documentation
|
||||
- Common patterns and best practices
|
||||
|
||||
### Phase 5: Styling & UX
|
||||
|
||||
#### 5.1 Layout & Design
|
||||
|
||||
**Sidebar**:
|
||||
- Fixed width (e.g., 300px) on desktop
|
||||
- Collapsible on mobile
|
||||
- Scrollable list of demos
|
||||
- Visual hierarchy with tags
|
||||
|
||||
**Main Content Area**:
|
||||
- Fluid width
|
||||
- Tabs at the top
|
||||
- Full-height content area
|
||||
- Proper spacing and padding
|
||||
|
||||
**Colors & Theme**:
|
||||
- Professional color scheme
|
||||
- Clear visual hierarchy
|
||||
- Accessible contrast ratios
|
||||
- Consistent with Microsoft design language
|
||||
|
||||
#### 5.2 Responsive Design
|
||||
|
||||
- Desktop (>1024px): Full sidebar + content
|
||||
- Tablet (768px-1024px): Collapsible sidebar
|
||||
- Mobile (<768px): Hamburger menu for sidebar, full-width content
|
||||
|
||||
#### 5.3 Loading States
|
||||
|
||||
- Skeleton loaders for chat messages
|
||||
- Loading indicators for responses
|
||||
- Smooth transitions
|
||||
- Error states with retry options
|
||||
|
||||
### Phase 6: Configuration & State Management
|
||||
|
||||
#### 6.1 Demo Configuration Service
|
||||
|
||||
```csharp
|
||||
public class DemoService
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly string _serverUrl;
|
||||
|
||||
public DemoService(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_serverUrl = configuration["SERVER_URL"] ?? "http://localhost:5100";
|
||||
}
|
||||
|
||||
public IEnumerable<DemoScenario> GetAllScenarios() { ... }
|
||||
|
||||
public DemoScenario? GetScenario(string id) { ... }
|
||||
|
||||
public IChatClient CreateChatClient(string endpoint)
|
||||
{
|
||||
var httpClient = new HttpClient { BaseAddress = new Uri(_serverUrl) };
|
||||
return new AGUIChatClient(httpClient, endpoint);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 6.2 State Management
|
||||
|
||||
- Use Blazor's built-in state management
|
||||
- Component-level state for each demo
|
||||
- Service-level state for app-wide settings
|
||||
- No global state persistence needed (demos are ephemeral)
|
||||
|
||||
### Phase 7: Testing & Refinement
|
||||
|
||||
#### 7.1 Manual Testing Checklist
|
||||
|
||||
- [ ] All scenarios load and display correctly
|
||||
- [ ] Routing works for all scenarios
|
||||
- [ ] Tab switching works smoothly
|
||||
- [ ] Chat functionality works in each scenario
|
||||
- [ ] Code viewer displays code correctly
|
||||
- [ ] Docs viewer renders markdown correctly
|
||||
- [ ] Responsive design works on different screen sizes
|
||||
- [ ] Error handling works properly
|
||||
- [ ] Loading states display correctly
|
||||
|
||||
#### 7.2 Performance Considerations
|
||||
|
||||
- Lazy load demo components
|
||||
- Minimize initial bundle size
|
||||
- Use Blazor InteractiveServer for UI interactions
|
||||
- Optimize chat message rendering
|
||||
- Consider virtualization for long message lists
|
||||
|
||||
## Technical Considerations
|
||||
|
||||
### Blazor Render Modes
|
||||
|
||||
We'll use **Interactive Server** render mode (`@rendermode InteractiveServer`) for:
|
||||
- Tab switching
|
||||
- Demo sidebar interactions
|
||||
- Chat interactions
|
||||
- Real-time updates
|
||||
|
||||
This provides:
|
||||
- Real-time updates over SignalR
|
||||
- Server-side state management
|
||||
- No need for WebAssembly
|
||||
- Simplified deployment
|
||||
|
||||
### AG-UI Client Integration
|
||||
|
||||
Each demo component will:
|
||||
1. Inject or create an `IChatClient` instance
|
||||
2. Configure with the appropriate endpoint
|
||||
3. Use `ChatClient.GetStreamingResponseAsync()` for streaming
|
||||
4. Handle different content types (text, state, approvals, etc.)
|
||||
5. Dispose properly on component disposal
|
||||
|
||||
### Code Organization Best Practices
|
||||
|
||||
Following existing conventions:
|
||||
- Copyright headers on all `.cs` files
|
||||
- XML documentation for public classes/methods
|
||||
- Use `@inject` for dependency injection
|
||||
- Use `@implements IDisposable` for cleanup
|
||||
- Use `@code` blocks for component logic
|
||||
- Follow Blazor naming conventions (PascalCase for components)
|
||||
|
||||
## Success Criteria
|
||||
|
||||
1. **Functional**: All seven scenarios work correctly
|
||||
2. **Usable**: Intuitive navigation between scenarios and tabs
|
||||
3. **Educational**: Code and docs help users understand AG-UI
|
||||
4. **Performant**: Smooth interactions, fast loading
|
||||
5. **Maintainable**: Clean code, good structure, easy to extend
|
||||
6. **Responsive**: Works on desktop, tablet, and mobile
|
||||
|
||||
## Future Enhancements (Out of Scope)
|
||||
|
||||
- Authentication/authorization
|
||||
- Saving/sharing demo sessions
|
||||
- Custom scenario creation
|
||||
- Integration selector (supporting multiple frameworks)
|
||||
- Deployment to Azure
|
||||
- Analytics/telemetry
|
||||
- Dark mode toggle
|
||||
- Internationalization
|
||||
|
||||
## Dependencies & Prerequisites
|
||||
|
||||
### Required NuGet Packages
|
||||
- Microsoft.Agents.AI.AGUI (already referenced)
|
||||
- Markdig (for markdown rendering in docs)
|
||||
- BlazorMonaco or similar (optional, for code syntax highlighting)
|
||||
|
||||
### Environment Configuration
|
||||
- Server must be running on configured port (default: 5100)
|
||||
- All seven endpoints must be available on AGUIDojoServer
|
||||
- Azure OpenAI credentials configured in AGUIDojoServer
|
||||
|
||||
## Implementation Timeline
|
||||
|
||||
### Phase 1 (Structure): 2-3 hours
|
||||
- Create component structure
|
||||
- Set up routing
|
||||
- Create demo service
|
||||
|
||||
### Phase 2 (Core Components): 3-4 hours
|
||||
- Build DemoSidebar
|
||||
- Build DemoViewTabs
|
||||
- Build Demo.razor container
|
||||
|
||||
### Phase 3 (Scenarios): 4-6 hours
|
||||
- Implement all seven scenario components
|
||||
- Reuse/adapt existing chat components
|
||||
|
||||
### Phase 4 (Code/Docs): 2-3 hours
|
||||
- Build code viewer
|
||||
- Build docs viewer
|
||||
- Create documentation content
|
||||
|
||||
### Phase 5 (Styling): 2-3 hours
|
||||
- Implement responsive layout
|
||||
- Style components
|
||||
- Add loading states
|
||||
|
||||
### Phase 6 (Testing): 2-3 hours
|
||||
- Manual testing
|
||||
- Bug fixes
|
||||
- Refinements
|
||||
|
||||
**Total Estimated Time**: 15-22 hours
|
||||
|
||||
## Conclusion
|
||||
|
||||
This plan provides a comprehensive roadmap for building a simplified Blazor version of the AG-UI dojo. By following this plan, we'll create an educational and interactive platform that showcases the capabilities of the Microsoft Agent Framework's AG-UI integration. The modular structure ensures maintainability and extensibility for future enhancements.
|
||||
Reference in New Issue
Block a user