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

briyah

v1.1.6

Published

Briyah multi-agent AI SDK

Readme

Briyah SDK

Briyah is an SDK for AI agents, multi-agent rooms, and interactive stories. It wraps the Briyah runtime as a single class with per-user data isolation and balance tracking, and supports Anthropic, OpenAI, Google, Grok, DeepSeek, Together, and Fal as LLM providers.

What's in the package:

  • Agents. AI agents with a system prompt, persistent conversation history, attached documents, and per-call cost and token tracking. Histories can be summarized/compacted or cleared.
  • Rooms. Multi-agent conversations with a shared goal. Agents exchange messages at different visibility levels (speak, whisper, think, shout), draft and approve shared artifacts, and a moderator can route turns.
  • Stories. Text-based interactive fiction with a narrator, AI-played characters, and a human player. Stories progress through chapters and can introduce new characters mid-game. Story events (state updates, character suggestions, chapter transitions, errors) are delivered through an emitter the host app subscribes to.
  • Text processing. One-shot processText for non-conversational use, with cost and token counts on the result.
  • File attachments. Attach documents to agents as context. Supported file types vary by LLM provider.
  • Per-user data. Agents, rooms, stories, attached files, balances, and transactions are scoped to a userId the host controls. Per-user directories keep state isolated.
  • Balances and transactions. Track per-user balances against usage cost. Record pending, succeeded, failed, or cancelled transactions when integrating with a payment provider, credit balances on webhook confirmation, and resume stories that paused on insufficient funds. Briyah does not process payments itself.
  • Real-time event emitters. Story-state and balance updates can be forwarded to SSE or websockets.

State is persisted as JSON files under a configurable data path; no external database is required.

Installation

npm install briyah
import { Briyah } from 'briyah';

Quick Start

import { Briyah } from 'briyah';

// 1. Create and initialize Briyah instance
const briyah = new Briyah({
    dataPath: './my-briyah-data',
    userServiceCacheTimeoutMinutes: 30,
    startingBalance: 10.00
});

await briyah.init();

// 2. Get user-specific service (userId managed by your app)
const appService = briyah.getAppService('user-123');

// 3. Use full Briyah functionality
// createAgent() registers the agent in memory immediately — agent.id is usable right away.
// Call agent.save() when you want to persist it to disk.
const agent = appService.createAgent(
    'Anthropic',
    'AI Assistant',
    'James',
    'A helpful AI assistant',
    'claude-haiku-4-5'
);

if (!agent.id) throw new Error('Agent creation failed');
const result = await appService.processText(agent.id, 'Hello! How are you?');
console.log(result.result);

agent.save(); // persist to disk

// 4. Cleanup when done
await briyah.shutdown();

Configuration

BriyahConfigOptions

interface BriyahConfigOptions {
    /**
     * Base directory for Briyah data storage
     * Default: './briyah-data' relative to process.cwd()
     */
    dataPath?: string;

    /**
     * Timeout in minutes for cached user services
     * Default: 30 minutes
     */
    userServiceCacheTimeoutMinutes?: number;

    /**
     * Starting balance for new users (in dollars)
     * Default: value from process.env.STARTING_BALANCE
     */
    startingBalance?: number;

    /**
     * Override environment variables
     * Useful for testing or multi-instance configurations
     */
    envOverrides?: Record<string, string>;
}

Environment Variables

LLM Provider API Keys (at least one required):

  • ANTHROPIC_API_KEY - For Claude models
  • OPENAI_API_KEY - For GPT models
  • GOOGLE_GENAI_API_KEY - For Google AI (Gemini) models
  • XAI_API_KEY - For Grok models
  • DEEPSEEK_API_KEY - For DeepSeek models
  • TOGETHER_API_KEY - For Together AI models
  • FAL_API_KEY - For Fal image-generation models

Optional:

  • STARTING_BALANCE - Starting balance for new users (e.g., "10.00")
  • BRIYAH_DATA_PATH - Global default data path (overridden by constructor dataPath)
  • USER_SERVICE_CACHE_TIMEOUT_MINUTES - Cache timeout (overridden by constructor option)

Logging

Briyah writes logs to {dataPath}/logs/briyah.log by default. Configure or disable via the logging option:

const briyah = new Briyah({
    dataPath: './my-data',
    logging: {
        enabled: true,                        // default
        logFile: './my-data/logs/app.log',    // default: {dataPath}/logs/briyah.log
        console: false,                       // set true to also log to stdout/stderr
        level: 'warn',                        // 'debug' | 'log' | 'warn' | 'error' — default: 'log'
    }
});

// Log to console only (no file):
const briyah = new Briyah({ logging: { console: true, logFile: null } });

// Disable logging entirely:
const briyah = new Briyah({ logging: { enabled: false } });

API Reference

Briyah Class

constructor(options?: BriyahConfigOptions)

Creates a new Briyah SDK instance.

const briyah = new Briyah({
    dataPath: './briyah-data',
    startingBalance: 10.00
});

async init(): Promise<void>

Initializes the Briyah system. Must be called before using getAppService().

await briyah.init();

getAppService(userId: string): AppService

Gets the AppService instance for a specific user. The AppService provides full access to:

  • Agent management
  • Room conversations
  • Story generation
  • Text processing
  • File attachments
const appService = briyah.getAppService('user-123');

Throws: Error if init() has not been called.

removeUserService(userId: string): void

Manually removes a user's service from the cache. Useful for:

  • Forcing a fresh AppService instance
  • Cleaning up when a user logs out
briyah.removeUserService('user-123');

getCacheStats()

Returns statistics about cached user services.

const stats = briyah.getCacheStats();
console.log(`Cached users: ${stats.cachedUsers}`);

async shutdown(): Promise<void>

Shuts down the Briyah system and cleans up resources.

await briyah.shutdown();

isInitialized(): boolean

Checks if Briyah has been initialized.

if (briyah.isInitialized()) {
    const appService = briyah.getAppService('user-123');
}

AppService

The AppService provides full access to Briyah functionality.

Common operations:

// Agent Management
const agent = appService.createAgent(provider, name, nickname, description, model);
const agents = await appService.listAgents();
await appService.deleteAgent(agentId);
await appService.reloadAgent(agentId);              // Clear conversation history (keeps any prior summary)
await appService.compactAgentConversation(agentId); // Summarize history into a single message

// Room Management
const room = await appService.createRoom(name, goal, agentIds);
const rooms = await appService.listRooms();
await appService.sendRoomMessage(roomId, content, sender, action?);

// Story Management
const story = await appService.createStory(name, idea, userCharacterDesc, otherCharactersDesc, storyModel?);
await appService.progressStory(storyId);

// Text Processing
const result = await appService.processText(agentId, text);

// File Attachments
const attachment = await appService.attachDocument(agentId, fileName, fileData);
await appService.deleteAttachedFile(agentId, fileName);       // by filename
await appService.deleteAttachedFileById(documentId);           // by document ID

Usage Examples

Example 1: Multi-User Setup

import { Briyah } from 'briyah';

// Initialize once at application startup
const briyah = new Briyah({
    dataPath: './data/briyah',
    startingBalance: 10.00
});

await briyah.init();

// In your route handler or service
async function handleUserRequest(userId: string, message: string) {
    const appService = briyah.getAppService(userId);

    // Each user gets their own isolated AppService
    const agents = await appService.listAgents();

    // ... process user request
}

// Cleanup at application shutdown
process.on('SIGINT', async () => {
    await briyah.shutdown();
    process.exit(0);
});

Example 2: Custom Data Path

import { Briyah } from 'briyah';
import path from 'path';

const briyah = new Briyah({
    dataPath: path.join(__dirname, '..', 'user-data', 'briyah'),
    userServiceCacheTimeoutMinutes: 60 // 1 hour cache
});

await briyah.init();

Example 3: Testing Configuration

import { Briyah } from 'briyah';

const testBriyah = new Briyah({
    dataPath: './test-data',
    startingBalance: 100.00,
    userServiceCacheTimeoutMinutes: 5,
    envOverrides: {
        ANTHROPIC_API_KEY: process.env.TEST_ANTHROPIC_KEY,
        OPENAI_API_KEY: process.env.TEST_OPENAI_KEY
    }
});

await testBriyah.init();

// Run tests...

await testBriyah.shutdown();

Example 4: Agent Creation and Text Processing

const appService = briyah.getAppService('user-123');

// Create an agent
const agent = appService.createAgent(
    'Anthropic',           // provider
    'AI Assistant',        // name
    'James',               // nickname
    'A helpful AI assistant',          // description
    'claude-haiku-4-5'  // model
);

if (!agent.id) throw new Error('Agent creation failed');
console.log(`Created agent: ${agent.id}`);

// Process text with the agent
const result = await appService.processText(
    agent.id,
    'What is the capital of France?'
);

console.log(`Response: ${result.result}`);
console.log(`Cost: $${result.totalCost}`);
console.log(`Tokens: ${(result.totalInputTokens ?? 0) + (result.totalOutputTokens ?? 0)}`);

Example 5: Multi-Agent Room Conversation

const appService = briyah.getAppService('user-123');

// Create agents
const analyst = appService.createAgent('OpenAI', 'Analyst', 'Analyst', 'Data analyst', 'gpt-4');
const writer = appService.createAgent('Anthropic', 'Writer', 'Writer', 'Content writer', 'claude-haiku-4-5');

if (!analyst.id || !writer.id) throw new Error('Agent creation failed');

// Create a room with both agents
const room = await appService.createRoom(
    'Analysis Session',
    'Analyze sales data and produce a written summary',
    [analyst.id, writer.id]
);

// Send a message to start the conversation
await appService.sendRoomMessage(
    room.roomId,
    'Please analyze the sales data for Q4',
    'Analyst',
    'speak'
);

// The agents will automatically respond and interact
// Check room messages to see the conversation
const messages = await appService.getRoomMessages(room.roomId);
console.log(`Messages: ${messages.messages.length}`);

Example 6: Story Message Emitter

The story message emitter delivers real-time events during gameplay. Subscribe to it after creating the story but before the first player turn, so no events are missed.

import type {
    StoryStateEvent,
    StoryIntroduceCharacterEvent,
    StoryProgressChapterEvent,
    StoryErrorEvent,
} from 'briyah';

const app = briyah.getAppService('user-123');

const story = await app.createStory(
    'The Lost Kingdom',
    'A medieval fantasy where ancient ruins hold a terrible secret',
    'A disgraced knight seeking redemption'
);

const emitter = app.getStoryMessageEmitter(story.id);

// Fires after every turn with the full updated game state.
emitter.on('story-state', async (event: StoryStateEvent) => {
    const { state } = event;
    console.log('Latest message:', state.latestRoomMessage?.content);

    // Detect the player's turn by comparing speaker names.
    // Do NOT use state.humanPrompt for this — it is a UI display string,
    // not a reliable turn indicator.
    if (state.currentSpeaker === state.userAgentName) {
        const input = await promptPlayer(state.humanPrompt);
        await app.respondToStory(story.id, input);
    }
});

// Fires when the narrator wants to introduce a new character.
// The host app should present this to the player before acting.
// Accept by calling introduceCharacterToStory, or decline with declineCharacter.
emitter.on('suggest-introduce-character', async (event: StoryIntroduceCharacterEvent) => {
    const accept = await askPlayer(`Add ${event.characterName} to the story?`);
    if (accept) {
        await app.introduceCharacterToStory(story.id, event.characterName!, '', undefined, true);
    } else {
        await app.declineCharacter(story.id, event.characterName!);
    }
});

// Fires when the narrator wants to advance to the next chapter.
// Call progressStory to accept. Ignoring the event stays in the current chapter —
// there is no explicit rejection call.
emitter.on('suggest-progress-chapter', async (_event: StoryProgressChapterEvent) => {
    const accept = await askPlayer('The narrator suggests ending this chapter. Continue?');
    if (accept) {
        await app.progressStory(story.id);
    }
});

// Fires on fatal errors during room processing.
// Named 'story-error' rather than 'error' to avoid Node.js throwing when no
// listener is attached.
emitter.on('story-error', (event: StoryErrorEvent) => {
    if (event.errorType === 'InsufficientBalanceError') {
        console.error('Out of credits:', event.message);
    } else {
        console.error(`Story error [${event.errorType}]:`, event.message);
    }
});

Example 7: Recording Payments and Managing Balance

Briyah does not process payments itself — your application handles the payment provider interaction. Once a payment is confirmed, use AppService to record the transaction, credit the user's balance, and restart any stories that stalled due to insufficient funds.

const app = briyah.getAppService(userId);

// --- When your payment provider initiates a charge ---
// Record it as pending so the transaction log stays consistent.
await app.recordTransaction(amount, paymentIntentId, 'pending');

// --- When your payment provider webhook confirms success ---
await app.updateTransactionStatus(paymentIntentId, 'succeeded');
await app.addBalance(amount);

// Resume any stories that paused mid-turn due to InsufficientBalanceError.
await app.resumePausedStories();

// --- When a payment fails or is cancelled ---
await app.updateTransactionStatus(paymentIntentId, 'failed');

// --- Querying balance and history ---
const balance = app.getBalance();

const { transactions, total } = await app.getTransactions(50, 0);

const tx = await app.getTransactionByPaymentId(paymentIntentId);
console.log(tx?.status); // 'pending' | 'succeeded' | 'failed' | 'cancelled'

To push real-time balance updates to a connected client (e.g. via SSE), subscribe to the balance emitter before crediting the user:

const emitter = app.getBalanceMessageEmitter(userId);
emitter.on('update', (newBalance: number) => {
    // Push newBalance to the client
});

Data Storage

Briyah stores data in the following structure:

{dataPath}/
├── common/                      # Shared across all users
│   ├── config/                  # LLM pricing and image-model config
│   ├── prompts/                 # Global prompt templates
│   └── published-agents.json    # Published agent mappings
└── user/
    └── {userId}/                # Per-user data
        ├── prompts/             # User-specific prompts
        ├── upload/              # User file attachments
        └── userconfig/          # User configuration files
            ├── agents.json      # User's agents
            ├── rooms.json       # User's rooms
            ├── stories.json     # User's stories
            └── balance.json     # User's balance

Multi-Instance Support

You can create multiple Briyah instances with different configurations:

const briyah1 = new Briyah({ dataPath: './data1' });
const briyah2 = new Briyah({ dataPath: './data2' });

await briyah1.init();
await briyah2.init();

// Each instance has isolated data
const user1Service = briyah1.getAppService('user-123');
const user2Service = briyah2.getAppService('user-123');
// These are completely separate services with different data paths

Note: Singleton services (LLM providers, message emitters) are shared across all Briyah instances within the same process. This is safe because they are stateless or keyed by ID.

Troubleshooting

"Must call init() before getAppService()"

Make sure to call await briyah.init() before calling getAppService().

"No LLM provider API keys configured"

Set at least one of the required API key environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.).

"STARTING_BALANCE environment variable is required"

Set the STARTING_BALANCE environment variable or pass startingBalance in the constructor options.

Cache not working as expected

Check the cache statistics with getCacheStats() and adjust userServiceCacheTimeoutMinutes in the constructor options.