CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-langchain

TypeScript framework for building LLM-powered applications with agents, tools, middleware, and model interoperability

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

storage.mddocs/guides/

Storage Guide

This guide covers using storage implementations for persisting key-value data.

In-Memory Store

Basic Usage

import { InMemoryStore } from "langchain";

const store = new InMemoryStore<{ name: string; age: number }>();

// Set values
await store.mset([
  ["user:1", { name: "Alice", age: 30 }],
  ["user:2", { name: "Bob", age: 25 }],
]);

// Get values
const [user1, user2] = await store.mget(["user:1", "user:2"]);
console.log(user1); // { name: "Alice", age: 30 }

// Delete values
await store.mdelete(["user:1"]);

// Iterate keys
for await (const key of store.yieldKeys("user:")) {
  console.log(key); // "user:1", "user:2"
}

With Agent

import { createAgent, InMemoryStore } from "langchain";

const store = new InMemoryStore();

// Pre-populate with data
await store.mset([
  ["user:preferences", { theme: "dark", language: "en" }],
  ["user:history", { lastVisit: "2024-01-15" }],
]);

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  store: store,
});

// Agent can access store during execution

File System Store

Basic Usage

import { LocalFileStore } from "langchain/storage/file_system";

// Create store at specific path
const store = await LocalFileStore.fromPath("./data/store");

// Store binary data
const encoder = new TextEncoder();
await store.mset([
  ["doc:1", encoder.encode("Document 1 content")],
  ["doc:2", encoder.encode("Document 2 content")],
]);

// Retrieve data
const [doc1, doc2] = await store.mget(["doc:1", "doc:2"]);
const decoder = new TextDecoder();
console.log(decoder.decode(doc1)); // "Document 1 content"

// Iterate keys
for await (const key of store.yieldKeys("doc:")) {
  console.log(key);
}

// Delete
await store.mdelete(["doc:1"]);

Direct File Access

import { LocalFileStore } from "langchain/storage/file_system";

const store = new LocalFileStore({ rootPath: "./data" });

// Get single file
const file = await store.getParsedFile("config.json");
if (file) {
  const decoder = new TextDecoder();
  console.log(decoder.decode(file));
}

Encoder-Backed Store

With Type Safety

import { EncoderBackedStore, LocalFileStore } from "langchain/storage/encoder_backed";

interface User {
  id: number;
  name: string;
  email: string;
}

// Create file-backed store with JSON encoding
const fileStore = await LocalFileStore.fromPath("./users");

const userStore = new EncoderBackedStore<number, User, Uint8Array>({
  store: fileStore,
  keyEncoder: (id) => `user:${id}`,
  valueSerializer: (user) => new TextEncoder().encode(JSON.stringify(user)),
  valueDeserializer: (data) => JSON.parse(new TextDecoder().decode(data)),
});

// Use with type safety
await userStore.mset([
  [1, { id: 1, name: "Alice", email: "alice@example.com" }],
  [2, { id: 2, name: "Bob", email: "bob@example.com" }],
]);

const [user1] = await userStore.mget([1]);
console.log(user1); // { id: 1, name: "Alice", email: "alice@example.com" }

Custom Serialization

import { EncoderBackedStore } from "langchain/storage/encoder_backed";
import msgpack from "msgpack-lite";

const store = new EncoderBackedStore({
  store: baseStore,
  keyEncoder: (key) => `data:${key}`,
  valueSerializer: (value) => msgpack.encode(value),
  valueDeserializer: (data) => msgpack.decode(data),
});

Document Store

Creating Document Store

import { createDocumentStoreFromByteStore, LocalFileStore } from "langchain/storage/encoder_backed";
import { Document } from "langchain";

// Create document store from file store
const fileStore = await LocalFileStore.fromPath("./documents");
const docStore = createDocumentStoreFromByteStore(fileStore);

// Store documents
await docStore.mset([
  [
    "doc1",
    new Document({
      pageContent: "Content of document 1",
      metadata: { author: "Alice", date: "2024-01-01" },
    }),
  ],
  [
    "doc2",
    new Document({
      pageContent: "Content of document 2",
      metadata: { author: "Bob", date: "2024-01-02" },
    }),
  ],
]);

// Retrieve documents
const [doc1, doc2] = await docStore.mget(["doc1", "doc2"]);
console.log(doc1.pageContent);
console.log(doc1.metadata);

Batch Operations

// Store multiple documents
const documents = [
  ["doc:1", new Document({ pageContent: "Content 1" })],
  ["doc:2", new Document({ pageContent: "Content 2" })],
  ["doc:3", new Document({ pageContent: "Content 3" })],
];

await docStore.mset(documents);

// Retrieve multiple
const docs = await docStore.mget(["doc:1", "doc:2", "doc:3"]);

// Delete multiple
await docStore.mdelete(["doc:1", "doc:2"]);

Common Patterns

Namespaced Keys

const store = new InMemoryStore();

// Organize with prefixes
await store.mset([
  ["users:1", userData1],
  ["users:2", userData2],
  ["sessions:abc", sessionData1],
  ["sessions:xyz", sessionData2],
  ["config:app", configData],
]);

// Query by namespace
for await (const key of store.yieldKeys("users:")) {
  console.log(key); // "users:1", "users:2"
}

for await (const key of store.yieldKeys("sessions:")) {
  console.log(key); // "sessions:abc", "sessions:xyz"
}

Caching

const cache = new InMemoryStore<string>();

async function getCachedData(key: string) {
  // Check cache
  const [cached] = await cache.mget([key]);
  if (cached) {
    return cached;
  }

  // Fetch and cache
  const data = await fetchExpensiveData(key);
  await cache.mset([[key, data]]);
  return data;
}

Session Storage

interface Session {
  userId: string;
  data: Record<string, any>;
  expiresAt: number;
}

const sessionStore = new InMemoryStore<Session>();

async function saveSession(sessionId: string, userId: string, data: any) {
  await sessionStore.mset([
    [
      `session:${sessionId}`,
      {
        userId,
        data,
        expiresAt: Date.now() + 3600000, // 1 hour
      },
    ],
  ]);
}

async function getSession(sessionId: string) {
  const [session] = await sessionStore.mget([`session:${sessionId}`]);
  if (!session) return null;

  // Check expiration
  if (session.expiresAt < Date.now()) {
    await sessionStore.mdelete([`session:${sessionId}`]);
    return null;
  }

  return session;
}

Configuration Storage

const configStore = new InMemoryStore<any>();

async function loadConfig() {
  const [config] = await configStore.mget(["app:config"]);
  return config || getDefaultConfig();
}

async function saveConfig(config: any) {
  await configStore.mset([["app:config", config]]);
}

async function updateConfig(updates: Partial<any>) {
  const config = await loadConfig();
  const newConfig = { ...config, ...updates };
  await saveConfig(newConfig);
}

User Preferences

interface UserPreferences {
  theme: "light" | "dark";
  language: string;
  notifications: boolean;
  customSettings: Record<string, any>;
}

const prefStore = new InMemoryStore<UserPreferences>();

async function getUserPreferences(userId: string) {
  const [prefs] = await prefStore.mget([`prefs:${userId}`]);
  return prefs || getDefaultPreferences();
}

async function updateUserPreferences(
  userId: string,
  updates: Partial<UserPreferences>
) {
  const prefs = await getUserPreferences(userId);
  const newPrefs = { ...prefs, ...updates };
  await prefStore.mset([[`prefs:${userId}`, newPrefs]]);
}

Persistence Strategies

Development

// Use in-memory for development
const devStore = new InMemoryStore();

Production

// Use file system for persistence
const prodStore = await LocalFileStore.fromPath("./data/storage");

Hybrid

// In-memory cache backed by file system
const fileStore = await LocalFileStore.fromPath("./data");
const cache = new InMemoryStore();

async function getWithCache(key: string) {
  // Check cache first
  const [cached] = await cache.mget([key]);
  if (cached) return cached;

  // Load from disk
  const encoder = new TextEncoder();
  const decoder = new TextDecoder();
  const [data] = await fileStore.mget([key]);
  if (!data) return null;

  const value = JSON.parse(decoder.decode(data));

  // Cache for next time
  await cache.mset([[key, value]]);

  return value;
}

Best Practices

Key Naming

  • Use consistent prefixes: user:123, session:abc
  • Include type information in prefix
  • Use hierarchical keys: app:config:feature
  • Keep keys readable and meaningful

In-Memory Store

  • Fast but not persistent
  • Good for caching and temporary data
  • Lost on process restart
  • Use for development and testing

File System Store

  • Persistent across restarts
  • Good for local development
  • Not suitable for distributed systems
  • Ensure proper file permissions
  • Handle disk space limitations

Encoder-Backed Store

  • Adds type safety to byte stores
  • Use appropriate serialization (JSON, MessagePack, etc.)
  • Handle serialization errors gracefully
  • Consider compression for large values

Performance

  • Batch operations when possible (mset, mget, mdelete)
  • Implement key expiration for caches
  • Monitor storage size and clean up old data
  • Use appropriate data structures for your use case

Error Handling

  • Handle missing keys appropriately
  • Catch and log serialization errors
  • Implement retry logic for transient failures
  • Validate data before storing

See Storage API Reference for complete API documentation.

docs

glossary.md

index.md

quick-reference.md

task-index.md

tile.json