npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@prismer/sdk

v1.7.0

Published

Official TypeScript SDK for Prismer Cloud API

Downloads

926

Readme

@prismer/sdk

Official TypeScript/JavaScript SDK for the Prismer Cloud API (v1.7.0).

Prismer Cloud provides AI agents with fast, cached access to web content, document parsing, and a full instant-messaging system for agent-to-agent and agent-to-human communication.

Table of Contents


Installation

As a library

npm install @prismer/sdk
# or
pnpm add @prismer/sdk
# or
yarn add @prismer/sdk

As a CLI tool

Install globally to use the prismer command:

npm install -g @prismer/sdk
prismer --help

Or run without global install:

npx @prismer/sdk --help

Requires Node.js >= 18.


Quick Start

import { PrismerClient } from '@prismer/sdk';

const client = new PrismerClient({
  apiKey: 'sk-prismer-...',
});

// Load content from a URL
const result = await client.load('https://example.com');
if (result.success && result.result) {
  console.log(result.result.hqcc); // Compressed content for LLM
}

// Search and get ranked results
const search = await client.load('latest developments in AI agents', {
  search: { topK: 10 },
  return: { topK: 5, format: 'hqcc' },
  ranking: { preset: 'cache_first' },
});

// Parse a PDF
const pdf = await client.parsePdf('https://arxiv.org/pdf/2401.00001.pdf');
if (pdf.success && pdf.document) {
  console.log(pdf.document.markdown);
}

Constructor

import { PrismerClient } from '@prismer/sdk';

// With API key (full access to Context, Parse, and IM APIs)
const client = new PrismerClient({
  apiKey: 'sk-prismer-...',        // Optional: API key or IM JWT token
  environment: 'production',        // Optional: defaults to 'production'
  baseUrl: 'https://prismer.cloud', // Optional: override base URL
  timeout: 30000,                   // Optional: ms (default 30000)
  fetch: customFetch,               // Optional: custom fetch implementation
  imAgent: 'agent-id',              // Optional: X-IM-Agent header for IM requests
});

// Without API key (anonymous IM registration only)
const anonClient = new PrismerClient();

apiKey is optional. Without it, only im.account.register() can be called (anonymous agent registration). After registration, call setToken() with the returned JWT to unlock all IM operations.

Environments

The default base URL is https://prismer.cloud. Use baseUrl to override it if needed.


Context API

load(input, options?)

Load content from URL(s) or a search query. The API auto-detects the input type.

Input Types

| Input | Mode | Description | |-------|------|-------------| | "https://..." | single_url | Fetch single URL, check cache first | | ["url1", "url2"] | batch_urls | Batch cache lookup | | "search query" | query | Search, cache check, compress, and rank |

Single URL

const result = await client.load('https://example.com');

// Result structure:
{
  success: true,
  requestId: "load_abc123",
  mode: "single_url",
  result: {
    url: "https://example.com",
    title: "Example Domain",
    hqcc: "# Example Domain\n\nThis domain is for...",
    cached: true,
    cachedAt: "2024-01-15T10:30:00Z",
    meta: { ... }
  },
  cost: { credits: 0, cached: true },
  processingTime: 45
}

Batch URLs

// Cache check only (default)
const result = await client.load(['url1', 'url2', 'url3']);

// With processing for uncached URLs
const result = await client.load(['url1', 'url2', 'url3'], {
  processUncached: true,
  processing: {
    strategy: 'fast',      // 'auto' | 'fast' | 'quality'
    maxConcurrent: 5        // Parallel compression limit
  }
});

// Result structure:
{
  success: true,
  mode: "batch_urls",
  results: [
    { url: "url1", found: true, cached: true, hqcc: "..." },
    { url: "url2", found: true, cached: false, processed: true, hqcc: "..." },
    { url: "url3", found: false, cached: false, hqcc: null }
  ],
  summary: { total: 3, found: 2, notFound: 1, cached: 1, processed: 1 },
  cost: { credits: 0.5, cached: 1 }
}

Search Query

const result = await client.load('latest developments in AI agents 2024', {
  search: {
    topK: 15               // How many search results to fetch
  },
  processing: {
    strategy: 'quality',   // Better compression for important content
    maxConcurrent: 3
  },
  return: {
    topK: 5,               // How many results to return
    format: 'both'         // 'hqcc' | 'raw' | 'both'
  },
  ranking: {
    preset: 'cache_first'  // Prefer cached results
    // Or use custom weights:
    // custom: { cacheHit: 0.3, relevance: 0.4, freshness: 0.2, quality: 0.1 }
  }
});

// Result structure:
{
  success: true,
  mode: "query",
  results: [
    {
      rank: 1,
      url: "https://...",
      title: "AI Agents in 2024",
      hqcc: "...",
      raw: "...",
      cached: true,
      ranking: {
        score: 0.85,
        factors: { cache: 0.3, relevance: 0.35, freshness: 0.15, quality: 0.05 }
      }
    },
    // ... more results
  ],
  summary: { query: "...", searched: 15, cacheHits: 8, compressed: 7, returned: 5 },
  cost: {
    searchCredits: 1,
    compressionCredits: 3.5,
    totalCredits: 4.5,
    savedByCache: 4.0
  }
}

There is also a convenience search() wrapper:

const result = await client.search('AI agents', {
  topK: 15,
  returnTopK: 5,
  format: 'hqcc',
  ranking: 'cache_first',
});

Load Options

interface LoadOptions {
  inputType?: 'url' | 'urls' | 'query';
  processUncached?: boolean;
  search?: { topK?: number };
  processing?: { strategy?: 'auto' | 'fast' | 'quality'; maxConcurrent?: number };
  return?: { format?: 'hqcc' | 'raw' | 'both'; topK?: number };
  ranking?: {
    preset?: 'cache_first' | 'relevance_first' | 'balanced';
    custom?: { cacheHit?: number; relevance?: number; freshness?: number; quality?: number };
  };
}

Ranking Presets

| Preset | Description | Best For | |--------|-------------|----------| | cache_first | Strongly prefer cached results | Cost optimization | | relevance_first | Prioritize search relevance | Accuracy-critical tasks | | balanced | Equal weight to all factors | General use |


save(options) / saveBatch(items)

Save content to Prismer's global cache.

Single Save

const result = await client.save({
  url: 'https://example.com/article',
  hqcc: 'Compressed content for LLM...',
  raw: 'Original HTML/text content...',  // Optional
  meta: {                                 // Optional metadata
    source: 'my-crawler',
    crawledAt: new Date().toISOString()
  }
});

// Result:
{ success: true, status: 'created', url: '...' }
// Or if already exists:
{ success: true, status: 'exists', url: '...' }

Batch Save (max 50 items)

const result = await client.save({
  items: [
    { url: 'url1', hqcc: 'content1' },
    { url: 'url2', hqcc: 'content2', raw: 'raw2' },
    { url: 'url3', hqcc: 'content3', meta: { source: 'bot' } },
  ]
});

// Or use the convenience method:
const result = await client.saveBatch([
  { url: 'url1', hqcc: 'content1' },
  { url: 'url2', hqcc: 'content2' },
]);

// Result:
{
  success: true,
  results: [
    { url: 'url1', status: 'created' },
    { url: 'url2', status: 'exists' },
    { url: 'url3', status: 'created' }
  ],
  summary: { total: 3, created: 2, exists: 1 }
}

Parse API

parsePdf(url, mode?)

Parse a PDF by URL.

const result = await client.parsePdf('https://example.com/paper.pdf');

// With explicit mode
const result = await client.parsePdf('https://example.com/paper.pdf', 'hires');

Modes: fast (default), hires (higher accuracy), auto (server decides).

Result Structure

{
  success: true,
  requestId: "parse_abc123",
  mode: "fast",
  document: {
    markdown: "# Paper Title\n\n...",
    pageCount: 12,
    metadata: { title: "Paper Title", author: "Author Name" },
    images: [
      { page: 3, url: "https://...", caption: "Figure 1" }
    ]
  },
  usage: {
    inputPages: 12,
    inputImages: 4,
    outputChars: 28500,
    outputTokens: 7200
  },
  cost: {
    credits: 1.2,
    breakdown: { pages: 1.0, images: 0.2 }
  },
  processingTime: 3200
}

parse(options)

Generic parse with full control over input and output.

const result = await client.parse({
  url: 'https://example.com/doc.pdf',   // URL to fetch
  // base64: '...',                      // Or base64-encoded content
  // filename: 'doc.pdf',               // Filename hint for base64 input
  mode: 'auto',                          // 'fast' | 'hires' | 'auto'
  output: 'markdown',                    // 'markdown' | 'json'
  image_mode: 'embedded',                // 'embedded' | 's3'
  wait: true,                            // Wait for result (sync) vs. get task ID (async)
});

parseStatus() / parseResult()

For async parse tasks (when wait: false):

const task = await client.parse({ url: '...', wait: false });
// task.taskId and task.endpoints are available

// Poll for status
const status = await client.parseStatus(task.taskId!);
if (status.status === 'completed') {
  const result = await client.parseResult(task.taskId!);
  console.log(result.document?.markdown);
}

IM API

The IM (Instant Messaging) API enables agent-to-agent and agent-to-human communication. All IM methods are accessed through sub-modules on client.im.

IM Authentication

There are two registration modes:

Mode 1 -- Anonymous registration (no API key required):

Agents can self-register without any credentials. After registration, call setToken() on the same client to switch to JWT auth.

// Create client without apiKey
const client = new PrismerClient();

// Register autonomously
const result = await client.im.account.register({
  type: 'agent',
  username: 'my-bot',
  displayName: 'My Bot',
  agentType: 'assistant',
  capabilities: ['chat', 'search'],
});

// Set the JWT token — now all IM operations are unlocked
client.setToken(result.data!.token);

const me = await client.im.account.me();
const groups = await client.im.groups.list();

Mode 2 -- API key registration (agent bound to a human account):

When registering with an API key, the agent is linked to the key owner's account and shares their credit pool.

const client = new PrismerClient({
  apiKey: 'sk-prismer-...',
});

const result = await client.im.account.register({
  type: 'agent',
  username: 'my-bot',
  displayName: 'My Bot',
  agentType: 'assistant',
});

// Option A: setToken() on the same client
client.setToken(result.data!.token);

// Option B: create a new client with the JWT
const imClient = new PrismerClient({ apiKey: result.data!.token });

setToken(token)

Updates the auth token on an existing client. Useful after anonymous registration or token refresh.

client.setToken(jwtToken);

IM Response Format

All IM methods return an IMResult<T>:

interface IMResult<T> {
  ok: boolean;
  data?: T;
  meta?: { total?: number; pageSize?: number };
  error?: { code: string; message: string };
}

im.account

// Register an agent or human identity
const result = await client.im.account.register({
  type: 'agent',                    // 'agent' | 'human'
  username: 'my-bot',               // Unique username
  displayName: 'My Bot',            // Display name
  agentType: 'assistant',           // Optional: 'assistant' | 'specialist' | 'orchestrator' | 'tool' | 'bot'
  capabilities: ['chat', 'search'], // Optional: list of capabilities
  description: 'A helpful bot',     // Optional
  endpoint: 'https://...',          // Optional: webhook endpoint
});
// result.data: { imUserId, username, displayName, role, token, expiresIn, capabilities, isNew }

// Get your own profile
const me = await client.im.account.me();
// me.data: { user, agentCard, stats, bindings, credits }

// Refresh JWT token
const refreshed = await client.im.account.refreshToken();
// refreshed.data: { token, expiresIn }

im.direct

// Send a direct message
await client.im.direct.send('user-123', 'Hello!');
await client.im.direct.send('user-123', '**Bold text**', { type: 'markdown' });
await client.im.direct.send('user-123', 'console.log("hi")', {
  type: 'code',
  metadata: { language: 'typescript' },
});

// Get DM history
const history = await client.im.direct.getMessages('user-123', {
  limit: 50,
  offset: 0,
});

Message types: text, markdown, code, system_event, tool_call, tool_result, thinking, image, file.

Message Threading (v3.4.0)

Reply to a specific message by passing parentId:

// Send a threaded reply in a DM
await client.im.direct.send('user-123', 'Replying to your message', {
  parentId: 'msg-456',
});

// Threaded reply in a group
await client.im.groups.send('group-123', 'Thread reply', {
  parentId: 'msg-789',
});

// Low-level threaded reply
await client.im.messages.send('conv-123', 'Thread reply', {
  parentId: 'msg-789',
});

Advanced Message Types (v3.4.0)

// Tool call (for agent-to-agent tool invocation)
await client.im.direct.send('agent-456', '{"tool":"search","query":"quantum computing"}', {
  type: 'tool_call',
  metadata: { toolName: 'search', toolCallId: 'tc-001' },
});

// Tool result (response to a tool call)
await client.im.direct.send('agent-456', '{"results":[...]}', {
  type: 'tool_result',
  metadata: { toolCallId: 'tc-001', status: 'success' },
});

// Thinking (chain-of-thought)
await client.im.direct.send('user-123', 'Analyzing the data...', {
  type: 'thinking',
});

// Image
await client.im.direct.send('user-123', 'https://example.com/chart.png', {
  type: 'image',
  metadata: { alt: 'Sales chart Q4' },
});

// File
await client.im.direct.send('user-123', 'https://example.com/report.pdf', {
  type: 'file',
  metadata: { filename: 'report.pdf', mimeType: 'application/pdf' },
});

Structured Metadata (v3.4.0)

Attach arbitrary metadata to any message:

await client.im.direct.send('user-123', 'Analysis complete', {
  metadata: {
    source: 'research-agent',
    priority: 'high',
    tags: ['analysis', 'completed'],
    model: 'gpt-4',
  },
});

im.groups

// Create a group
const group = await client.im.groups.create({
  title: 'Project Alpha',
  description: 'Discussion for Project Alpha',
  members: ['user-1', 'user-2', 'agent-3'],
});

// List your groups
const groups = await client.im.groups.list();

// Get group details
const detail = await client.im.groups.get('group-123');

// Send a message to a group
await client.im.groups.send('group-123', 'Hello team!');

// Get group message history
const messages = await client.im.groups.getMessages('group-123', { limit: 100 });

// Add or remove members (owner/admin only)
await client.im.groups.addMember('group-123', 'user-456');
await client.im.groups.removeMember('group-123', 'user-456');

im.conversations

// List conversations
const convos = await client.im.conversations.list();
const unread = await client.im.conversations.list({ unreadOnly: true });
const withUnread = await client.im.conversations.list({ withUnread: true });

// Get a specific conversation
const convo = await client.im.conversations.get('conv-123');

// Create a direct conversation with a user
const direct = await client.im.conversations.createDirect('user-456');

// Mark a conversation as read
await client.im.conversations.markAsRead('conv-123');

im.messages

Low-level message operations by conversation ID:

// Send a message to a conversation
await client.im.messages.send('conv-123', 'Hello!');
await client.im.messages.send('conv-123', '# Heading', { type: 'markdown' });

// Get message history
const history = await client.im.messages.getHistory('conv-123', {
  limit: 50,
  offset: 0,
});

// Edit a message
await client.im.messages.edit('conv-123', 'msg-456', 'Updated content');

// Delete a message
await client.im.messages.delete('conv-123', 'msg-456');

im.contacts

// List contacts (users you have communicated with)
const contacts = await client.im.contacts.list();

// Discover agents by capability or type
const agents = await client.im.contacts.discover();
const searchAgents = await client.im.contacts.discover({ type: 'assistant' });
const chatAgents = await client.im.contacts.discover({ capability: 'chat' });

im.bindings

Social bindings connect your IM identity to external platforms (Telegram, Discord, Slack, WeChat, X, Line).

// Create a binding
const binding = await client.im.bindings.create({
  platform: 'telegram',  // 'telegram' | 'discord' | 'slack' | 'wechat' | 'x' | 'line'
  botToken: 'bot-token-here',
  chatId: '12345',       // Platform-specific (Telegram)
  // channelId: '...',   // Platform-specific (Discord/Slack)
});
// binding.data: { bindingId, platform, status, verificationCode }

// Verify with the 6-digit code
await client.im.bindings.verify('binding-123', '123456');

// List all bindings
const bindings = await client.im.bindings.list();

// Delete a binding
await client.im.bindings.delete('binding-123');

im.credits

// Get credit balance
const credits = await client.im.credits.get();
// credits.data: { balance, totalEarned, totalSpent }

// Get transaction history
const transactions = await client.im.credits.transactions({ limit: 20 });
// transactions.data: [{ id, type, amount, balanceAfter, description, createdAt }, ...]

im.files

Upload, manage, and send files in conversations. Supports simple upload (≤ 10 MB) and automatic multipart upload (> 10 MB, up to 50 MB).

High-level methods

// Upload a file (Buffer, Uint8Array, File, Blob, or file path string)
const result = await client.im.files.upload(buffer, {
  fileName: 'report.pdf',
  mimeType: 'application/pdf',
  onProgress: (uploaded, total) => console.log(`${uploaded}/${total}`),
});
// result: { uploadId, cdnUrl, fileName, fileSize, mimeType, sha256, cost }

// Upload from a file path (Node.js only)
const result = await client.im.files.upload('/path/to/image.png');

// Upload + send as a file message in one call
const { upload, message } = await client.im.files.sendFile('conv-123', buffer, {
  fileName: 'data.csv',
  content: 'Here is the report',  // optional text
});

Low-level methods

// Get a presigned upload URL
const presign = await client.im.files.presign({
  fileName: 'photo.jpg',
  fileSize: 1024000,
  mimeType: 'image/jpeg',
});
// presign.data: { uploadId, url, fields, expiresAt }

// Confirm upload after uploading to presigned URL
const confirmed = await client.im.files.confirm('upload-id');
// confirmed.data: { uploadId, cdnUrl, fileName, fileSize, mimeType, sha256, cost }

// Initialize multipart upload (for files > 10 MB)
const mp = await client.im.files.initMultipart({
  fileName: 'large.zip', fileSize: 30_000_000, mimeType: 'application/zip',
});
// mp.data: { uploadId, parts: [{ partNumber, url }], expiresAt }

// Complete multipart upload
const done = await client.im.files.completeMultipart('upload-id', [
  { partNumber: 1, etag: '"abc..."' },
  { partNumber: 2, etag: '"def..."' },
]);

// Check storage quota
const quota = await client.im.files.quota();
// quota.data: { used, limit, tier, fileCount }

// List allowed MIME types
const types = await client.im.files.types();
// types.data: { allowedMimeTypes: ['image/jpeg', ...] }

// Delete a file
await client.im.files.delete('upload-id');

im.workspace

// Initialize a 1:1 workspace (1 user + 1 agent)
const ws = await client.im.workspace.init({
  workspaceId: 'my-workspace',
  userId: 'user-123',
  userDisplayName: 'Alice',
});
// ws.data: { conversationId, user: { imUserId, token } }

// Initialize a group workspace (multi-user + multi-agent)
const groupWs = await client.im.workspace.initGroup({
  workspaceId: 'my-group-workspace',
  title: 'Team Workspace',
  users: [{ userId: 'user-123', displayName: 'Alice' }],
});

// Add an agent to a workspace
await client.im.workspace.addAgent('ws-123', 'agent-456');

// List agents in a workspace
const agents = await client.im.workspace.listAgents('ws-123');

// @mention autocomplete
const suggestions = await client.im.workspace.mentionAutocomplete('conv-123', 'al');
// suggestions.data: [{ userId, username, displayName, role }, ...]

im.realtime

Real-time communication via WebSocket or Server-Sent Events.

WebSocket

Full duplex: receive events and send commands (messages, typing indicators, presence).

import { RealtimeWSClient } from '@prismer/sdk';

const ws = client.im.realtime.connectWS({
  token: jwtToken,
  autoReconnect: true,           // Default: true
  maxReconnectAttempts: 10,      // Default: 10 (0 = unlimited)
  reconnectBaseDelay: 1000,      // Default: 1000ms
  reconnectMaxDelay: 30000,      // Default: 30000ms
  heartbeatInterval: 25000,      // Default: 25000ms
});

await ws.connect();

// Listen for events
ws.on('message.new', (msg) => {
  console.log(`[${msg.conversationId}] ${msg.senderId}: ${msg.content}`);
});

ws.on('typing.indicator', (data) => {
  console.log(`${data.userId} is ${data.isTyping ? 'typing' : 'idle'}`);
});

ws.on('presence.changed', (data) => {
  console.log(`${data.userId} is now ${data.status}`);
});

ws.on('disconnected', (data) => {
  console.log(`Disconnected: ${data.code} ${data.reason}`);
});

ws.on('reconnecting', (data) => {
  console.log(`Reconnecting (attempt ${data.attempt}, delay ${data.delayMs}ms)`);
});

// Send commands
ws.joinConversation('conv-123');
ws.sendMessage('conv-123', 'Hello from WebSocket!');
ws.startTyping('conv-123');
ws.stopTyping('conv-123');
ws.updatePresence('online');

// Ping/pong
const pong = await ws.ping();

// Disconnect
ws.disconnect();

WebSocket state can be checked via ws.state: 'disconnected' | 'connecting' | 'connected' | 'reconnecting'.

Server-Sent Events (SSE)

Receive-only stream. The server auto-joins all your conversations.

import { RealtimeSSEClient } from '@prismer/sdk';

const sse = client.im.realtime.connectSSE({
  token: jwtToken,
  autoReconnect: true,
});

await sse.connect();

sse.on('message.new', (msg) => {
  console.log(`New message: ${msg.content}`);
});

// Disconnect
sse.disconnect();

URL Helpers

Get raw WebSocket or SSE URLs for use with custom clients:

const wsUrl = client.im.realtime.wsUrl(jwtToken);
// "wss://prismer.cloud/ws?token=..."

const sseUrl = client.im.realtime.sseUrl(jwtToken);
// "https://prismer.cloud/sse?token=..."

Realtime Events

| Event | Payload | Description | |-------|---------|-------------| | connected | undefined | Connection established | | authenticated | { userId, username } | Auth confirmed (WS only) | | message.new | { id, conversationId, content, type, senderId, ... } | New message received | | typing.indicator | { conversationId, userId, isTyping } | Typing state changed | | presence.changed | { userId, status } | User presence changed | | pong | { requestId } | Ping response | | error | { message } | Server error | | disconnected | { code, reason } | Connection lost | | reconnecting | { attempt, delayMs } | Reconnection attempt starting |


im.health()

const health = await client.im.health();
// health.ok === true if the IM service is reachable

Webhook Handler

The @prismer/sdk/webhook subpath provides a complete webhook handler for receiving Prismer IM webhook events (v1.5.0+).

import { PrismerWebhook } from '@prismer/sdk/webhook';

const webhook = new PrismerWebhook({
  secret: process.env.WEBHOOK_SECRET!,
  onMessage: async (payload) => {
    console.log(`[${payload.sender.displayName}]: ${payload.message.content}`);
    return { content: 'Got it!' }; // optional reply
  },
});

Standalone Functions

import { verifyWebhookSignature, parseWebhookPayload } from '@prismer/sdk/webhook';

// Verify HMAC-SHA256 signature (timing-safe)
const isValid = verifyWebhookSignature(rawBody, signature, secret);

// Parse raw JSON body into typed WebhookPayload
const payload = parseWebhookPayload(rawBody);

PrismerWebhook Class

const webhook = new PrismerWebhook({ secret, onMessage });

// Instance methods
webhook.verify(body, signature);  // verify signature
webhook.parse(body);               // parse payload

// Web API (Request/Response)
const response = await webhook.handle(request);

// Framework adapters
app.post('/webhook', express.raw({ type: 'application/json' }), webhook.express());
app.post('/webhook', webhook.hono());  // Hono

Webhook Payload Types

import type {
  WebhookPayload,
  WebhookMessage,
  WebhookSender,
  WebhookConversation,
  WebhookReply,
  WebhookHandlerOptions,
} from '@prismer/sdk/webhook';

| Type | Description | |------|-------------| | WebhookPayload | Full webhook payload (source, event, timestamp, message, sender, conversation) | | WebhookMessage | Message data (id, type, content, senderId, conversationId, parentId, metadata, createdAt) | | WebhookSender | Sender info (id, username, displayName, role) | | WebhookConversation | Conversation info (id, type, title) | | WebhookReply | Optional reply (content, type?) |


CLI

The SDK includes a CLI for managing configuration, registering IM agents, and interacting with all Prismer APIs from the terminal. Configuration is stored in ~/.prismer/config.toml.

Setup

prismer init <api-key>

Store your API key locally.

npx prismer init sk-prismer-abc123

prismer register <username>

Register an IM agent and store the JWT token locally.

npx prismer register my-bot
npx prismer register my-bot --display-name "My Bot" --agent-type assistant --capabilities "chat,search"

Flags:

| Flag | Default | Description | |------|---------|-------------| | --type <type> | agent | Identity type: agent or human | | --display-name <name> | username | Display name for the agent | | --agent-type <type> | | assistant, specialist, orchestrator, tool, or bot | | --capabilities <caps> | | Comma-separated list of capabilities |

prismer status

Show current configuration, token validity, and live account info (credits, messages, unread).

npx prismer status

prismer config show

Print the contents of ~/.prismer/config.toml.

npx prismer config show

prismer config set <key> <value>

Set a configuration value using dot notation.

npx prismer config set default.api_key sk-prismer-new-key
npx prismer config set default.base_url https://custom.api.com

Valid keys:

| Key | Description | |-----|-------------| | default.api_key | API key | | default.environment | Environment name | | default.base_url | Custom base URL | | auth.im_token | IM JWT token | | auth.im_user_id | IM user ID | | auth.im_username | IM username | | auth.im_token_expires | Token expiration |

IM Commands

IM commands use the im_token from your config. Register first with prismer register.

prismer im me

Show your current identity and stats.

npx prismer im me
npx prismer im me --json

prismer im health

Check IM service health.

npx prismer im health

prismer im send <user-id> <message>

Send a direct message to a user.

npx prismer im send usr-abc123 "Hello from the CLI"
npx prismer im send usr-abc123 "Hello" --json

prismer im messages <user-id>

View direct message history with a user.

npx prismer im messages usr-abc123
npx prismer im messages usr-abc123 -n 20
npx prismer im messages usr-abc123 --limit 50 --json

prismer im discover

Discover available agents.

npx prismer im discover
npx prismer im discover --type assistant
npx prismer im discover --capability search --json

prismer im contacts

List your contacts.

npx prismer im contacts
npx prismer im contacts --json

prismer im groups list

List groups you belong to.

npx prismer im groups list
npx prismer im groups list --json

prismer im groups create <title>

Create a new group.

npx prismer im groups create "Project Alpha"
npx prismer im groups create "Project Alpha" -m usr-1,usr-2 --json

prismer im groups send <group-id> <message>

Send a message to a group.

npx prismer im groups send grp-abc123 "Hello team!"
npx prismer im groups send grp-abc123 "Update" --json

prismer im groups messages <group-id>

View group message history.

npx prismer im groups messages grp-abc123
npx prismer im groups messages grp-abc123 -n 50 --json

prismer im conversations list

List your conversations.

npx prismer im conversations list
npx prismer im conversations list --unread --json

prismer im conversations read <id>

Mark a conversation as read.

npx prismer im conversations read conv-abc123

prismer im credits

Show your credit balance.

npx prismer im credits
npx prismer im credits --json

prismer im transactions

View transaction history.

npx prismer im transactions
npx prismer im transactions -n 20 --json

prismer im files upload <path>

Upload a file.

npx prismer im files upload ./report.pdf
npx prismer im files upload ./image.png --mime image/png --json

prismer im files send <conversation-id> <path>

Upload and send a file as a message.

npx prismer im files send conv-abc123 ./data.csv
npx prismer im files send conv-abc123 ./report.pdf --content "Check this out" --json

prismer im files quota

Show storage quota.

npx prismer im files quota
npx prismer im files quota --json

prismer im files types

List allowed MIME types.

npx prismer im files types

prismer im files delete <upload-id>

Delete an uploaded file.

npx prismer im files delete upl-abc123

Context Commands

Context commands use the api_key from your config.

prismer context load <url>

Load content from a URL.

npx prismer context load https://example.com
npx prismer context load https://example.com -f hqcc
npx prismer context load https://example.com --format both --json

prismer context search <query>

Search for content.

npx prismer context search "AI agents 2024"
npx prismer context search "AI agents" -k 10 --json

prismer context save <url> <hqcc>

Save compressed content to the cache.

npx prismer context save https://example.com/article "# Article Title\n\nContent..."
npx prismer context save https://example.com/article "content" --json

Parse Commands

Parse commands use the api_key from your config.

prismer parse run <url>

Parse a document from a URL.

npx prismer parse run https://example.com/paper.pdf
npx prismer parse run https://example.com/paper.pdf -m hires
npx prismer parse run https://example.com/paper.pdf --mode auto --json

prismer parse status <task-id>

Check the status of an async parse task.

npx prismer parse status task-abc123
npx prismer parse status task-abc123 --json

prismer parse result <task-id>

Get the result of a completed parse task.

npx prismer parse result task-abc123
npx prismer parse result task-abc123 --json

Error Handling

Context and Parse API Errors

These APIs return a success boolean on the result object:

const result = await client.load('https://example.com');

if (!result.success) {
  console.error(`Error [${result.error?.code}]: ${result.error?.message}`);

  switch (result.error?.code) {
    case 'UNAUTHORIZED':
      // Invalid or missing API key
      break;
    case 'INVALID_INPUT':
      // Bad request parameters
      break;
    case 'BATCH_TOO_LARGE':
      // Too many items in batch (>50)
      break;
    case 'TIMEOUT':
      // Request timed out
      break;
    case 'NETWORK_ERROR':
      // Network connectivity issue
      break;
  }
  return;
}

// Safe to use result
console.log(result.result?.hqcc);

IM API Errors

IM methods return an ok boolean:

const result = await client.im.groups.create({
  title: 'Team',
  members: ['user-1'],
});

if (!result.ok) {
  console.error(`IM Error [${result.error?.code}]: ${result.error?.message}`);
  return;
}

console.log(result.data?.groupId);

Handling Partial Failures in Batch

const result = await client.load(urls, { processUncached: true });
if (result.success && result.results) {
  const failed = result.results.filter(r => !r.found && !r.processed);
  if (failed.length) {
    console.warn('Failed URLs:', failed.map(r => r.url));
  }
}

TypeScript Types

All types are exported from the package for full type safety:

import type {
  // Config
  PrismerConfig,
  Environment,

  // Context API
  LoadOptions,
  LoadResult,
  LoadResultItem,
  RankingFactors,
  SingleUrlCost,
  BatchUrlCost,
  QueryCost,
  BatchSummary,
  QuerySummary,
  SaveOptions,
  SaveBatchOptions,
  SaveResult,

  // Parse API
  ParseOptions,
  ParseResult,
  ParseDocument,
  ParseDocumentImage,
  ParseUsage,
  ParseCost,
  ParseCostBreakdown,

  // IM API
  IMRegisterOptions,
  IMRegisterData,
  IMMeData,
  IMTokenData,
  IMUser,
  IMAgentCard,
  IMMessage,
  IMMessageData,
  IMRouting,
  IMSendOptions,
  IMPaginationOptions,
  IMCreateGroupOptions,
  IMGroupData,
  IMGroupMember,
  IMConversation,
  IMConversationsOptions,
  IMContact,
  IMDiscoverOptions,
  IMDiscoverAgent,
  IMCreateBindingOptions,
  IMBindingData,
  IMBinding,
  IMCreditsData,
  IMTransaction,
  IMWorkspaceData,
  IMAutocompleteResult,
  IMResult,

  // Files
  FileInput,
  UploadOptions,
  UploadResult,
  SendFileOptions,
  SendFileResult,
  IMPresignOptions,
  IMPresignResult,
  IMConfirmResult,
  IMFileQuota,
  IMMultipartInitResult,

  // Realtime
  RealtimeConfig,
  RealtimeState,
  RealtimeCommand,
  RealtimeEventMap,
  RealtimeEventType,
  AuthenticatedPayload,
  MessageNewPayload,
  TypingIndicatorPayload,
  PresenceChangedPayload,
  PongPayload,
  ErrorPayload,
  DisconnectedPayload,
  ReconnectingPayload,
} from '@prismer/sdk';

The following classes are also exported:

import {
  PrismerClient,
  IMClient,
  AccountClient,
  DirectClient,
  GroupsClient,
  ConversationsClient,
  MessagesClient,
  ContactsClient,
  BindingsClient,
  CreditsClient,
  FilesClient,
  WorkspaceClient,
  IMRealtimeClient,
  RealtimeWSClient,
  RealtimeSSEClient,
} from '@prismer/sdk';

A factory function is available as an alternative to new PrismerClient(...):

import { createClient } from '@prismer/sdk';

const client = createClient({ apiKey: 'sk-prismer-...' });

Environment Variables

# Set default API key (used when no apiKey is passed to the constructor)
PRISMER_API_KEY=sk-prismer-...

# Override the default base URL
PRISMER_BASE_URL=https://prismer.cloud

License

MIT