npm package: @illuma-ai/agentviz
Description: Embeddable agent chat widget — stream LLM responses with DOM extraction, theming, and markdown rendering
Latest version: 1.0.1

# @illuma-ai/agentviz

Embeddable, framework-agnostic agent chat widget. Stream LLM responses with markdown rendering, file attachments, text selection summaries, and complete style isolation via Shadow DOM.

- **Two widget types**: Inline Summary (icon → summary/analysis) and Agent Chat (full conversation)
- **Multiple display modes**: Popover, drawer, FAB (floating action button), DOM injection
- **Text selection summary**: Highlight any text → floating "Summarize" / "Ask" toolbar
- **Zero framework dependencies** — works with React, Vue, Angular, or plain HTML
- **Full style isolation** — Shadow DOM + `all: initial` CSS reset, no parent style leakage
- **Dark & light themes** with full color token customization

## Installation

```bash
npm install @illuma-ai/agentviz
```

Or via CDN (IIFE bundle — exposes `AgentViz` and `SelectionSummary` globals):

```html
<script src="https://unpkg.com/@illuma-ai/agentviz/dist/agentviz.iife.js"></script>
```

---

## Quick Start

### Agent Chat — FAB (Floating Action Button)

A circular chat icon pinned to the bottom-right of the viewport. Clicking opens a drawer.

```javascript
import { AgentViz } from '@illuma-ai/agentviz';

const widget = new AgentViz({
  type: 'agent-chat',
  displayMode: 'fab',
  agentId: 'agent_xxx',
  url: 'https://app.illuma.ai',
  token: 'rat_xxx',
  icon: '<svg>...</svg>',  // or image URL
  brandName: 'Illuma',
  theme: 'dark',
});
widget.mount();
```

### Inline Summary — Icon in Header

Place a summary icon next to any section. Clicking extracts the content and sends it to the agent.

```javascript
import { AgentViz } from '@illuma-ai/agentviz';

const widget = new AgentViz({
  type: 'inline',
  agentId: 'agent_xxx',
  url: 'https://app.illuma.ai',
  token: 'rat_xxx',
  icon: '<svg>...</svg>',
  contentMode: 'dom',
  data: document.querySelector('#my-section'),
  displayMode: 'popover',
  parentElement: document.querySelector('#icon-container'),
  brandName: 'Illuma',
});
widget.mount();
```

---

## Widget Types

### `type: "inline"` — Inline Summary

An icon placed in the page DOM (header, toolbar, sidebar). When clicked, it extracts content based on `contentMode` and sends it to the agent for summary/analysis.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `"inline"` | Yes | Widget type discriminator |
| `agentId` | `string` | Yes | Agent ID for API calls |
| `url` | `string` | Yes | API base URL |
| `token` | `string` | Yes | API token (`rat_...`) |
| `icon` | `string` | Yes | Icon SVG markup or image URL |
| `contentMode` | `"dom" \| "text" \| "json"` | Yes | How content is delivered to the agent |
| `data` | `HTMLElement \| string \| object` | Yes | Content payload (type depends on `contentMode`) |
| `displayMode` | `"popover" \| "drawer"` | Yes | How the summary UI is displayed |
| `parentElement` | `HTMLElement` | Yes | DOM element to mount the icon into |
| `chatEnabled` | `boolean` | No | Show chat input for follow-up questions (default: `false`) |
| `attachAsContext` | `boolean` | No | JSON mode only — how JSON data is sent (default: `true`) |
| `theme` | `"dark" \| "light" \| ThemeColors` | No | Theme preset or custom colors (default: `"dark"`) |
| `brandName` | `string` | No | Brand name in header (default: `"Agent"`) |
| `updateMemory` | `boolean` | No | Pass updateMemory flag to API (default: `false`) |

#### Content Modes

```javascript
// DOM — extract text/HTML from DOM elements
{ contentMode: 'dom', data: document.querySelector('#article') }
{ contentMode: 'dom', data: [el1, el2, el3] }  // multiple elements

// Text — send plain text directly
{ contentMode: 'text', data: 'Your text content to summarize...' }

// JSON — send structured data
{ contentMode: 'json', data: { revenue: 12500000, growth: 0.18 } }
```

#### Display Modes

```javascript
// Popover — floating panel anchored to the icon
{ displayMode: 'popover' }

// Drawer — slide-in panel from the right
{ displayMode: 'drawer' }
```

---

### `type: "agent-chat"` — Agent Chat

Full conversational chat with the agent. Three display modes with different UX patterns.

#### FAB (Floating Action Button)

Circular button pinned to bottom-right of viewport. Always opens a drawer.

```javascript
new AgentViz({
  type: 'agent-chat',
  displayMode: 'fab',
  agentId: 'agent_xxx',
  url: 'https://app.illuma.ai',
  token: 'rat_xxx',
  icon: '<svg>...</svg>',
  fileAttach: true,   // enable file uploads
  theme: 'dark',
}).mount();
```

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `displayMode` | `"fab"` | Yes | FAB mode |
| `icon` | `string` | Yes | Icon SVG or image URL for the FAB button |
| `fileAttach` | `boolean` | No | Enable file attachment (default: `false`) |

#### Icon Inline

Icon embedded in your page DOM (header, toolbar, etc). Opens chat via popover or drawer.

```javascript
new AgentViz({
  type: 'agent-chat',
  displayMode: 'icon-inline',
  parentElement: document.querySelector('#header-actions'),
  subDisplayMode: 'popover',  // or 'drawer'
  agentId: 'agent_xxx',
  url: 'https://app.illuma.ai',
  token: 'rat_xxx',
  icon: '<svg>...</svg>',
}).mount();
```

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `displayMode` | `"icon-inline"` | Yes | Icon inline mode |
| `parentElement` | `HTMLElement` | Yes | DOM element to mount the icon into |
| `subDisplayMode` | `"popover" \| "drawer"` | Yes | How the chat panel opens |
| `icon` | `string` | Yes | Icon SVG or image URL |

#### DOM Inject

Chat injected directly into a container element. No icon, no overlay — the chat is part of your page layout.

```javascript
new AgentViz({
  type: 'agent-chat',
  displayMode: 'dom-inject',
  parentElement: document.querySelector('#chat-container'),
  agentId: 'agent_xxx',
  url: 'https://app.illuma.ai',
  token: 'rat_xxx',
}).mount();
```

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `displayMode` | `"dom-inject"` | Yes | DOM inject mode |
| `parentElement` | `HTMLElement` | Yes | Container to inject chat into |
| `icon` | `string` | No | Not typically needed |

---

### Selection Summary

Global text-selection feature. Users highlight text anywhere on the page and get a floating toolbar with **"Summarize"** and **"Ask"** actions.

```javascript
import { SelectionSummary } from '@illuma-ai/agentviz';

// Enable once at app level — works across all pages
SelectionSummary.enable({
  agentId: 'agent_xxx',
  url: 'https://app.illuma.ai',
  token: 'rat_xxx',
  brandName: 'Illuma',
  theme: 'dark',
  chatEnabled: true,  // allow follow-up questions after summary
});

// Disable when no longer needed
SelectionSummary.disable();
```

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `agentId` | `string` | Yes | Agent ID |
| `url` | `string` | Yes | API base URL |
| `token` | `string` | Yes | API token |
| `brandName` | `string` | No | Shown in toolbar and popover header |
| `theme` | `"dark" \| "light" \| ThemeColors` | No | Theme (default: `"dark"`) |
| `chatEnabled` | `boolean` | No | Show chat input for follow-up (default: `false`) |
| `icon` | `string` | No | Custom icon for the toolbar button |
| `minSelectionLength` | `number` | No | Minimum chars to trigger toolbar (default: `10`) |

---

## API Reference

### `AgentViz`

```typescript
class AgentViz {
  constructor(config: AgentVizConfig);

  /** Mount the widget into the DOM */
  mount(): void;

  /** Remove from DOM but preserve conversation state */
  unmount(): void;

  /** Full cleanup — remove from DOM, abort streams, reset state */
  destroy(): void;

  /** Send a message to the agent programmatically */
  sendMessage(text: string, files?: File[]): Promise<void>;

  /** Send content for inline widgets (extracts based on contentMode) */
  sendContent(): Promise<void>;

  /** Update theme at runtime */
  setTheme(theme: 'dark' | 'light' | Partial<ThemeColors>): void;

  /** Open the widget panel */
  open(): void;

  /** Close the widget panel (preserves conversation) */
  close(): void;
}
```

### `SelectionSummary`

```typescript
class SelectionSummary {
  /** Enable text-selection summary globally (singleton) */
  static enable(config: SelectionSummaryConfig): SelectionSummary;

  /** Disable and clean up */
  static disable(): void;

  /** Check if currently enabled */
  static isEnabled(): boolean;
}
```

### Callbacks

```javascript
new AgentViz({
  // ...
  onMessage: (msg) => console.log(`${msg.role}: ${msg.content}`),
  onError: (err) => console.error('Widget error:', err),
  onReady: () => console.log('Widget mounted'),
});
```

---

## Theming

### Built-in Themes

```javascript
// Dark theme (default)
{ theme: 'dark' }

// Light theme
{ theme: 'light' }
```

### Custom Colors

Override any color token from the base theme:

```javascript
new AgentViz({
  // ...
  theme: {
    background: '#0f0f23',
    accent: '#8b5cf6',
    userBubble: '#7c3aed',
    userBubbleText: '#ffffff',
  },
});
```

### Runtime Theme Switching

```javascript
widget.setTheme('light');
widget.setTheme({ accent: '#e94560', background: '#1a1a2e' });
```

### Color Tokens

| Token | Description |
|-------|-------------|
| `background` | Main widget background |
| `surface` | Message bubble / card background |
| `surfaceHover` | Hover state for interactive surfaces |
| `text` | Primary text color |
| `textSecondary` | Secondary / muted text |
| `primary` | Primary brand color |
| `accent` | Accent color for links, highlights |
| `border` | Border color |
| `inputBackground` | Chat input background |
| `inputText` | Chat input text color |
| `inputBorder` | Chat input border |
| `userBubble` | User message bubble background |
| `userBubbleText` | User message text color |
| `agentBubble` | Agent message bubble background |
| `agentBubbleText` | Agent message text color |
| `skeleton` | Loading skeleton base color |
| `skeletonShimmer` | Loading skeleton shimmer highlight |
| `error` | Error text color |
| `scrollbarThumb` | Scrollbar thumb color |
| `codeBackground` | Code block background |

---

## Framework Integration

### React

```tsx
import { useRef, useEffect } from 'react';
import { AgentViz } from '@illuma-ai/agentviz';

function ChatWidget() {
  const containerRef = useRef<HTMLDivElement>(null);
  const widgetRef = useRef<AgentViz | null>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const widget = new AgentViz({
      type: 'agent-chat',
      displayMode: 'dom-inject',
      parentElement: containerRef.current,
      agentId: 'agent_xxx',
      url: 'https://app.illuma.ai',
      token: 'rat_xxx',
      theme: 'dark',
    });
    widget.mount();
    widgetRef.current = widget;

    return () => widget.destroy();
  }, []);

  return <div ref={containerRef} style={{ height: 500 }} />;
}
```

### React — Inline Summary Icon

```tsx
function SectionWithSummary({ children }) {
  const iconRef = useRef<HTMLDivElement>(null);
  const contentRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!iconRef.current || !contentRef.current) return;

    const widget = new AgentViz({
      type: 'inline',
      agentId: 'agent_xxx',
      url: 'https://app.illuma.ai',
      token: 'rat_xxx',
      icon: '<svg>...</svg>',
      contentMode: 'dom',
      data: contentRef.current,
      displayMode: 'popover',
      parentElement: iconRef.current,
    });
    widget.mount();
    return () => widget.destroy();
  }, []);

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <h2>Section Title</h2>
        <div ref={iconRef} />
      </div>
      <div ref={contentRef}>{children}</div>
    </div>
  );
}
```

### Vue

```vue
<template>
  <div ref="container" style="height: 500px" />
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { AgentViz } from '@illuma-ai/agentviz';

const container = ref(null);
let widget = null;

onMounted(() => {
  widget = new AgentViz({
    type: 'agent-chat',
    displayMode: 'dom-inject',
    parentElement: container.value,
    agentId: 'agent_xxx',
    url: 'https://app.illuma.ai',
    token: 'rat_xxx',
  });
  widget.mount();
});

onUnmounted(() => widget?.destroy());
</script>
```

### Plain HTML (IIFE)

```html
<script src="https://unpkg.com/@illuma-ai/agentviz/dist/agentviz.iife.js"></script>

<script>
  // FAB — no container needed, auto-injects bottom-right
  new AgentViz({
    type: 'agent-chat',
    displayMode: 'fab',
    agentId: 'agent_xxx',
    url: 'https://app.illuma.ai',
    token: 'rat_xxx',
    icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
  }).mount();

  // Selection Summary — global text highlight feature
  SelectionSummary.enable({
    agentId: 'agent_xxx',
    url: 'https://app.illuma.ai',
    token: 'rat_xxx',
    brandName: 'Illuma',
  });
</script>
```

---

## Exports

```typescript
// Main class (facade)
export { AgentViz } from './widget';

// Widget implementations (advanced use)
export { InlineWidget } from './widget-inline';
export { AgentChatWidget } from './widget-agent-chat';

// Selection Summary
export { SelectionSummary } from './selection-summary';
export type { SelectionSummaryConfig } from './selection-summary';

// Types
export type {
  AgentVizConfig,
  InlineWidgetConfig,
  AgentChatWidgetConfig,
  AgentChatFabConfig,
  AgentChatIconInlineConfig,
  AgentChatDomInjectConfig,
  AgentVizInstance,
  WidgetType,
  ContentMode,
  InlineDisplayMode,
  AgentChatDisplayMode,
  SubDisplayMode,
  ThemeColors,
  ThemeInput,
  Message,
  FileAttachment,
  StreamEvent,
} from './types';

// Theme presets
export { DARK_THEME, LIGHT_THEME } from './themes';

// Constants
export { ICONS, DEFAULTS, Z_INDEX } from './constants';
```

## License

MIT — see [LICENSE](./LICENSE)