Skip to content

Latest commit

 

History

History
179 lines (140 loc) · 6.91 KB

File metadata and controls

179 lines (140 loc) · 6.91 KB

ContentBlocks Refactor: Preserving Structured Data Throughout the Pipeline

Overview

This refactor eliminates unnecessary text flattening throughout the AiStudio4 system, ensuring that structured ContentBlocks maintain their integrity from creation through storage to display. The goal was to preserve tool execution data and other structured content so that conversations maintain their rich formatting when reloaded.

The Problem

Text Flattening Destroying Structure

The system had well-designed ContentBlock infrastructure with proper typed content renderers on the frontend, but structured data was being destroyed at multiple points through unnecessary text flattening:

  1. LinearConvMessage used string content instead of ContentBlock[]
  2. MessageHistoryItem used string Content instead of ContentBlock[]
  3. SimpleChatResponse used string ResponseText instead of ContentBlock[]
  4. Multiple services were using string.Join() to flatten ContentBlocks into plain text

Impact on Tool Loops

When tool loops executed:

  • ✅ Tools created proper ContentBlocks with specific types (Tool, ToolResponse, Text, etc.)
  • Storage flattened the structure into plain strings
  • Reload lost all structured data - everything became plain text
  • Frontend couldn't render properly - lost rich formatting for tools, responses, etc.

The frontend contentBlockRendererRegistry was designed to handle structured ContentBlocks but never received them after reload.

The Solution

Core Infrastructure Changes

1. LinearConvMessage - Replaced string content with ContentBlock[]

// BEFORE
public class LinearConvMessage
{
    public string role { get; set; }
    public string content { get; set; }  // ❌ Flattened
}

// AFTER  
public class LinearConvMessage
{
    public string role { get; set; }
    public List<ContentBlock> contentBlocks { get; set; } = new List<ContentBlock>(); // ✅ Structured
}

2. MessageHistoryItem - Replaced string Content with ContentBlock[]

// BEFORE
public class MessageHistoryItem
{
    public string Role { get; set; }
    public string Content { get; set; }  // ❌ Flattened
}

// AFTER
public class MessageHistoryItem
{
    public string Role { get; set; }
    public List<ContentBlock> ContentBlocks { get; set; } = new List<ContentBlock>(); // ✅ Structured
}

3. SimpleChatResponse - Replaced string ResponseText with ContentBlock[]

// BEFORE
public class SimpleChatResponse
{
    public bool Success { get; set; }
    public string ResponseText { get; set; }  // ❌ Flattened
}

// AFTER
public class SimpleChatResponse
{
    public bool Success { get; set; }
    public List<ContentBlock> ContentBlocks { get; set; } = new List<ContentBlock>(); // ✅ Structured
}

Service Layer Updates

4. DefaultChatService - Removed string.Join() flattening

// BEFORE - Flattening ContentBlocks
Content = string.Join("\n\n", msg.ContentBlocks?.Select(cb => cb.Content))

// AFTER - Preserving structure
ContentBlocks = msg.ContentBlocks ?? new List<ContentBlock>()

5. AI Service Providers - Local conversion control

Each AI service now handles ContentBlocks → API format conversion locally:

  • OpenAI.cs: Converts ContentBlocks to OpenAI JSON format
  • Claude.cs: Converts ContentBlocks to Claude JSON format
  • NetOpenAi.cs: Converts ContentBlocks to .NET SDK format
  • LlamaCpp.cs: Converts ContentBlocks to llama.cpp format
  • Gemini.cs: Handles TTS text extraction from ContentBlocks

Updated Components

Files Modified:

  • LinearConversationMessage.cs - Core data structure
  • MessageHistoryItem.cs - History data structure
  • SimpleChatResponse.cs - Response data structure
  • DefaultChatService.cs - Service layer flattening removal
  • ToolResponseProcessor.cs - Message creation updates
  • OpenAI.cs - ContentBlocks → OpenAI API conversion
  • NetOpenAi.cs - ContentBlocks → .NET SDK conversion
  • Claude.cs - ContentBlocks → Claude API conversion
  • LlamaCpp.cs - ContentBlocks → llama.cpp API conversion
  • Gemini.cs - ContentBlocks → Gemini API conversion
  • MessageBuilder.cs - Message building with ContentBlocks
  • AiServiceBase.cs - Base interjection message creation
  • Tools: SecondAiOpinionTool.cs, ModifyFilesUsingMorph.cs, GeminiGoogleSearchTool.cs
  • Services: SecondaryAiService.cs, ChatProcessingService.cs
  • Handlers: ChatRequestHandler.cs

The Result

Tool Loop Integrity Preserved

Now when tool loops execute and are reloaded:

  • Execution: ContentBlocks created with proper types (Tool, ToolResponse, Text, etc.)
  • Storage: ContentBlocks stored as structured data in v4BranchedConversation
  • Reload: ContentBlocks loaded back with original structure intact
  • Display: Frontend contentBlockRendererRegistry renders each type appropriately

Frontend Benefits

The frontend infrastructure was already perfect - it just needed the structured data to not be destroyed:

  • TextContentRenderer: Handles text blocks
  • ToolContentRenderer: Handles tool execution blocks
  • ToolResponseContentRenderer: Handles tool response blocks with rich formatting
  • SystemContentRenderer: Handles system message blocks
  • AiHiddenContentRenderer: Handles hidden AI content blocks

Backward Compatibility

AI service providers maintain their existing API format requirements by converting ContentBlocks locally:

// Example: OpenAI service converts ContentBlocks to required JSON
foreach (var block in message.contentBlocks ?? new List<ContentBlock>())
{
    if (block.ContentType == ContentType.Text)
    {
        messageContent.Add(new JObject
        {
            ["type"] = "text", 
            ["text"] = block.Content ?? ""
        });
    }
    // Handle other content types...
}

Key Benefits

  1. Data Integrity: Structured content preserved throughout entire pipeline
  2. Rich Display: Tool responses, system messages, and other content display properly
  3. Persistence: Conversations maintain formatting after reload
  4. Extensibility: Easy to add new ContentBlock types with custom renderers
  5. Provider Flexibility: Each AI service controls its own format conversion
  6. Frontend Ready: Leverages existing contentBlockRendererRegistry infrastructure

Migration Notes

  • No frontend changes required - the infrastructure was already designed for this
  • AI providers handle conversion locally - each service converts ContentBlocks to its required API format
  • Tool execution data persists - rich tool responses now survive reload
  • Backward compatibility maintained - existing functionality preserved while adding structure

This refactor transforms AiStudio4 from a text-flattening system to a structure-preserving one, enabling rich, persistent conversations that maintain their formatting and tool execution context across sessions.