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

@metrio-ai/memory-service

v1.0.10

Published

Memory Service SDK for Metrio AI - multi-tenant memory management with pgvector

Readme

@metrio-ai/memory-service

Multi-tenant Memory Service SDK for AI applications. Provides user memory management, semantic search, and automatic memory extraction via pgvector.

Installation

pnpm add @metrio-ai/memory-service

Environment Variables

# Required
DATABASE_URL=postgresql://user:pass@host:5432/db
GOOGLE_AI_API_KEY=your-gemini-api-key

# Optional (if using Metrio extraction)
METRIO_API_KEY=your-metrio-api-key

Quick Start

import { MemoryService } from '@metrio-ai/memory-service';

const memory = new MemoryService({
  databaseUrl: process.env.DATABASE_URL!,
  embedding: {
    provider: 'gemini',
    apiKey: process.env.GOOGLE_AI_API_KEY!
  },
  extraction: {
    provider: 'metrio',
    apiKey: process.env.METRIO_API_KEY!,
    projectId: 'your-project-id',
    extractionPromptId: 1,
    summaryMergerPromptId: 2
  }
});

// Get context before a conversation
const context = await memory.getContext('dog-lab', 'LINE_USER_ID');

// Process conversation and auto-extract memories
await memory.processConversation({
  tenantSlug: 'dog-lab',
  userExternalId: 'LINE_USER_ID',
  conversation: [
    { role: 'user', content: 'I want to sign up my dog for a class' },
    { role: 'assistant', content: 'Sure! How old is your dog?' }
  ]
});

// Semantic search
const results = await memory.search({
  tenantSlug: 'dog-lab',
  userExternalId: 'LINE_USER_ID',
  query: 'order shipping'
});

// Close connection when done
await memory.close();

API

Core Methods

| Method | Description | |---|---| | getContext(tenant, userId, options?) | Load context before a conversation (profile, recent memories, org notes/memories) | | processConversation(input) | Extract memories from a conversation and update user profile | | search(input) | Semantic search user memories | | getRecentMemories(tenant, userId, options?) | Get recent memories by recency | | addMemory(input) | Directly add a memory | | updateProfileSummary(input) | Update user profile summary | | getProfileSummary(tenant, userId) | Get user profile summary | | close() | Close the database connection pool |

Context

const context = await memory.getContext('dog-lab', 'LINE_USER_ID', {
  recentLimit: 3,
  includeOrgNotes: true,
  orgNoteCategories: ['product', 'policy'],
  includeOrgMemories: true,
  orgMemoryTypes: ['learned', 'pattern']
});

// context.formatted contains:
// 【組織資訊】 - org notes
// 【組織知識】 - org memories
// 【客戶檔案】 - user profile summary
// 【最近互動】 - recent memories

Tenant Notes

Store organization-level information (products, policies, FAQs):

await memory.tenants.notes.add('dog-lab', {
  category: 'product',
  title: 'Basic Obedience Course',
  content: 'Price: NT$ 8,000 (8 sessions)...',
  tags: ['course', 'pricing']
});

await memory.tenants.notes.search('dog-lab', { query: 'course pricing' });
await memory.tenants.notes.getByCategory('dog-lab', 'product');

Categories: product, policy, faq, announcement, custom

Tenant Memories

Store organization knowledge learned from conversations:

await memory.tenants.memories.add('dog-lab', {
  content: 'Shiba Inu training requires more patience',
  type: 'learned',
  importance: 7
});

await memory.tenants.memories.promoteFromUser('dog-lab', {
  sourceMemoryId: 'user-memory-id',
  content: 'Saturday afternoon classes are most popular',
  type: 'pattern'
});

Types: learned, feedback, pattern, exception

Admin API

Manage and inspect data via memory.admin.*:

// List all tenants
const tenants = await memory.admin.listTenants();

// List users under a tenant
const users = await memory.admin.listUsers('dog-lab');

// Semantic search across all users in a tenant
const results = await memory.admin.searchMemories('dog-lab', 'dog training', {
  limit: 10,
  threshold: 0.3
});
// → AdminSearchResult[] includes userId, userExternalId, content, similarity

// List user memories (includes rawConversation)
const memories = await memory.admin.listUserMemories('dog-lab', 'LINE_USER_ID');

// List org notes and memories
const notes = await memory.admin.listTenantNotes('dog-lab');
const orgMemories = await memory.admin.listTenantMemories('dog-lab');

// Purge (irreversible hard delete)
await memory.admin.purgeUserMemories('dog-lab', 'LINE_USER_ID');  // memories only
await memory.admin.purgeUserProfile('dog-lab', 'LINE_USER_ID');   // profile only
await memory.admin.purgeUserAll('dog-lab', 'LINE_USER_ID');       // memories + profile
await memory.admin.purgeTenantNotes('dog-lab');
await memory.admin.purgeTenantMemories('dog-lab');

context.formatted vs getProfileSummary()

getContext() returns a ContextResult with a pre-built formatted string combining all four sections (org notes, org memories, user profile, recent memories) — designed to be injected directly into an LLM system prompt.

getProfileSummary() returns only the user's profile summary (the 【客戶檔案】 portion), useful for displaying or editing in a dashboard.

Configuration

interface MemoryServiceConfig {
  databaseUrl: string;

  embedding: {
    provider: 'gemini' | 'openai';
    apiKey: string;
    model?: string; // default: gemini-embedding-001 (gemini), text-embedding-3-large (openai)
  };

  extraction?: {
    provider: 'metrio' | 'custom';
    apiKey?: string;
    projectId?: string;
    extractionPromptId?: number;
    summaryMergerPromptId?: number;
    baseUrl?: string;
    customExtractor?: ExtractionProvider;
  };
}

Database Setup

This SDK uses PostgreSQL with pgvector. Run migrations to set up the schema:

# Set DATABASE_URL in .env
cp .env.example .env

# Run migrations
pnpm db:migrate

Tables

| Table | Description | |---|---| | tenants | Multi-tenant isolation | | tenant_notes | Organization notes (products, policies, FAQs) | | tenant_memories | Organization knowledge from conversations | | users | Users scoped to tenants via external ID | | user_profiles | User profile summaries with embeddings | | memories | User conversation memories with embeddings |

Development

pnpm install
pnpm build          # Build with tsup
pnpm test           # Run tests with vitest
pnpm db:generate    # Generate new migration after schema changes
pnpm db:migrate     # Apply migrations
pnpm db:studio      # Open Drizzle Studio GUI

License

ISC