THINKING_PANEL_COMPONENT.md

Component documentation for the ThinkingPanel AI reasoning display.

Overview

The ThinkingPanel component provides a dedicated interface for viewing AI reasoning and thought processes. It extracts, processes, and displays “thinking” content from chat messages, allowing users to understand how AI assistants approach problems and make decisions.

Component Location

  • File: src/components/ThinkingPanel.tsx
  • Type: Display Panel Component
  • Framework: React with TypeScript

Features

  • Intelligent Content Extraction: Automatically extracts thinking content from messages
  • Nested Tag Handling: Properly processes nested <thinking> tags
  • Multiple Positioning: Supports bottom and right panel positioning
  • Expandable Interface: Collapsible panel with toggle controls
  • Rich Formatting: Markdown rendering with GitHub Flavored Markdown
  • Temporal Context: Shows timestamps for each thinking session
  • Responsive Design: Adapts to different screen sizes

Props Interface

interface ThinkingPanelProps {
  messages: ChatMessage[];                    // Messages to extract thinking from
  position?: 'bottom' | 'right';            // Panel positioning (default: 'bottom')
  className?: string;                        // Additional CSS classes
}

Usage Examples

Basic Implementation

import ThinkingPanel from '@/components/ThinkingPanel';

function ChatLayout({ messages }) {
  return (
    <div className="chat-container">
      <div className="messages-area">
        {/* Chat messages */}
      </div>
      
      <ThinkingPanel 
        messages={messages}
        position="bottom"
      />
    </div>
  );
}

Right-Side Panel

<div className="flex">
  <div className="flex-1">
    {/* Main content */}
  </div>
  
  <ThinkingPanel 
    messages={messages}
    position="right"
    className="border-l-2"
  />
</div>

Conditional Display

function EnhancedChat({ messages, showThinking }) {
  return (
    <div>
      {/* Chat interface */}
      {showThinking && (
        <ThinkingPanel messages={messages} />
      )}
    </div>
  );
}

Thinking Content Extraction

The component uses sophisticated regex to extract thinking content:

/**
 * Extracts content from innermost <thinking> tags in a message
 * Handles nested thinking tags by extracting only innermost content
 */
const extractThinkingContent = (content: string): string | null => {
  // Regex finds innermost thinking tags (those that don't contain other thinking tags)
  const innermostTagsRegex = /<thinking>((?:[^<]|<(?!thinking>))*?)<\/thinking>/g;
  const results: string[] = [];
  let match: RegExpExecArray | null;
  
  // Find all innermost tags in a single pass
  while ((match = innermostTagsRegex.exec(content)) !== null) {
    results.push(match[1]);
  }
  
  if (results.length === 0) return null;
  return results.join('\n\n');
};

Extraction Examples

<!-- Simple case -->
<thinking>This is a simple thought</thinking>

<!-- Multiple thinking blocks -->
<thinking>First thought</thinking>
Some other content
<thinking>Second thought</thinking>

<!-- Nested thinking (extracts innermost) -->
<thinking>
  Outer thought
  <thinking>Inner thought that gets extracted</thinking>
  More outer content
</thinking>

Message Processing

The component processes messages to create thinking entries:

useEffect(() => {
  const newThinkingMessages = messages
    .map(message => {
      const thinkingContent = extractThinkingContent(message.content);
      if (!thinkingContent) return null;
      
      return {
        messageId: `${message.sender}-${message.timestamp}`,
        senderName: message.userName || message.sender,
        timestamp: message.timestamp || Date.now(),
        content: thinkingContent
      };
    })
    .filter(Boolean);
  
  setThinkingMessages(newThinkingMessages);
}, [messages]);

Panel Positioning

Bottom Panel Configuration

const bottomPanelStyles = {
  container: 'fixed bottom-0 left-0 right-0 z-40',
  header: 'flex items-center justify-between p-2 border-t bg-background',
  body: 'max-h-[300px]',
  expandButton: 'absolute -top-8 right-4 bg-background border rounded-t-md'
};

Right Panel Configuration

const rightPanelStyles = {
  container: 'fixed top-16 bottom-0 right-0 z-40 w-80',
  header: 'flex items-center justify-between p-2 border-l bg-background',
  body: 'h-full',
  expandButton: 'absolute -left-8 top-4 bg-background border rounded-l-md'
};

Component Structure

Toggle Button

<Button
  variant="ghost"
  size="sm"
  className={panelStyles.expandButton}
  onClick={() => setIsExpanded(!isExpanded)}
>
  {position === 'bottom' ? (
    isExpanded ? <ChevronDown /> : <ChevronUp />
  ) : (
    <ChevronDown />
  )}
  <span className="ml-1 text-xs">Thinking</span>
</Button>

Panel Header

<div className={panelStyles.header}>
  <h3 className="text-sm font-medium">Thinking Process</h3>
  <Button variant="ghost" size="sm" onClick={() => setIsExpanded(false)}>
    <X className="h-4 w-4" />
  </Button>
</div>

Content Area

<ScrollArea className={panelStyles.body}>
  <div className="p-3 space-y-4">
    {thinkingMessages.map(msg => (
      <div key={msg.messageId} className="border-b pb-3 last:border-b-0">
        <div className="flex items-center justify-between mb-1">
          <span className="text-xs font-medium">{msg.senderName}</span>
          <span className="text-xs text-muted-foreground">
            {formatDistanceToNow(msg.timestamp, { addSuffix: true })}
          </span>
        </div>
        
        <div className="prose prose-sm max-w-none text-xs bg-slate-50 p-2 rounded">
          <Markdown
            remarkPlugins={[remarkGfm]}
            rehypePlugins={[rehypeRaw]}
          >
            {msg.content}
          </Markdown>
        </div>
      </div>
    ))}
  </div>
</ScrollArea>

Markdown Configuration

Enhanced markdown rendering for thinking content:

import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';

// Supports:
// - GitHub Flavored Markdown
// - Raw HTML content
// - Code blocks and syntax highlighting
// - Lists, tables, and other rich formatting

Conditional Rendering

The panel only renders when thinking content is found:

// If no thinking content found, don't render anything
if (thinkingMessages.length === 0) {
  return null;
}

Styling Classes

Panel Container

.fixed .z-40                    /* Positioning and z-index */
.bottom-0 .left-0 .right-0      /* Bottom panel positioning */
.top-16 .bottom-0 .right-0 .w-80 /* Right panel positioning */

Content Styling

.prose .prose-sm .max-w-none .text-xs /* Markdown content */
.bg-slate-50 .p-2 .rounded           /* Content background */
.border-b .pb-3 .last:border-b-0     /* Message separation */

Interactive Elements

.absolute .-top-8 .right-4           /* Bottom panel toggle */
.absolute .-left-8 .top-4            /* Right panel toggle */

Accessibility Features

  • Semantic HTML: Proper heading and section structure
  • ARIA Labels: Screen reader friendly controls
  • Keyboard Navigation: Full keyboard support
  • Focus Management: Proper focus handling for expand/collapse

Performance Considerations

  • Efficient Extraction: Single-pass regex for content extraction
  • Memoized Processing: Processes messages only when they change
  • Conditional Rendering: No DOM overhead when no thinking content exists
  • Scroll Optimization: Virtual scrolling for large thinking content

Time Formatting

Uses date-fns for human-readable timestamps:

import { formatDistanceToNow } from 'date-fns';

// Examples:
// "2 minutes ago"
// "1 hour ago"  
// "yesterday"

Error Handling

  • Safe regex processing with null checks
  • Graceful handling of malformed thinking tags
  • Fallback values for missing timestamps or sender names
  • Robust message filtering to prevent render errors

Dependencies

Core Libraries

  • React hooks for state management
  • date-fns for time formatting
  • tailwind-merge for class composition

UI Components

  • @/components/ui/scroll-area for scrollable content
  • @/components/ui/button for controls
  • Lucide icons for UI elements

Markdown Support

  • react-markdown for content rendering
  • remark-gfm for GitHub Flavored Markdown
  • rehype-raw for HTML support
  • Chat message components that contain thinking content
  • AI assistant interfaces
  • Debug and development tools
  • Content analysis components