{"version":3,"file":"base.cjs","names":[],"sources":["../../src/store/base.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Embeddings } from \"@langchain/core/embeddings\";\n\n/**\n * Error thrown when an invalid namespace is provided.\n */\nexport class InvalidNamespaceError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = \"InvalidNamespaceError\";\n  }\n}\n\n/**\n * Validates the provided namespace.\n * @param namespace The namespace to validate.\n * @throws {InvalidNamespaceError} If the namespace is invalid.\n */\nfunction validateNamespace(namespace: string[]): void {\n  if (namespace.length === 0) {\n    throw new InvalidNamespaceError(\"Namespace cannot be empty.\");\n  }\n  for (const label of namespace) {\n    if (typeof label !== \"string\") {\n      throw new InvalidNamespaceError(\n        `Invalid namespace label '${label}' found in ${namespace}. Namespace labels ` +\n          `must be strings, but got ${typeof label}.`\n      );\n    }\n    if (label.includes(\".\")) {\n      throw new InvalidNamespaceError(\n        `Invalid namespace label '${label}' found in ${namespace}. Namespace labels cannot contain periods ('.').`\n      );\n    }\n    if (label === \"\") {\n      throw new InvalidNamespaceError(\n        `Namespace labels cannot be empty strings. Got ${label} in ${namespace}`\n      );\n    }\n  }\n  if (namespace[0] === \"langgraph\") {\n    throw new InvalidNamespaceError(\n      `Root label for namespace cannot be \"langgraph\". Got: ${namespace}`\n    );\n  }\n}\n\n/**\n * Represents a stored item with metadata.\n */\nexport interface Item {\n  /**\n   * The stored data as an object. Keys are filterable.\n   */\n  value: Record<string, any>;\n  /**\n   * Unique identifier within the namespace.\n   */\n  key: string;\n  /**\n   * Hierarchical path defining the collection in which this document resides.\n   * Represented as an array of strings, allowing for nested categorization.\n   * For example: [\"documents\", \"user123\"]\n   */\n  namespace: string[];\n  /**\n   * Timestamp of item creation.\n   */\n  createdAt: Date;\n  /**\n   * Timestamp of last update.\n   */\n  updatedAt: Date;\n}\n\n/**\n * Represents a search result item with relevance score.\n * Extends the base Item interface with an optional similarity score.\n */\nexport interface SearchItem extends Item {\n  /**\n   * Relevance/similarity score if from a ranked operation.\n   * Higher scores indicate better matches.\n   *\n   * This is typically a cosine similarity score between -1 and 1,\n   * where 1 indicates identical vectors and -1 indicates opposite vectors.\n   */\n  score?: number;\n}\n\n/**\n * Operation to retrieve an item by namespace and ID.\n */\nexport interface GetOperation {\n  /**\n   * Hierarchical path for the item.\n   *\n   * @example\n   * // Get a user profile\n   * namespace: [\"users\", \"profiles\"]\n   */\n  namespace: string[];\n\n  /**\n   * Unique identifier within the namespace.\n   * Together with namespace forms the complete path to the item.\n   *\n   * @example\n   * key: \"user123\"  // For a user profile\n   * key: \"doc456\"   // For a document\n   */\n  key: string;\n}\n\n/**\n * Operation to search for items within a namespace prefix.\n */\nexport interface SearchOperation {\n  /**\n   * Hierarchical path prefix to search within.\n   * Only items under this prefix will be searched.\n   *\n   * @example\n   * // Search all user documents\n   * namespacePrefix: [\"users\", \"documents\"]\n   *\n   * // Search everything\n   * namespacePrefix: []\n   */\n  namespacePrefix: string[];\n\n  /**\n   * Key-value pairs to filter results based on exact matches or comparison operators.\n   *\n   * Supports both exact matches and operator-based comparisons:\n   * - $eq: Equal to (same as direct value comparison)\n   * - $ne: Not equal to\n   * - $gt: Greater than\n   * - $gte: Greater than or equal to\n   * - $lt: Less than\n   * - $lte: Less than or equal to\n   *\n   * @example\n   * // Exact match\n   * filter: { status: \"active\" }\n   *\n   * // With operators\n   * filter: { score: { $gt: 4.99 } }\n   *\n   * // Multiple conditions\n   * filter: {\n   *   score: { $gte: 3.0 },\n   *   color: \"red\"\n   * }\n   */\n  filter?: Record<string, any>;\n\n  /**\n   * Maximum number of items to return.\n   * @default 10\n   */\n  limit?: number;\n\n  /**\n   * Number of items to skip before returning results.\n   * Useful for pagination.\n   * @default 0\n   */\n  offset?: number;\n\n  /**\n   * Natural language search query for semantic search.\n   * When provided, results will be ranked by relevance to this query\n   * using vector similarity search.\n   *\n   * @example\n   * // Find technical documentation about APIs\n   * query: \"technical documentation about REST APIs\"\n   *\n   * // Find recent ML papers\n   * query: \"machine learning papers from 2023\"\n   */\n  query?: string;\n}\n\n/**\n * Operation to store, update, or delete an item.\n */\nexport interface PutOperation {\n  /**\n   * Hierarchical path for the item.\n   * Acts as a folder-like structure to organize items.\n   * Each element represents one level in the hierarchy.\n   *\n   * @example\n   * // Root level documents\n   * namespace: [\"documents\"]\n   *\n   * // User-specific documents\n   * namespace: [\"documents\", \"user123\"]\n   *\n   * // Nested cache structure\n   * namespace: [\"cache\", \"docs\", \"v1\"]\n   */\n  namespace: string[];\n\n  /**\n   * Unique identifier for the document within its namespace.\n   * Together with namespace forms the complete path to the item.\n   *\n   * Example: If namespace is [\"documents\", \"user123\"] and key is \"report1\",\n   * the full path would effectively be \"documents/user123/report1\"\n   */\n  key: string;\n\n  /**\n   * Data to be stored, or null to delete the item.\n   * Must be a JSON-serializable object with string keys.\n   * Setting to null signals that the item should be deleted.\n   *\n   * @example\n   * {\n   *   field1: \"string value\",\n   *   field2: 123,\n   *   nested: { can: \"contain\", any: \"serializable data\" }\n   * }\n   */\n  value: Record<string, any> | null;\n\n  /**\n   * Controls how the item's fields are indexed for search operations.\n   *\n   * - undefined: Uses store's default indexing configuration\n   * - false: Disables indexing for this item\n   * - string[]: List of field paths to index\n   *\n   * Path syntax supports:\n   * - Nested fields: \"metadata.title\"\n   * - Array access: \"chapters[*].content\" (each indexed separately)\n   * - Specific indices: \"authors[0].name\"\n   *\n   * @example\n   * // Index specific fields\n   * index: [\"metadata.title\", \"chapters[*].content\"]\n   *\n   * // Disable indexing\n   * index: false\n   */\n  index?: false | string[];\n}\n\n/**\n * Operation to list and filter namespaces in the store.\n */\nexport interface ListNamespacesOperation {\n  matchConditions?: MatchCondition[];\n  maxDepth?: number;\n  limit: number;\n  offset: number;\n}\n\nexport type NameSpacePath = (string | \"*\")[];\n\nexport type NamespaceMatchType = \"prefix\" | \"suffix\";\n\nexport interface MatchCondition {\n  matchType: NamespaceMatchType;\n  path: NameSpacePath;\n}\n\nexport type Operation =\n  | GetOperation\n  | SearchOperation\n  | PutOperation\n  | ListNamespacesOperation;\n\nexport type OperationResults<Tuple extends readonly Operation[]> = {\n  [K in keyof Tuple]: Tuple[K] extends PutOperation\n    ? void\n    : Tuple[K] extends SearchOperation\n      ? SearchItem[]\n      : Tuple[K] extends GetOperation\n        ? Item | null\n        : Tuple[K] extends ListNamespacesOperation\n          ? string[][]\n          : never;\n};\n\n/**\n * Configuration for indexing documents for semantic search in the store.\n *\n * This configures how documents are embedded and indexed for vector similarity search.\n */\nexport interface IndexConfig {\n  /**\n   * Number of dimensions in the embedding vectors.\n   *\n   * Common embedding model dimensions:\n   * - OpenAI text-embedding-3-large: 256, 1024, or 3072\n   * - OpenAI text-embedding-3-small: 512 or 1536\n   * - OpenAI text-embedding-ada-002: 1536\n   * - Cohere embed-english-v3.0: 1024\n   * - Cohere embed-english-light-v3.0: 384\n   * - Cohere embed-multilingual-v3.0: 1024\n   * - Cohere embed-multilingual-light-v3.0: 384\n   */\n  dims: number;\n\n  /**\n   * The embeddings model to use for generating vectors.\n   * This should be a LangChain Embeddings implementation.\n   */\n  embeddings: Embeddings;\n\n  /**\n   * Fields to extract text from for embedding generation.\n   *\n   * Path syntax supports:\n   * - Simple field access: \"field\"\n   * - Nested fields: \"metadata.title\"\n   * - Array indexing:\n   *   - All elements: \"chapters[*].content\"\n   *   - Specific index: \"authors[0].name\"\n   *   - Last element: \"array[-1]\"\n   *\n   * @default [\"$\"] Embeds the entire document as one vector\n   */\n  fields?: string[];\n}\n\n/**\n * Utility function to get text at a specific JSON path\n */\nexport function getTextAtPath(obj: any, path: string): string[] {\n  const parts = path.split(\".\");\n  let current: any = obj;\n\n  for (const part of parts) {\n    if (part.includes(\"[\")) {\n      const [arrayName, indexStr] = part.split(\"[\");\n      const index = indexStr.replace(\"]\", \"\");\n\n      if (!current[arrayName]) return [];\n\n      if (index === \"*\") {\n        const results: string[] = [];\n        for (const item of current[arrayName]) {\n          if (typeof item === \"string\") results.push(item);\n        }\n        return results;\n      }\n\n      const idx = parseInt(index, 10);\n      if (Number.isNaN(idx)) return [];\n      current = current[arrayName][idx];\n    } else {\n      current = current[part];\n    }\n\n    if (current === undefined) return [];\n  }\n\n  return typeof current === \"string\" ? [current] : [];\n}\n\n/**\n * Tokenizes a JSON path into parts\n */\nexport function tokenizePath(path: string): string[] {\n  return path.split(\".\");\n}\n\n/**\n * Abstract base class for persistent key-value stores.\n *\n * Stores enable persistence and memory that can be shared across threads,\n * scoped to user IDs, assistant IDs, or other arbitrary namespaces.\n *\n * Features:\n * - Hierarchical namespaces for organization\n * - Key-value storage with metadata\n * - Vector similarity search (if configured)\n * - Filtering and pagination\n */\nexport abstract class BaseStore {\n  /**\n   * Execute multiple operations in a single batch.\n   * This is more efficient than executing operations individually.\n   *\n   * @param operations Array of operations to execute\n   * @returns Promise resolving to results matching the operations\n   */\n  abstract batch<Op extends Operation[]>(\n    operations: Op\n  ): Promise<OperationResults<Op>>;\n\n  /**\n   * Retrieve a single item by its namespace and key.\n   *\n   * @param namespace Hierarchical path for the item\n   * @param key Unique identifier within the namespace\n   * @returns Promise resolving to the item or null if not found\n   */\n  async get(namespace: string[], key: string): Promise<Item | null> {\n    return (await this.batch<[GetOperation]>([{ namespace, key }]))[0];\n  }\n\n  /**\n   * Search for items within a namespace prefix.\n   * Supports both metadata filtering and vector similarity search.\n   *\n   * @param namespacePrefix Hierarchical path prefix to search within\n   * @param options Search options for filtering and pagination\n   * @returns Promise resolving to list of matching items with relevance scores\n   *\n   * @example\n   * // Search with filters\n   * await store.search([\"documents\"], {\n   *   filter: { type: \"report\", status: \"active\" },\n   *   limit: 5,\n   *   offset: 10\n   * });\n   *\n   * // Vector similarity search\n   * await store.search([\"users\", \"content\"], {\n   *   query: \"technical documentation about APIs\",\n   *   limit: 20\n   * });\n   */\n  async search(\n    namespacePrefix: string[],\n    options: {\n      filter?: Record<string, any>;\n      limit?: number;\n      offset?: number;\n      query?: string;\n    } = {}\n  ): Promise<SearchItem[]> {\n    const { filter, limit = 10, offset = 0, query } = options;\n    return (\n      await this.batch<[SearchOperation]>([\n        {\n          namespacePrefix,\n          filter,\n          limit,\n          offset,\n          query,\n        },\n      ])\n    )[0];\n  }\n\n  /**\n   * Store or update an item.\n   *\n   * @param namespace Hierarchical path for the item\n   * @param key Unique identifier within the namespace\n   * @param value Object containing the item's data\n   * @param index Optional indexing configuration\n   *\n   * @example\n   * // Simple storage\n   * await store.put([\"docs\"], \"report\", { title: \"Annual Report\" });\n   *\n   * // With specific field indexing\n   * await store.put(\n   *   [\"docs\"],\n   *   \"report\",\n   *   {\n   *     title: \"Q4 Report\",\n   *     chapters: [{ content: \"...\" }, { content: \"...\" }]\n   *   },\n   *   [\"title\", \"chapters[*].content\"]\n   * );\n   */\n  async put(\n    namespace: string[],\n    key: string,\n    value: Record<string, any>,\n    index?: false | string[]\n  ): Promise<void> {\n    validateNamespace(namespace);\n    await this.batch<[PutOperation]>([{ namespace, key, value, index }]);\n  }\n\n  /**\n   * Delete an item from the store.\n   *\n   * @param namespace Hierarchical path for the item\n   * @param key Unique identifier within the namespace\n   */\n  async delete(namespace: string[], key: string): Promise<void> {\n    await this.batch<[PutOperation]>([{ namespace, key, value: null }]);\n  }\n\n  /**\n   * List and filter namespaces in the store.\n   * Used to explore data organization and navigate the namespace hierarchy.\n   *\n   * @param options Options for listing namespaces\n   * @returns Promise resolving to list of namespace paths\n   *\n   * @example\n   * // List all namespaces under \"documents\"\n   * await store.listNamespaces({\n   *   prefix: [\"documents\"],\n   *   maxDepth: 2\n   * });\n   *\n   * // List namespaces ending with \"v1\"\n   * await store.listNamespaces({\n   *   suffix: [\"v1\"],\n   *   limit: 50\n   * });\n   */\n  async listNamespaces(\n    options: {\n      prefix?: string[];\n      suffix?: string[];\n      maxDepth?: number;\n      limit?: number;\n      offset?: number;\n    } = {}\n  ): Promise<string[][]> {\n    const { prefix, suffix, maxDepth, limit = 100, offset = 0 } = options;\n\n    const matchConditions: MatchCondition[] = [];\n    if (prefix) {\n      matchConditions.push({ matchType: \"prefix\", path: prefix });\n    }\n    if (suffix) {\n      matchConditions.push({ matchType: \"suffix\", path: suffix });\n    }\n\n    return (\n      await this.batch<[ListNamespacesOperation]>([\n        {\n          matchConditions: matchConditions.length ? matchConditions : undefined,\n          maxDepth,\n          limit,\n          offset,\n        },\n      ])\n    )[0];\n  }\n\n  /**\n   * Start the store. Override if initialization is needed.\n   */\n  start(): void | Promise<void> {}\n\n  /**\n   * Stop the store. Override if cleanup is needed.\n   */\n  stop(): void | Promise<void> {}\n}\n"],"mappings":"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"}