Constructors

Methods

  • Attach a Brain for durable write-through persistence. Once attached, all store/softDelete/recordAccess operations also write to the brain's memory_traces table. Initial attachment must happen before any memory operation; after that, only another handle with the same coordination token can be supplied.

    Parameters

    • brain: Brain

      Brain instance (already initialized with schema)

    Returns void

    Throws

    When attachment is late or would switch backing resources.

  • Return the subset of cached trace IDs that remain recallable after a fail-closed durable-state check. Used by non-vector recall paths such as graph association injection so a tombstone cannot bypass vector filters. A trace whose Brain row a move filed under another scope id than the one this store holds it under is not recallable until the store follows it.

    Parameters

    • traceIds: string[]

      The candidate trace IDs.

    • Optional scopes: readonly {
          scope: MemoryScope;
          scopeId: string;
      }[]

      When given and non-empty, only traces filed under one of these scopes are recallable, as in query: a graph association never brings in a trace of a scope the caller does not read.

    Returns Promise<Set<string>>

  • Get all traces for a scope (for consolidation pipeline).

    Limitation: This primarily returns traces from the in-process cache. Traces that were persisted to the vector store in a prior process lifetime (or by another process) will only be returned if the cache is empty for this scope, in which case we fall back to querying the vector store with a zero vector of the collection's size (zeroQueryVector) and a metadata filter. The fallback is approximate (limited by topK) and does not guarantee completeness.

    Parameters

    Returns Promise<MemoryTrace[]>

  • Loads one scope's most recent traces from the Brain by the scope_id column, so a returning learner's memories are recallable however many traces other scopes hold (the whole-brain hydration loads the MemoryStore.HYDRATION_LIMIT most recent of the brain). A trace already loaded is skipped. A row a release older than the column wrote since the Brain opened holds '' there until the next open files it; the whole-brain hydration loads it meanwhile while it is among the brain's most recent.

    Parameters

    • scope: MemoryScope
    • scopeId: string
    • limit: number = MemoryStore.HYDRATION_LIMIT

      How many of the scope's most recent traces to read: a positive integer.

    Returns Promise<number>

    How many traces it loaded.

    Throws

    RangeError when limit is not a positive integer.

  • Moves one scope id's traces to another. Every Brain row filed under it moves, soft-deleted rows included (scope_id and the metadata's scopeId), so a later delete of the new id finds them all. Each live trace this store holds moves with its vector document, from the old collection into the new one; a trace it does not hold leaves the old collection, and a store files it in the new one when it loads it (hydrateScope, or the whole-brain hydration). A live trace's knowledge-graph copy, where the graph holds one, is recorded again under the new id. With no Brain the vector index is the scope's record, so the old collection is walked from its start (walkScopeCollection) and the documents another store filed into it before a restart move too; a stale document there, of a trace this store holds under another scope, is deleted from it. A vector the store holds no embedding for is read from the trace's Brain row or from the index, or embedded again. A document the index fails to delete from the old collection stays, with a warning; recall under the old id does not return it, since this store holds the trace under the new one. Another store open on the same Brain keeps what it holds under the old id until it re-files the scope itself or loads it again. A trace this store holds under the old id whose row another store or process moved to another scope or a third id, or deleted for good, before this move or while it runs, stays as this store holds it, and is not counted: a deleted trace's words go into no collection.

    A host that starts passing an organization id re-files each user's earlier traces with it once, since a learner under a namespace reads user:<namespace>/<userId> and not the plain form filed before.

    A Brain row's metadata is written with a compare against what the move read, so a write another writer makes to the row meanwhile (a facade's recall, feedback or update) is read again and kept. A hydration of this store, or of another store on the same Brain in this process, that read a row before the move reads it again before it loads it, so the trace loads under the new id.

    Parameters

    Returns Promise<number>

    The number of traces moved: Brain rows, soft-deleted ones included, and the live traces the store held or the index listed under the old id with no row.

    Throws

    TypeError when either scope id is empty, so a caller's missing id never moves the traces filed under no scope id or files a scope's traces under none.

    Throws

    When a live trace's vector cannot be embedded or written into the new collection, or a Brain row cannot be read or written or kept changing through three reads; the traces moved before it stay moved, and a call made again moves the rest. A row moves before its trace's vector, so a store that reads the new id meanwhile finds no document there yet rather than one its row does not name: a trace whose vector could not be written has its row under the new id, this store reads it under neither id, and the call made again moves the vector.

  • Puts this store's Brain in the encoded form a learning layer reads the first time a layer opens it (refileBrainScopeIds). Once the re-file has committed, every live store on the Brain in this process, this one included, moves what it holds of the traces the re-file moved, and of those alone: a row filed under an old id after the re-file is a namespaced learner's, and stays where it is. Then, whoever re-filed the Brain (this call, another handle or another process), this store follows the Brain's rows: each trace it holds under a user or persona id that the encoded form would change moves to the scope id its row holds, and one whose row holds the id as it is stays, since a namespaced id holds a / too. A hydration under way loads its rows as the Brain holds them after the re-file. Until a store follows, a read of an old id does not return a trace whose row moved. A store with no Brain has nothing to re-file.

    Returns Promise<number>

    How many Brain rows this call's re-file moved: none when the Brain held the record already.

    Throws

    When the re-file fails (its transaction rolls back, and a later call re-files the Brain), or when this store cannot read the rows of the traces it holds or move one into its new collection.

  • Re-upsert a trace's metadata to the vector store using the cached embedding. Used by consolidation when a mutation to the in-memory trace (e.g. provenance.contradictedBy, provenance.lastVerifiedAt) needs to survive a process restart without paying for re-embedding.

    No-ops silently when the trace or its embedding is not cached; the caller should getTrace first or accept that an uncached trace will not be durably updated.

    Parameters

    • traceId: string

    Returns Promise<void>

  • Soft-delete a trace and preserve the local barrier if durable persistence cannot confirm the tombstone.

    Parameters

    • traceId: string

    Returns Promise<void>

    Throws

    When an attached Brain cannot persist the tombstone or the trace has no durable row to update.

  • Deletes the given traces for good: their knowledge-graph copies go first, then each is soft-deleted in this process (cache, vector index, sibling stores), then its Brain row is deleted, so no reload, in this process or another, brings it back (a store that finds a row gone reads it as deleted). The rows that name a trace go first, as the Brain's foreign keys require: its retrieval feedback (with the query that recalled it) is deleted, and the document chunk it was filed from lets go of it and keeps its text, which belongs to the document. On SQLite the full-text index is rebuilt from the rows that remain, as every hard delete must; a rebuild that fails is repaired when the Brain next opens. Last, every store on the backing resource in this process, this one included, keeps of each trace only where it was filed, none of its words (withoutWords).

    A trace this store holds under another scope than its Brain row names (a move another process made, which this store has not followed) also leaves the collection its row names, where that process filed its document.

    With no Brain, the traces this store holds are the ones it reaches: an id the vector index holds of a trace this store never loaded names no collection, and deleteScope is what finds such a trace.

    Parameters

    • traceIds: readonly string[]

      Trace ids; unknown ids are skipped.

    • options: {
          beforeDelete?: ((traceIds) => Promise<void>);
      } = {}
      • Optional beforeDelete?: ((traceIds) => Promise<void>)

        Runs with the ids of the traces found (a Brain row or a trace this store holds) before any of them is deleted, and not at all when none is found. The memory manager removes what it keeps of each trace there, so a call that fails part way finds the same traces again.

          • (traceIds): Promise<void>
          • Parameters

            • traceIds: readonly string[]

            Returns Promise<void>

    Returns Promise<number>

    How many of them had a Brain row or a live cached trace, so a second call for the same ids counts none.

    Throws

    When the Brain cannot be read, the knowledge graph cannot delete the traces' copies (no trace is deleted then), or a row cannot be deleted, or what beforeDelete throws.

  • Deletes every trace of one scope for good (deleteTraces). The traces this store holds and every Brain row filed under the scope (memory_traces.scope_id), soft-deleted rows and another process's included, go in one batch; the brain's rows a release older than the column wrote are filed first (scopeTraceIds). A trace this store holds under the scope whose row a move filed under another scope id (refileScope in another store or process, a Brain's re-file this store has not followed) stays: it is that scope id's, and after a Brain's re-file the old id names another user. With no Brain the vector index is the scope's durable record, holding what another store filed before a restart, so the scope's collection is then walked from its start a page at a time (readScopeCollection), following the cursor the index returns, and each page is deleted. The walk runs again while it finds a document this call has not read, since a delete moves the documents after it past a cursor that counts positions. A document whose eviction fails stays in the index, as softDelete warns, and a later call reads it again; a document of a trace this store holds under another scope is removed from the collection and its trace kept. Last, every knowledge-graph copy filed under the scope whose trace was already gone; a graph that cannot delete them fails the call, with the scope's traces already deleted, so a second call finds the copies alone.

    Parameters

    • scope: MemoryScope
    • scopeId: string
    • options: {
          turnUserId?: string;
          beforeDelete?: ((traceIds) => Promise<void>);
      } = {}
      • Optional turnUserId?: string

        Deletes only the scope's traces that name this user: a trace a second user filed on another user's session (MemoryTrace.turnUserId), or a summary of their words, whose Brain row names them among its contributors (traceNamesUser); the scope's other traces and copies stay. A trace this store holds with no Brain row is read by its turnUserId, since a cached trace carries no contributors.

      • Optional beforeDelete?: ((traceIds) => Promise<void>)

        Runs with the ids of each batch's traces before the batch is deleted (deleteTraces runs it). The memory manager removes what it keeps of each trace there, so a call that fails part way finds the same traces again.

          • (traceIds): Promise<void>
          • Parameters

            • traceIds: readonly string[]

            Returns Promise<void>

    Returns Promise<number>

    The number of traces deleted.

    Throws

    TypeError when scopeId is empty, so a caller's missing id never deletes every trace filed under no scope id, or when turnUserId is given and is not a non-empty string.

    Throws

    When the Brain cannot be read or a row cannot be deleted, when the knowledge graph cannot delete the scope's copies, or, with no Brain, when the vector index cannot say whether it holds the scope's collection or cannot read the collection it holds.

  • Whether this store has soft-deleted the trace in this process. Lifecycle hooks that re-activate traces leaving working memory MUST consult this so a tombstone's isActive flag is never resurrected — a resurrected flag let the spaced-repetition sweep re-embed and re-upsert deleted memories back into shared vector recall.

    Parameters

    • traceId: string

    Returns boolean