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
- Always use within ArtifactProvider: The hook will throw if used outside provider
- Handle storage errors: localStorage may fail in private browsing modes
- Scope by assistant: Use assistantId to prevent cross-contamination
- Check tool availability: Verify βartifactsβ tool is enabled before API calls
- 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)))
Related Components
- ArtifactDisplay - Renders individual artifacts
- ArtifactPreview - Sandboxed preview component
- ArtifactPanel - Artifact management panel
- StreamingContext - Real-time artifact updates during streaming
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.