Artifact Context System

🎨 Complete artifact management system for AI-generated content with localStorage persistence and real-time updates.

Overview

The ArtifactContext provides a centralized system for managing AI-generated artifacts (code snippets, documents, visualizations) with persistent storage, CRUD operations, and seamless integration with AI assistants. It supports per-assistant artifact collections and automatic API formatting.

Core Features

  • Persistent Storage: Assistant-specific localStorage with automatic save/load
  • Real-time Management: Add, update, remove, and clear artifacts
  • Active Selection: Track currently selected artifact with panel state
  • API Integration: Format artifacts for AI assistant consumption
  • Cross-Assistant Support: Load artifacts from different assistants

Usage

Basic Setup

import { ArtifactProvider, useArtifacts } from '@/contexts/ArtifactContext'

// Wrap your app with the provider
<ArtifactProvider assistantId="assistant-123">
  <MyApp />
</ArtifactProvider>

Using the Hook

function MyComponent() {
  const {
    artifacts,
    activeArtifactId,
    setActiveArtifactId,
    updateArtifact,
    addArtifact,
    removeArtifact,
    clearArtifacts,
    getArtifactsForApi,
    isPanelOpen,
    setPanelOpen
  } = useArtifacts()

  // Add a new artifact
  const handleAddArtifact = () => {
    addArtifact({
      id: 'artifact-123',
      title: 'My Component',
      type: 'react',
      content: '<div>Hello World</div>'
    })
  }

  // Update existing artifact
  const handleUpdateArtifact = () => {
    updateArtifact('artifact-123', '<div>Updated content</div>')
  }

  return (
    <div>
      <p>Total artifacts: {artifacts.size}</p>
      <button onClick={handleAddArtifact}>Add Artifact</button>
    </div>
  )
}

API Reference

ArtifactProvider Props

Prop Type Description Required
children ReactNode Child components Yes
assistantId string Assistant identifier for storage scoping No

ArtifactContextType

State Properties

Property Type Description
artifacts Map<string, ArtifactData> Current artifacts collection
activeArtifactId string | null Currently selected artifact ID
isPanelOpen boolean Artifact panel visibility state

Artifact Operations

Method Signature Description
addArtifact (artifact: ArtifactData) => void Add new artifact and auto-select if none active
updateArtifact (id: string, content: string, type?: string) => void Update artifact content and optionally type
removeArtifact (id: string) => void Remove artifact and handle active selection
clearArtifacts () => void Remove all artifacts and reset state

Selection Management

Method Signature Description
setActiveArtifactId (id: string | null) => void Set currently active artifact
setPanelOpen (open: boolean) => void Control panel visibility

API Integration

Method Signature Description
getArtifactsForApi (assistantId?: string, tools?: string[]) => string Format artifacts for AI assistant consumption

ArtifactData Interface

interface ArtifactData {
  id: string        // Unique identifier
  title: string     // Display title
  type: string      // Artifact type (react, javascript, html, etc.)
  content: string   // Raw content
}

Storage Strategy

Per-Assistant Storage

Artifacts are stored in localStorage using assistant-specific keys:

// Storage key format
const storageKey = assistantId ? 
  `aitana-artifacts-${assistantId}` : 
  'aitana-artifacts'

// Example keys
'aitana-artifacts-assistant-123'
'aitana-artifacts-assistant-456'
'aitana-artifacts' // Default when no assistantId

Automatic Save/Load

  • Load: Artifacts are loaded from localStorage on mount or when assistantId changes
  • Save: Artifacts are automatically saved whenever the collection changes
  • Error Handling: localStorage errors are logged as warnings, not thrown

Advanced Features

Cross-Assistant Access

The getArtifactsForApi method can load artifacts from different assistants:

// Get artifacts for specific assistant
const artifactsForApi = getArtifactsForApi('other-assistant-id', ['artifacts'])

// Uses current assistant if no ID provided
const currentArtifacts = getArtifactsForApi(undefined, ['artifacts'])

Tool Integration

Artifacts are only included in API calls when the β€˜artifacts’ tool is enabled:

// Only includes artifacts if 'artifacts' tool is in the tools array
const formattedArtifacts = getArtifactsForApi(assistantId, ['artifacts', 'other-tools'])

// Returns empty string if 'artifacts' tool not enabled
const noArtifacts = getArtifactsForApi(assistantId, ['other-tools'])

API Output Format

The getArtifactsForApi method returns artifacts in a standardized XML-like format:

// Returns format: 'Current artifacts:\n' + artifactStrings
const apiContent = getArtifactsForApi(assistantId, ['artifacts'])
// Example output:
// Current artifacts:
// <artifact id="component-1" title="Button Component" type="react">...</artifact>
// <artifact id="script-2" title="Data Processor" type="javascript">...</artifact>

State Management Patterns

Active Artifact Selection

When artifacts are removed, the context intelligently handles active selection:

// If removing active artifact, select first remaining or clear
removeArtifact(activeArtifactId) // Automatically selects next available

Panel State

The panel state is independent of artifact operations:

// Adding artifacts doesn't auto-open panel (prevents unwanted opens)
addArtifact(newArtifact) // Panel stays closed
setPanelOpen(true)       // User must explicitly open

Integration Examples

With Streaming Context

function ChatComponent() {
  const { addArtifact } = useArtifacts()
  const { sendMessage } = useStreaming()

  const handleArtifactReceived = (artifacts: ArtifactData[]) => {
    artifacts.forEach(artifact => addArtifact(artifact))
  }

  return <StreamingInterface onArtifacts={handleArtifactReceived} />
}

With Firebase Persistence

function PersistentArtifacts() {
  const { artifacts, addArtifact } = useArtifacts()
  
  // Save to Firebase when artifacts change
  useEffect(() => {
    if (artifacts.size > 0) {
      saveArtifactsToFirebase(Array.from(artifacts.values()))
    }
  }, [artifacts])

  return <ArtifactDisplay />
}

Error Handling

The context includes comprehensive error handling:

// localStorage errors are handled gracefully
const loadArtifactsFromStorage = (assistantId?: string) => {
  try {
    // ... load logic
  } catch (error) {
    console.warn('Failed to load artifacts from localStorage:', error)
    return new Map() // Returns empty map on error
  }
}

Performance Considerations

  • Lazy Loading: Artifacts are only loaded when assistantId changes
  • Efficient Updates: Uses Map for O(1) artifact access
  • Memory Management: localStorage prevents memory leaks between sessions
  • Selective API Formatting: Only formats artifacts when tool is enabled

Best Practices

  1. Always use within ArtifactProvider: The hook will throw if used outside provider
  2. Handle storage errors: localStorage may fail in private browsing modes
  3. Scope by assistant: Use assistantId to prevent cross-contamination
  4. Check tool availability: Verify β€˜artifacts’ tool is enabled before API calls
  5. Manage panel state: Don’t auto-open panels to avoid user experience issues

Troubleshooting

Common Issues

Artifacts not persisting

  • Check if localStorage is available
  • Verify assistantId is consistent between sessions

Artifacts not appearing in API

  • Ensure β€˜artifacts’ tool is included in tools array
  • Check if artifacts exist for the specified assistantId

Memory issues

  • Clear artifacts periodically: clearArtifacts()
  • Monitor localStorage usage in browser dev tools

Debug Helpers

// Log current state
console.log('Artifacts:', Array.from(artifacts.entries()))
console.log('Active:', activeArtifactId)
console.log('Panel:', isPanelOpen)

// Test storage
console.log('Storage key:', getStorageKey(assistantId))
console.log('Stored data:', localStorage.getItem(getStorageKey(assistantId)))

Architecture

ArtifactProvider
β”œβ”€β”€ localStorage integration
β”œβ”€β”€ State management (useState with useEffect)
β”œβ”€β”€ Cross-assistant support
└── API formatting

useArtifacts Hook
β”œβ”€β”€ CRUD operations
β”œβ”€β”€ Selection management
β”œβ”€β”€ Panel state control
└── Error boundaries

The ArtifactContext serves as the foundation for the entire artifact system, providing reliable state management and persistence while maintaining separation of concerns with presentation components.