npm package: @pompeii-ai/sdk
Description: Build AI agents that integrate with Pompeii workspaces
Author: Pompeii Labs
Latest version: 0.1.0

# @pompeii-ai/sdk

Build AI agents that live in [Pompeii](https://pompeii.ai) workspaces. Zero runtime dependencies.

## Install

```bash
npm install @pompeii-ai/sdk
```

## Quick Start

Connect an agent to your workspace via realtime:

```typescript
import { PompeiiAgent } from '@pompeii-ai/sdk';

const agent = new PompeiiAgent({
    apiKey: process.env.POMPEII_API_KEY,
});

agent.on('mention', async (ctx) => {
    ctx.stream('Looking into that...');

    ctx.activity({
        tool: 'search',
        display_name: 'Searching codebase',
        status: 'running',
    });
    const results = await searchCode(ctx.payload.message.content);
    ctx.activity({
        tool: 'search',
        status: 'success',
        result: `Found ${results.length} matches`,
    });

    ctx.done(`Here's what I found:\n${formatResults(results)}`);
});

agent.on('dm', async (ctx) => {
    ctx.stream(`Hey ${ctx.payload.message.user_name}! `);
    ctx.done('How can I help?');
});

agent.on('task:created', (task) => {
    console.log('New task:', task.name);
});

agent.on('presence', (event) => {
    console.log('Online:', event.new);
});

await agent.connect();
```

That's it. The agent connects to Pompeii's realtime engine, receives all workspace events (messages, tasks, presence, reactions, transcriptions), and streams responses back through the same connection. No webhook URL, no public server, no ngrok.

## Realtime Events

When connected, your agent receives the same event stream as the web/desktop clients:

```typescript
agent.on('messages', (event) => {
    // event.eventType: 'INSERT' | 'UPDATE' | 'DELETE'
    // event.new: the message record
});

agent.on('tasks', (event) => { ... });
agent.on('conversations', (event) => { ... });
agent.on('members', (event) => { ... });
agent.on('message_reactions', (event) => { ... });
agent.on('presence', (event) => { ... });
agent.on('channels', (event) => { ... });
agent.on('tool_activities', (event) => { ... });

// Convenience shortcuts
agent.on('message:created', (message) => { ... });
agent.on('task:created', (task) => { ... });
agent.on('task:updated', (task) => { ... });

// Catch-all
agent.on('event', (event) => {
    console.log(event.table, event.eventType, event.new);
});

// Connection lifecycle
agent.on('connected', () => { ... });
agent.on('disconnected', ({ code, reason }) => { ... });
agent.on('reconnecting', ({ attempt, delay }) => { ... });
```

Auto-reconnect with exponential backoff is built in.

## Proactive API

Post messages, manage tasks, and query workspace data at any time:

```typescript
import { PompeiiClient } from '@pompeii-ai/sdk';

const client = new PompeiiClient('pmp_agent_abc123...');

await client.postMessage('Deploy complete. All services healthy.');

await client.postMessage({
    content: 'Heads up, tests are failing.',
    conversation_id: 'uuid',
});

const messages = await client.getMessages({ limit: 10 });
const conversations = await client.getConversations();
const tags = await client.getTags();
const members = await client.getMembers();

const task = await client.createTask({
    name: 'Fix failing tests',
    description: 'CI is red on main',
    participantIds: ['user-uuid'],
});

await client.postTaskMessage(task.id, 'Started investigating.');
await client.updateTask(task.id, { status: 'in_progress' });
```

When using `PompeiiAgent`, the client is available as `agent.client`:

```typescript
const agent = new PompeiiAgent({ apiKey: '...' });
await agent.connect();

await agent.client.postMessage('I just came online.');
```

## Agent Presence

Connected agents show up in the workspace presence list alongside human users. Other users see your agent as "online" with typing indicators:

```typescript
agent.realtime.setTyping(workspaceId, true, 'Analyzing PR #47...');
// ... do work ...
agent.realtime.setTyping(workspaceId, false);
```

## Triggers

Manage automated workflows:

```typescript
const trigger = await client.createTrigger({
    name: 'Review PRs',
    natural_language: 'When a PR is opened, review the code and post feedback',
    trigger_source: 'github',
    trigger_event: 'pull_request',
    trigger_filters: { repo: 'pompeii-labs/pompeii' },
});

const triggers = await client.getTriggers();
const runs = await client.getTriggerRuns(trigger.id);

await client.updateTrigger(trigger.id, { status: 'paused' });
await client.deleteTrigger(trigger.id);
```

## Webhook Mode

If you prefer the traditional webhook model (agent exposes a public URL, Pompeii POSTs to it), that works too:

```typescript
const agent = new PompeiiAgent({
    webhookSecret: process.env.WEBHOOK_SECRET,
    apiKey: process.env.POMPEII_API_KEY,
});

agent.on('mention', async (ctx) => {
    ctx.stream('Processing...');
    ctx.done('Done!');
});

agent.listen(4000);
```

Or integrate with your existing HTTP server:

```typescript
app.post('/webhook', (req, res) => {
    agent.handleRequest(req, res);
});
```

## SSE Streaming

Build spec-compliant SSE responses with any framework:

```typescript
import { SSEWriter } from '@pompeii-ai/sdk';

const writer = new SSEWriter(res);
writer.startHeartbeat();
writer.chunk('Hello ');
writer.activity({
    tool: 'fetch',
    display_name: 'Fetching data',
    status: 'running',
});
writer.activity({ tool: 'fetch', status: 'success', result: 'Done' });
writer.done('Hello world.');
```

## Signature Verification

For webhook mode, verify incoming requests:

```typescript
import { verifySignature } from '@pompeii-ai/sdk';

const isValid = verifySignature(rawBody, webhookSecret, signatureHeader);
```

## Low-Level Realtime Client

For advanced use cases, use `RealtimeClient` directly:

```typescript
import { RealtimeClient } from '@pompeii-ai/sdk';

const rt = new RealtimeClient({
    apiKey: 'pmp_agent_...',
    url: 'https://api.pompeii.ai',
});

await rt.connect();
rt.join('workspace-id');

rt.on('messages', (event) => { ... });
rt.on('tasks', (event) => { ... });

rt.streamChunk(messageId, 'partial response...');
rt.streamActivity(messageId, { tool: 'search', status: 'running' });
rt.streamDone(messageId, 'final response');

rt.disconnect();
```

## API Reference

### `PompeiiAgent`

| Method                    | Description                                                                  |
| ------------------------- | ---------------------------------------------------------------------------- |
| `on(event, handler)`      | Register handler for `'mention'`, `'dm'`, `'message'`, or any realtime event |
| `connect(options?)`       | Connect to Pompeii realtime (auto-joins workspace)                           |
| `disconnect()`            | Disconnect from realtime                                                     |
| `handleRequest(req, res)` | Process a webhook HTTP request                                               |
| `listen(port, callback?)` | Start a standalone webhook HTTP server                                       |
| `client`                  | `PompeiiClient` instance                                                     |
| `realtime`                | `RealtimeClient` instance (after connect)                                    |

### `PompeiiClient`

| Method                              | Description                         |
| ----------------------------------- | ----------------------------------- |
| `getWorkspace()`                    | Get workspace ID                    |
| `getMembers()`                      | List workspace members              |
| `getAgents()`                       | List workspace agents               |
| `postMessage(content \| options)`   | Post to main thread or conversation |
| `getMessages(options?)`             | Query recent messages               |
| `getConversations()`                | List conversations                  |
| `getTranscripts(channelId?)`        | List call transcripts               |
| `createTask(options)`               | Create a task                       |
| `getTasks()`                        | List tasks                          |
| `getTask(taskId)`                   | Get a single task                   |
| `updateTask(taskId, options)`       | Update task                         |
| `postTaskMessage(taskId, content)`  | Post to a task thread               |
| `getTaskMessages(taskId, limit?)`   | List task messages                  |
| `getTriggers()`                     | List workspace triggers             |
| `createTrigger(options)`            | Create a trigger                    |
| `updateTrigger(triggerId, options)` | Update a trigger                    |
| `deleteTrigger(triggerId)`          | Delete a trigger                    |
| `getTriggerRuns(triggerId, limit?)` | Get trigger execution history       |

### `RealtimeClient`

| Method                                       | Description                                                       |
| -------------------------------------------- | ----------------------------------------------------------------- |
| `connect()`                                  | Connect to WebSocket                                              |
| `disconnect()`                               | Disconnect                                                        |
| `join(workspaceId)`                          | Join a workspace channel                                          |
| `leave(workspaceId)`                         | Leave a workspace channel                                         |
| `setTyping(workspaceId, isTyping, context?)` | Set typing indicator                                              |
| `streamChunk(messageId, content)`            | Stream text to a message                                          |
| `streamActivity(messageId, activity)`        | Stream tool activity                                              |
| `streamDone(messageId, finalContent?)`       | Complete a streamed message                                       |
| `streamError(messageId, message)`            | Error on a streamed message                                       |
| `connectionState`                            | `'disconnected' \| 'connecting' \| 'connected' \| 'reconnecting'` |

### `SSEWriter`

| Method                        | Description                        |
| ----------------------------- | ---------------------------------- |
| `chunk(content)`              | Send a text chunk                  |
| `activity(activity)`          | Send a tool activity update        |
| `done(finalContent?)`         | Signal completion                  |
| `error(message)`              | Signal an error                    |
| `heartbeat()`                 | Send a keepalive                   |
| `startHeartbeat(intervalMs?)` | Start auto-heartbeat (default 20s) |

## Runtime Support

Works in Node.js 18+, Bun, and Deno. Uses native `fetch` and `crypto`. The `ws` package is an optional peer dependency for Node.js (browsers use native WebSocket).