Artifact System

This document describes the artifact system that allows users to extract, view, edit, and persist structured content from AI responses.

Overview

The artifact system extracts special <artifact> tags from AI model responses and presents them in an interactive side panel. Users can view, edit, copy, and download these artifacts. All edits are automatically persisted in localStorage and included in subsequent API calls.

Architecture

Components

  • ArtifactPanel - Main UI component with preview/edit tabs
  • ArtifactToggleButton - Header button to show/hide panel
  • ArtifactContext - State management and persistence
  • artifactExtractor.ts - Utility for parsing artifact tags
  • Artifact.tsx - Markdown component for rendering artifact buttons

Data Flow

  1. AI model includes <artifact> tags in responses
  2. artifactExtractor parses tags during streaming
  3. ArtifactContext stores artifacts in memory + localStorage
  4. ArtifactPanel displays artifacts with edit capabilities
  5. Edited artifacts are included in subsequent API calls

Artifact Tag Format

AI models should output artifacts using this format:

<artifact id="unique-id" title="Artifact Title" type="artifact-type">
Content goes here
</artifact>

Supported Parameters

  • id (required) - Unique identifier for the artifact
  • title (required) - Human-readable title displayed in UI
  • type (required) - Content type (markdown, html, javascript, python, react, jsx, tsx, etc.)

Example

<artifact id="shopping-list" title="Weekly Shopping List" type="markdown">
# Weekly Shopping List

## Groceries
- Milk
- Bread
- Eggs

## Household
- Laundry detergent
- Paper towels
</artifact>

API Integration

Including Artifacts in API Calls

When artifacts exist, they are automatically appended to user messages sent to the API:

const userMessage = originalMessage + artifactContext.getArtifactsForApi();

API Format

Original user message here

Current artifacts:
<artifact id="shopping-list" title="Weekly Shopping List" type="markdown">
# Weekly Shopping List (EDITED)

## Groceries
- Milk (2% organic)
- Bread (whole grain)
- Eggs (dozen)

## Household
- Laundry detergent
- Paper towels
</artifact>
<artifact id="recipe" title="Pasta Recipe" type="markdown">
# Simple Pasta Recipe

## Ingredients
- 1 lb pasta
- 2 cups marinara sauce
- 1/2 cup parmesan cheese
</artifact>

Multiple Artifacts Handling

Storage and Management

  • Artifacts stored in Map<string, ArtifactData> for O(1) lookup
  • Each artifact has unique ID to prevent conflicts
  • Active artifact tracked separately for UI focus

UI Features

  • Artifact selector dropdown when multiple artifacts exist
  • Navigation between artifacts while maintaining edits
  • Bulk operations like copy/download for active artifact
  • Auto-selection of new artifacts when added

API Inclusion

All artifacts (original + edited) are included in API calls:

const getArtifactsForApi = (): string => {
  if (artifacts.size === 0) return '';
  
  const artifactStrings = Array.from(artifacts.values()).map(artifact => 
    `<artifact id="${artifact.id}" title="${artifact.title}" type="${artifact.type}">${artifact.content}</artifact>`
  );
  
  return '\n\nCurrent artifacts:\n' + artifactStrings.join('\n');
};

Persistence

localStorage Implementation

  • Storage key: 'aitana-artifacts'
  • Format: JSON object with artifact IDs as keys
  • Automatic saving: Triggered on any artifact change
  • Automatic loading: Restored on page/app restart

Data Structure

interface ArtifactData {
  id: string;        // Unique identifier
  title: string;     // Display title
  type: string;      // Content type
  content: string;   // Editable content (may be modified from original)
}

Storage Example

{
  "shopping-list": {
    "id": "shopping-list",
    "title": "Weekly Shopping List", 
    "type": "markdown",
    "content": "# Weekly Shopping List (EDITED)\n\n## Groceries\n- Milk (2% organic)"
  },
  "recipe": {
    "id": "recipe",
    "title": "Pasta Recipe",
    "type": "markdown", 
    "content": "# Simple Pasta Recipe\n\n## Ingredients\n- 1 lb pasta"
  }
}

User Interface

Panel Layout

┌─────────────────────────────────┐
│ Artifacts (2)              [×]  │ ← Header with count
├─────────────────────────────────┤
│ [Artifact Selector Dropdown]    │ ← Multi-artifact navigation
├─────────────────────────────────┤
│ Title: Weekly Shopping List     │ ← Current artifact info
│ Type: markdown                  │
├─────────────────────────────────┤
│ [Preview] [Edit]                │ ← Tab switcher
├─────────────────────────────────┤
│                                 │
│ Scrollable content area         │ ← Preview/edit content
│                                 │
└─────────────────────────────────┘

Features

  • Preview tab: Rendered markdown with syntax highlighting
  • Edit tab: Large textarea with monospace font
  • Copy functionality: Preserves formatting using hybrid copy
  • Download: Saves as appropriate file extension (.md, .py, etc.)
  • Auto-scroll: Smooth scrolling within panel boundaries
  • Responsive: Adapts to different screen sizes

Integration Points

Streaming Context

// In StreamingContext, artifacts are extracted during streaming
const onArtifactContent = useCallback((artifacts: ArtifactData[]) => {
  artifacts.forEach(artifact => {
    artifactContext.addArtifact(artifact);
  });
}, []);

Chat Interface

// ArtifactPanel is included in ChatInterface
<ChatInterface {...props} />
<ArtifactPanel 
  onArtifactUpdate={updateArtifact}
  hideToggleButton={true} 
/>

Header Integration

// ArtifactToggleButton in page headers
<div className="flex items-center gap-2">
  <ArtifactToggleButton />
  {/* other header buttons */}
</div>

File Extensions Mapping

The system automatically determines file extensions for downloads:

const getFileExtension = (type: string): string => {
  switch (type.toLowerCase()) {
    case 'markdown': case 'md': return 'md';
    case 'html': return 'html';
    case 'javascript': case 'js': return 'js';
    case 'typescript': case 'ts': return 'ts';
    case 'python': case 'py': return 'py';
    case 'json': return 'json';
    case 'yaml': case 'yml': return 'yml';
    case 'css': return 'css';
    case 'svg': return 'svg';
    default: return 'txt';
  }
};

Error Handling

Graceful Degradation

  • localStorage failures: Continue in-memory operation
  • Malformed artifacts: Skip parsing errors, continue with valid ones
  • Missing artifact properties: Use sensible defaults

Console Warnings

console.warn('Failed to load artifacts from localStorage:', error);
console.warn('Failed to save artifacts to localStorage:', error);

Best Practices

For AI Models

  1. Use descriptive IDs: user-profile-form not artifact1
  2. Meaningful titles: Help users understand content at a glance
  3. Appropriate types: Use standard file extensions/types
  4. Self-contained content: Artifacts should be complete and useful standalone

For Developers

  1. Test persistence: Verify edits survive page refreshes
  2. Check API inclusion: Ensure edited artifacts reach the model
  3. Handle edge cases: Empty content, duplicate IDs, etc.
  4. Monitor localStorage: Large artifacts may hit storage limits

Interactive Preview Support

React and HTML Artifacts

The artifact system includes an interactive preview feature for web-based artifacts:

Supported Preview Types

  • HTML (type="html") - Renders HTML content directly
  • Browser JavaScript (type="javascript") - Executes client-side JavaScript code only
  • React (type="react" or type="jsx" or type="tsx") - Transpiles and renders React components

Not Supported for Preview

  • Server-side code (Node.js, Express, APIs) - Requires server environment
  • Code with dependencies - npm packages not available in preview
  • Database connections - No backend services available

Preview Features

  • Sandboxed iframe: Code runs in isolation for security
  • Live preview: See your changes immediately
  • Refresh button: Reload the preview
  • Open in new tab: Test in a full browser window
  • Error handling: Clear error messages for debugging

Example React Artifact

<artifact id="counter-app" title="React Counter App" type="react">
function App() {
  const [count, setCount] = React.useState(0);
  
  return (
    <div style={{padding: '20px', fontFamily: 'Arial' }}>
      <h1>Counter: {count}</h1>
      <button 
        onClick={() => setCount(count + 1)}
        style={{padding: '10px 20px', 
          fontSize: '16px',
          marginRight: '10px'
        }}
      >
        Increment
      </button>
      <button 
        onClick={() => setCount(0)}
        style={{padding: '10px 20px', 
          fontSize: '16px'
        }}
      >
        Reset
      </button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
</artifact>

Examples: What Works vs What Doesn’t

✅ Works with Preview (Browser JavaScript):

<artifact id="browser-demo" title="Browser Animation" type="javascript">
// This runs in the browser
let count = 0;
setInterval(() => {
  document.getElementById('root').innerHTML = 
    `<h1>Count: ${count++}</h1>`;
}, 1000);
</artifact>

❌ Won’t Work with Preview (Server Code):

<artifact id="express-server" title="Express.js Server" type="javascript">
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
</artifact>

For server code, the artifact panel will show a helpful message explaining that it needs to be downloaded and run locally.

Security Considerations

  • Previews run in sandboxed iframes with limited permissions
  • No access to parent window or external resources
  • Some browser APIs may be restricted
  • For full functionality, download and run locally

Custom Markdown Components

The artifact panel fully supports all custom markdown components:

  • <preview> - File previews (images, PDFs, etc.)
  • <plot> - Interactive data visualizations
  • <networkgraph> - Network/graph visualizations
  • <alert> - Styled alert messages
  • <tooltip> - Hover tooltips
  • <googlesearch> - Search result displays
  • <toolconfirmation> - Tool execution confirmations
  • <dynamic-ui> - Dynamic UI components

These components work identically in artifacts as they do in the main chat.

Future Enhancements

Potential Features

  • Artifact versioning: Track edit history
  • Collaborative editing: Multi-user artifact sharing
  • Export formats: PDF, Word document generation
  • Enhanced preview: Support for Vue, Angular, and other frameworks
  • Artifact templates: Pre-defined structures for common types
  • Search/filter: Find artifacts across conversations
  • Firestore sync: Cloud persistence option
  • Live collaboration: Real-time multi-user editing

Performance Considerations

  • Lazy loading: Load artifacts on-demand for large collections
  • Content limits: Prevent localStorage overflow
  • Debounced saving: Reduce save frequency during active editing