Emissary Component System

Overview

The Emissary Component System is the core frontend architecture for AI assistant interactions in the Aitana platform. It provides a sophisticated, context-driven interface that handles real-time streaming, tool integration, authentication, and message persistence.

Architecture Overview

The Emissary system is built on a multi-layered context architecture designed for performance, maintainability, and extensibility. It consists of several specialized components working together to provide a seamless AI assistant experience.

Core Components

Primary Components

  1. EmissaryOptimized.tsx - Main optimized assistant interface
  2. EmissaryChoose.tsx - Assistant selection carousel
  3. EmissaryList.tsx - Full-featured assistant management interface
  4. EmissaryListCompact.tsx - Compact variant for limited space
  5. EmissaryListMinimal.tsx - Minimal variant for simple displays
  6. EmissaryLoading.tsx - Loading states and transitions
  7. EmissaryEmptyState.tsx - Empty states when no assistants available

EmissaryOptimized - Primary Component

Component Architecture

The EmissaryOptimized component is the central hub for AI assistant interactions, designed with performance optimization and clean separation of concerns.

Key Features:

  • Optimized Context Integration: Uses multiple specialized contexts
  • Real-time Streaming: Handles streaming AI responses
  • Tool Integration: Manages tool confirmations and configurations
  • Authentication Flow: Handles login/logout with Firebase
  • Message Persistence: Integrates with Firestore for chat history
  • Artifact System: Supports interactive artifacts display

Props Interface (Actual Implementation)

export type EmissaryOptimizedProps = {
  name?: string;
  avatar?: string;
  assistantId: string;
  initialMessage?: string;
  initialDocuments?: Document[];
  initialInstructions?: string;
  adminEmail?: string;
  senderName?: string;
  userState: UserState;
  currentUser: User | null;
  showLoginDialog: boolean;
  setShowLoginDialog: (show: boolean) => void;
  handleLogout: () => Promise<void>;
  tools?: string[];
  toolConfigs?: Record<string, Record<string, any>>;
  accessControl?: AccessControl;
  templateId?: string;
};

Usage Example

import { EmissaryOptimized } from '@/components/EmissaryOptimized';

function ChatPage() {
  return (
    <EmissaryOptimized
      assistantId="data-analyst"
      showArtifacts={true}
      showThinking={false}
      onMessageUpdate={(messages) => {
        // Handle message updates
        console.log('Messages updated:', messages.length);
      }}
    />
  );
}

Context Architecture

The Emissary system uses a sophisticated multi-context architecture for optimal performance and state management.

Context Hierarchy (Actual Implementation)

<OptimizedContextProvider>
  <MessageStreamingProvider>
    <ToolConfirmationProvider>
      <EmissaryOptimized />
    </ToolConfirmationProvider>
  </MessageStreamingProvider>
</OptimizedContextProvider>

Note: The actual implementation uses OptimizedContextProvider that wraps multiple specialized contexts internally. The component accesses these via optimized hooks like useMessageState(), useStreaming(), useToolState(), etc.

Context Responsibilities

OptimizedContextProvider

  • Purpose: Root context wrapper with performance optimizations
  • Features: Memoization, batched updates, subscription management
  • Use Case: Wraps entire Emissary component tree

SessionContext

  • Purpose: User authentication and session management
  • Features: Firebase auth integration, user state, permissions
  • Data: User profile, authentication status, session metadata

AssistantContext

  • Purpose: Assistant configuration and metadata management
  • Features: Assistant loading, configuration caching, validation
  • Data: Assistant config, capabilities, model settings

MessageStateContext

  • Purpose: Core message state management
  • Features: Message CRUD operations, history management, validation
  • Data: Message array, loading states, error handling

MessageStreamingContext (Actual Implementation)

  • Purpose: Real-time streaming message handling and Firestore integration
  • Features: Reducer-based state management, abort controllers, automatic session management
  • Interface:
    interface MessageStreamingContextType {
      // State
      messages: Message[];
      streamingMessage: LocalChatMessage | null;
      effectiveThinkingContent: string;
      isStreaming: boolean;
      error: string | null;
      sessionId: string;
      traceId: string | null;
      selectedItems?: SelectedItem[];
        
      // Actions
      sendMessage: (text: string) => Promise<void>;
      sendToolConfirmationMessage: (
        userMessage: string, 
        confirmedTools: FirstImpressionTool[], 
        traceId: string,
        signal: AbortSignal
      ) => Promise<void>;
      stopStreaming: () => void;
      clearError: () => void;
    }
    

ToolStateContext

  • Purpose: Tool configuration and permission management
  • Features: Tool availability, permission checking, configuration
  • Data: Available tools, user permissions, tool settings

ToolConfirmationContext (Actual Implementation)

  • Purpose: Tool confirmation workflow management
  • Features: Confirmation state management, deduplication, abort handling
  • Interface:
    interface ToolConfirmationState {
      isWaitingForConfirmation: boolean;
      pendingTools: FirstImpressionTool[] | null;
      confirmedTools: FirstImpressionTool[] | null;
      confirmationId: string | null;
      isProcessingConfirmation: boolean;
    }
      
    // Actions
    setPendingConfirmation(tools, confirmationId)
    confirmTools(tools)
    rejectTools()
    processToolConfirmation(assistantConfig)
    abortToolConfirmation()
    clearConfirmation()
    

ArtifactContext

  • Purpose: Artifact display and interaction management
  • Features: Artifact rendering, editing, persistence
  • Data: Active artifacts, editing state, display preferences

State Management Patterns

Message State Flow

// Message creation flow
const addMessage = useCallback(async (content: string) => {
  // 1. Add optimistic message
  const tempMessage = createTempMessage(content);
  updateMessages(prev => [...prev, tempMessage]);
  
  // 2. Send to backend via streaming
  const stream = await sendToVACService(content, chatHistory);
  
  // 3. Process streaming response
  for await (const chunk of stream) {
    if (chunk.type === 'content') {
      updateStreamingContent(chunk.content);
    } else if (chunk.type === 'tool_confirmation') {
      triggerToolConfirmation(chunk.tools);
    }
  }
  
  // 4. Finalize and persist
  const finalMessage = finalizeMSesage(tempMessage, streamContent);
  await persistToFirestore(finalMessage);
}, [chatHistory, updateMessages]);

Tool Confirmation Flow

// Tool confirmation workflow
const handleToolConfirmation = useCallback(async (tools: Tool[]) => {
  // 1. Show confirmation dialog
  setToolConfirmationState({
    show: true,
    tools: tools,
    onConfirm: async (approvedTools) => {
      // 2. Send confirmation to backend
      await continueWithTools(approvedTools);
      setToolConfirmationState({ show: false });
    },
    onDeny: () => {
      // 3. Cancel tool execution
      cancelToolExecution();
      setToolConfirmationState({ show: false });
    }
  });
}, []);

Component Variants

EmissaryChoose - Assistant Selection

Purpose: Provides a carousel interface for selecting assistants from available templates.

Features:

  • Visual assistant thumbnails with avatars
  • Category filtering and search
  • Assistant capability preview
  • Quick selection and launch

Usage:

<EmissaryChoose
  onAssistantSelect={(assistantId) => {
    // Navigate to selected assistant
    router.push(`/assistant/${assistantId}`);
  }}
  showCategories={true}
  filterByUserPermissions={true}
/>

EmissaryList - Full Management Interface

Purpose: Comprehensive assistant management with list/grid views, creation, editing, and organization.

Features:

  • List and grid view modes
  • Assistant creation and editing
  • Bulk operations and organization
  • Advanced filtering and sorting
  • Permission management integration

Usage:

<EmissaryList
  viewMode="grid"
  showCreateButton={true}
  allowEditing={userPermissions.canEdit}
  onAssistantUpdate={(assistant) => {
    // Handle assistant updates
    invalidateAssistantCache(assistant.id);
  }}
/>

EmissaryListCompact - Space-Efficient Display

Purpose: Compact display variant for sidebars, mobile views, or embedded contexts.

Features:

  • Minimal visual footprint
  • Essential information only
  • Quick actions and navigation
  • Responsive design optimized

EmissaryListMinimal - Essential Display

Purpose: Minimal variant showing only basic assistant information and selection.

Features:

  • Text-only display
  • Basic selection functionality
  • Optimal for accessibility
  • Minimal resource usage

Integration Patterns

Frontend Page Integration

// In app/assistant/[assistantId]/page.tsx
import { EmissaryOptimized } from '@/components/EmissaryOptimized';

export default function AssistantPage({ params }: { params: { assistantId: string } }) {
  return (
    <OptimizedContextProvider>
      <div className="flex h-screen">
        <Sidebar />
        <main className="flex-1">
          <EmissaryOptimized
            assistantId={params.assistantId}
            showArtifacts={true}
            showThinking={false}
          />
        </main>
      </div>
    </OptimizedContextProvider>
  );
}

Shared Page Integration

// In components/SharePage.tsx
import { EmissaryOptimized } from '@/components/EmissaryOptimized';

export function SharePage({ shareData }: { shareData: ShareData }) {
  return (
    <EmissaryOptimized
      assistantId={shareData.assistantId}
      initialMessages={shareData.messages}
      showArtifacts={shareData.includeArtifacts}
      className="h-full w-full"
    />
  );
}

Performance Optimizations

Context Optimization Strategies

  1. Selective Subscriptions: Components subscribe only to relevant context slices
  2. Memoization: Expensive computations are memoized across renders
  3. Batch Updates: Multiple state updates are batched to prevent cascading renders
  4. Lazy Loading: Contexts are loaded on-demand when components need them

Component-Level Optimizations

// Example optimization patterns
const EmissaryOptimized = memo(({ assistantId, ...props }) => {
  // Memoize expensive calculations
  const assistantConfig = useMemo(() => 
    getAssistantConfig(assistantId), [assistantId]
  );
  
  // Debounce frequent updates
  const debouncedUpdate = useMemo(() => 
    debounce(updateMessages, 300), []
  );
  
  // Use callback refs for dynamic elements
  const messageContainerRef = useCallback((node) => {
    if (node) {
      // Scroll to bottom on new messages
      node.scrollTop = node.scrollHeight;
    }
  }, [messages.length]);
  
  return (
    <div ref={messageContainerRef}>
      {/* Component content */}
    </div>
  );
});

Styling and Theming

Tailwind Integration

The Emissary components use a consistent Tailwind CSS design system:

// Standard styling patterns
const emissaryStyles = {
  container: "flex flex-col h-full bg-background text-foreground",
  messageList: "flex-1 overflow-y-auto px-4 py-6 space-y-4",
  inputArea: "border-t border-border p-4 bg-card",
  loadingSpinner: "animate-spin h-6 w-6 text-primary",
  errorBoundary: "bg-destructive/10 border border-destructive/20 rounded-lg p-4"
};

Component Variants

// Responsive variants
const variants = {
  default: "w-full max-w-4xl mx-auto",
  compact: "w-full max-w-2xl",
  fullscreen: "w-full h-screen",
  embedded: "w-full h-96 min-h-96"
};

Error Handling

Error Boundaries

// EmissaryErrorBoundary component
export function EmissaryErrorBoundary({ children }: { children: React.ReactNode }) {
  return (
    <ErrorBoundary
      fallback={(error, retry) => (
        <div className="p-8 text-center">
          <h2 className="text-lg font-semibold mb-2">Something went wrong</h2>
          <p className="text-muted-foreground mb-4">{error.message}</p>
          <Button onClick={retry}>Try again</Button>
        </div>
      )}
    >
      {children}
    </ErrorBoundary>
  );
}

Graceful Degradation

// Service degradation patterns
const useEmissaryWithFallback = (assistantId: string) => {
  const [error, setError] = useState<Error | null>(null);
  const [fallbackMode, setFallbackMode] = useState(false);
  
  const handleError = useCallback((error: Error) => {
    console.error('Emissary error:', error);
    setError(error);
    
    // Enable fallback mode for network errors
    if (error.name === 'NetworkError') {
      setFallbackMode(true);
    }
  }, []);
  
  return {
    error,
    fallbackMode,
    handleError,
    isOnline: navigator.onLine
  };
};

Testing Strategy

Component Testing

// Example test structure
describe('EmissaryOptimized', () => {
  it('should render with assistant configuration', async () => {
    render(
      <EmissaryOptimized
        assistantId="test-assistant"
        showArtifacts={true}
      />
    );
    
    await waitFor(() => {
      expect(screen.getByRole('main')).toBeInTheDocument();
    });
  });
  
  it('should handle message sending', async () => {
    const mockSend = vi.fn();
    render(<EmissaryOptimized onMessageUpdate={mockSend} />);
    
    const input = screen.getByRole('textbox');
    fireEvent.change(input, { target: { value: 'Hello' } });
    fireEvent.submit(input.closest('form')!);
    
    await waitFor(() => {
      expect(mockSend).toHaveBeenCalled();
    });
  });
});

Context Testing

// Context testing patterns
describe('MessageStateContext', () => {
  it('should manage message state correctly', () => {
    const { result } = renderHook(() => useMessageState(), {
      wrapper: MessageStateProvider
    });
    
    act(() => {
      result.current.addMessage('Hello');
    });
    
    expect(result.current.messages).toHaveLength(1);
    expect(result.current.messages[0].content).toBe('Hello');
  });
});

Migration and Upgrade Guide

From Legacy Components

If migrating from older assistant components:

  1. Update imports to use new component paths
  2. Wrap with contexts using OptimizedContextProvider
  3. Update prop interfaces to match new API
  4. Test streaming integration thoroughly
  5. Verify tool confirmation workflow

Breaking Changes

v2.0 Changes:

  • Context architecture requires explicit provider wrapping
  • Message format includes additional metadata fields
  • Tool confirmation is now required by default
  • Authentication context is mandatory

Best Practices

Development Guidelines

  1. Always wrap with contexts: Use OptimizedContextProvider for all Emissary components
  2. Handle loading states: Provide appropriate loading indicators
  3. Implement error boundaries: Graceful error handling is essential
  4. Optimize subscriptions: Subscribe only to needed context slices
  5. Test streaming scenarios: Ensure proper handling of real-time updates

Performance Recommendations

  1. Memoize expensive operations: Use useMemo for complex calculations
  2. Debounce user inputs: Prevent excessive API calls
  3. Lazy load components: Use React.lazy for large assistant lists
  4. Monitor context updates: Use dev tools to identify unnecessary re-renders
  5. Optimize bundle size: Tree-shake unused Emissary variants

Accessibility Guidelines

  1. Keyboard navigation: Full keyboard support for all interactions
  2. Screen reader support: Proper ARIA labels and descriptions
  3. Focus management: Logical focus flow during interactions
  4. Color contrast: Meet WCAG 2.1 AA standards
  5. Reduced motion: Respect user motion preferences

Troubleshooting

Common Issues

Context Not Available Error

Error: useMessageState must be used within a MessageStateProvider

Solution: Wrap component with OptimizedContextProvider

Streaming Connection Failures

Error: Failed to connect to streaming endpoint

Solution: Check network connectivity and backend service status

Tool Confirmation Timeout

Error: Tool confirmation timed out

Solution: Increase timeout or implement retry logic

Memory Leaks in Development

Warning: Memory leak detected in component

Solution: Ensure proper cleanup in useEffect hooks

Debugging Tools

  1. React Developer Tools: Inspect context state and prop changes
  2. Network Tab: Monitor streaming connections and API calls
  3. Console Logging: Enable debug mode with NEXT_PUBLIC_DEBUG=true
  4. Performance Profiler: Identify rendering bottlenecks

Future Roadmap

Planned Enhancements

  • Enhanced Accessibility: WCAG 2.1 AAA compliance
  • Offline Support: Service worker integration for offline functionality
  • Advanced Theming: Dynamic theme switching and custom themes
  • Plugin System: Extensible architecture for custom tools and features
  • Real-time Collaboration: Multi-user assistant sessions
  • Mobile Optimization: Native mobile app integration