Skip to content

[Blazor] Components.AI — Multimodal attachments, conversation threads, and form input#66185

Draft
javiercn wants to merge 1 commit intojaviercn/ai-components-shells-themingfrom
javiercn/ai-components-multimodal-threads
Draft

[Blazor] Components.AI — Multimodal attachments, conversation threads, and form input#66185
javiercn wants to merge 1 commit intojaviercn/ai-components-shells-themingfrom
javiercn/ai-components-multimodal-threads

Conversation

@javiercn
Copy link
Copy Markdown
Member

@javiercn javiercn commented Apr 6, 2026

Part of the overall Components.AI design: #66178

Builds on #66184


Conversation Threads, Form Input, and Multimodal Attachments

Summary

Add three capabilities that complete the conversation experience: persistent conversation history via IConversationThread, SSR-compatible form-based input via AgentFormBoundary and FormMessageInput, and file attachment support in messages.

Motivation

Conversation persistence

Without persistence, refreshing the page or navigating away loses the entire conversation. Applications need to store and restore conversation history. The storage mechanism varies, so the library defines a minimal interface rather than a specific implementation.

Static SSR support

Not all Blazor applications use interactive render modes. Static SSR applications render HTML on the server and accept user input via form POST. The core MessageInput uses onclick events requiring an interactive circuit. SSR applications need a form-based alternative.

File attachments

Users frequently need to share images, documents, and files in chat. The LLM receives these as DataContent items alongside text.

Goals

  • Define IConversationThread as a pluggable interface for conversation persistence.
  • Integrate IConversationThread into UIAgent: record messages and updates, restore from history.
  • Provide AgentFormBoundary for SSR form-based chat interactions.
  • Provide FormMessageInput for SSR text input.
  • Support multimodal message submission (text + file attachments).
  • Automatically restore conversation on AgentBoundary initialization when a thread has history.
  • Support stateful LLMs: when ConversationId is set, send only the latest message.

Non-goals

  • Built-in storage implementations (Redis, Cosmos DB, etc.).
  • Real-time synchronization across multiple clients.
  • File upload progress indicators.
  • Server-side file storage — attachments are sent inline as DataContent.

Detailed design

IConversationThread interface

public interface IConversationThread
{
    string ThreadId { get; }
    bool IsStateful { get; }
    string? ConversationId { get; }
    void AppendUserMessage(ChatMessage message);
    void AppendUpdate(ChatResponseUpdate update);
    void CompleteTurn();
    IReadOnlyList<ChatResponseUpdate> GetUpdates();
    IReadOnlyList<ChatMessage> GetMessageHistory();
}

Conversation restore flow

When AgentBoundary initializes with a thread that has persisted updates, it calls RestoreAsync() which replays persisted ChatResponseUpdate objects through the pipeline, rebuilding the conversation turns.

SSR form-based input

AgentFormBoundary binds via [SupplyParameterFromForm]:

  • UserMessage — text from the input.
  • BlockAction — approval actions (format: "approve:blockId" or "reject:blockId").

Multimodal attachment flow

MessageInput supports file attachments when AllowAttachments=true. Files are read as byte[], stored as AttachedFile objects, and sent as DataContent items alongside TextContent. Max 10MB per file.

Stateful LLM support

When IConversationThread.IsStateful is true and ConversationId is set, UIAgent sends only the latest message. The LLM service manages history server-side.

Risks

  • Thread data consistency: Mitigated by CompleteTurn() acting as a commit marker.
  • SSR approval race: Mitigated by Blazor's streaming rendering.
  • Large attachment memory: Mitigated by the 10MB limit.

Drawbacks

  • AgentFormBoundary duplicates some logic from AgentBoundary. Accepted because the form boundary has genuinely different initialization logic.
  • FormMessageInput is a separate component from MessageInput because the rendering is fundamentally different.

Test coverage

288 tests (cumulative) covering:

  • IConversationThread contract: append, read, commit lifecycle.
  • UIAgent thread integration: message recording, update recording, restore replay.
  • AgentContext restore: turn reconstruction from thread history.
  • AgentFormBoundary form submission: text messages, approval actions, rejection actions.
  • FormMessageInput rendering: disabled state, placeholder, name attribute.
  • MessageInput attachments: file selection, preview, removal, size limit, submission with DataContent.
  • Stateful LLM scenario: ConversationId propagation.

Add cross-cutting features:
- IConversationThread for conversation storage, restore, and new conversation support
- RestoreAsync on UIAgent and AgentContext for replaying thread history
- AgentFormBoundary and FormMessageInput for SSR form-based input
- MessageInput attachment support using InputFile (no JS interop)
- Thread integration tests and form component tests
@javiercn javiercn force-pushed the javiercn/ai-components-multimodal-threads branch from 6fe25dd to 19b72f3 Compare April 6, 2026 20:27
@javiercn javiercn force-pushed the javiercn/ai-components-shells-theming branch from c649146 to 08e98cf Compare April 6, 2026 20:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant