Memory behaviour (fnord v0.9.29)

View Source

Summary

Callbacks

Returns true if a memory with the given title exists in the impl's storage.

Deletes the given memory from the impl's storage. The impl is responsible for locking any shared resources and ensuring atomic delete behavior. Expects an :error tuple if the memory does not exist.

Performs any necessary one-time initialization for the impl's storage. For example, creating directories, loading currently select project from Services.Globals, etc.

Returns true if this memory implementation is available in the current context. For example, project memory requires a selected project, and session memory requires an active conversation.

Returns a list of all memory titles available in the impl's storage. Ordering is not guaranteed.

Reads and returns the memory with the given title from the impl's storage. The impl is responsible for ensuring that the returned memory is in the correct structural format, including atomic keys (e.g. not strings if unmarshalling JSON from disk).

Saves the given memory to the impl's storage. The impl is responsible for locking any shared resources and ensuring atomic write behavior. It is expected that the title of the memory is unique, and any existing memory with the same title will be overwritten.

Functions

Regenerates embeddings for all stale long-term memories. Intended for background services that want to drain the queue opportunistically; foreground callers (Cmd.Index) should iterate list_stale_long_term_memories/0 directly so they can emit per-item progress.

A title is unique within the given scope if no existing memory with the same title exists.

A title is valid if it is non-empty (after trimming), contains at least one alphanumeric character, does not contain control characters or newlines, and is not unreasonably long.

Lists {scope, title} pairs for project/global memories whose persisted embedding is stale under the current model: either missing (nil) or of the wrong dimension. Session memories are intentionally excluded.

Returns the lock path for a single long-term memory. Foreground indexers and background backfill acquire this lock before reading + regenerating embeddings so two sessions don't both pay the embed cost for the same memory. Keyed by the canonical slug so collision-suffixed siblings still serialize against each other.

Serializes the given memory to a JSON binary.

Creates a new Memory struct from the given map. Expects keys to be atoms. Returns a Memory.t.

Regenerates the embedding for a single stale memory identified by {scope, title}. Returns :ok on success, {:error, reason} on failure (missing memory, embedding call failed, write failed). Intended for callers that want to drive a per-item progress UI.

Returns {count, avg_ms} for memory searches performed this session, or nil if no searches have been recorded.

Set the index_status of an existing memory and persist it.

Converts a slug back to a title by replacing hyphens with spaces and capitalizing each word.

Returns true when the memory at {scope, title} has a stored vector that can't be used with the current model - either the embedding is missing or its dimension doesn't match. Missing memories return false (nothing to reindex).

Converts a title to a slug by lowercasing it, replacing non-word characters with hyphens, and trimming leading/trailing hyphens.

Deserializes the given JSON binary to a Memory struct.

Types

scope()

@type scope() :: :global | :project | :session

t()

@type t() :: %Memory{
  content: binary(),
  embeddings: [float()] | nil,
  index_status:
    :new | :analyzed | :rejected | :incorporated | :merged | :ignore | nil,
  inserted_at: binary() | nil,
  scope: scope(),
  slug: binary() | nil,
  title: binary(),
  topics: [binary()],
  updated_at: binary() | nil
}

Callbacks

exists?(title)

@callback exists?(title :: binary()) :: boolean()

Returns true if a memory with the given title exists in the impl's storage.

forget(title)

@callback forget(title :: binary()) :: :ok | {:error, term()}

Deletes the given memory from the impl's storage. The impl is responsible for locking any shared resources and ensuring atomic delete behavior. Expects an :error tuple if the memory does not exist.

init()

@callback init() :: :ok | {:error, term()}

Performs any necessary one-time initialization for the impl's storage. For example, creating directories, loading currently select project from Services.Globals, etc.

is_available?()

@callback is_available?() :: boolean()

Returns true if this memory implementation is available in the current context. For example, project memory requires a selected project, and session memory requires an active conversation.

list()

@callback list() :: {:ok, [binary()]} | {:error, term()}

Returns a list of all memory titles available in the impl's storage. Ordering is not guaranteed.

read(title)

@callback read(title :: binary()) :: {:ok, t()} | {:error, term()}

Reads and returns the memory with the given title from the impl's storage. The impl is responsible for ensuring that the returned memory is in the correct structural format, including atomic keys (e.g. not strings if unmarshalling JSON from disk).

save(memory)

@callback save(memory :: t()) :: :ok | {:error, term()}

Saves the given memory to the impl's storage. The impl is responsible for locking any shared resources and ensuring atomic write behavior. It is expected that the title of the memory is unique, and any existing memory with the same title will be overwritten.

Functions

append(memory, new_content)

@spec append(t(), binary()) :: t()

backfill_stale_embeddings(opts \\ [])

@spec backfill_stale_embeddings(keyword()) ::
  {:ok, %{processed: non_neg_integer(), errors: non_neg_integer()}}

Regenerates embeddings for all stale long-term memories. Intended for background services that want to drain the queue opportunistically; foreground callers (Cmd.Index) should iterate list_stale_long_term_memories/0 directly so they can emit per-item progress.

Options:

  • :limit - cap the number of memories processed in this call. :infinity (default) processes every stale memory found.

Returns {:ok, %{processed: n, errors: k}}.

exists?(arg1, title)

@spec exists?(scope(), binary()) :: boolean()

forget(map)

@spec forget(t()) :: :ok | {:error, term()}

generate_embeddings(memory)

init()

@spec init() :: :ok | {:error, term()}

is_available?()

@spec is_available?() :: boolean()

is_stale?(arg1)

@spec is_stale?(t()) :: boolean()

is_unique_title?(scope, title)

@spec is_unique_title?(scope(), binary()) :: boolean()

A title is unique within the given scope if no existing memory with the same title exists.

is_valid_title?(title)

@spec is_valid_title?(binary()) :: boolean()

A title is valid if it is non-empty (after trimming), contains at least one alphanumeric character, does not contain control characters or newlines, and is not unreasonably long.

Punctuation and spaces are allowed. The system will ensure internal filename safety by slugifying titles for storage; collisions are handled elsewhere.

list()

@spec list() :: {:ok, [{:scope, binary()}]} | {:error, term()}

list(atom)

list_stale_long_term_memories()

@spec list_stale_long_term_memories() :: [{scope(), binary()}]

Lists {scope, title} pairs for project/global memories whose persisted embedding is stale under the current model: either missing (nil) or of the wrong dimension. Session memories are intentionally excluded.

lock_path(scope, title)

@spec lock_path(scope(), binary()) :: {:ok, String.t()} | {:error, term()}

Returns the lock path for a single long-term memory. Foreground indexers and background backfill acquire this lock before reading + regenerating embeddings so two sessions don't both pay the embed cost for the same memory. Keyed by the canonical slug so collision-suffixed siblings still serialize against each other.

marshal(memory)

@spec marshal(t()) :: {:ok, binary()} | {:error, term()}

Serializes the given memory to a JSON binary.

new(scope, title, content, topics)

@spec new(scope(), binary(), binary(), [binary()]) :: {:ok, t()} | {:error, term()}

new_from_map(data)

@spec new_from_map(map()) :: t()

Creates a new Memory struct from the given map. Expects keys to be atoms. Returns a Memory.t.

read(scope, title)

@spec read(scope(), binary()) :: {:ok, t()} | {:error, term()}

read_me()

@spec read_me() :: {:ok, t()} | {:error, term()}

reindex_memory(scope, title)

@spec reindex_memory(scope(), binary()) :: :ok | {:error, term()}

Regenerates the embedding for a single stale memory identified by {scope, title}. Returns :ok on success, {:error, reason} on failure (missing memory, embedding call failed, write failed). Intended for callers that want to drive a per-item progress UI.

save(memory, opts \\ [])

@spec save(
  t(),
  keyword()
) :: {:ok, t()} | {:error, term()}

search(query, limit, opts \\ [])

@spec search(binary(), non_neg_integer(), keyword()) ::
  {:ok, [{t(), float()}]} | {:error, term()}

search_stats()

@spec search_stats() :: {pos_integer(), float()} | nil

Returns {count, avg_ms} for memory searches performed this session, or nil if no searches have been recorded.

set_status(scope, title, status)

@spec set_status(scope(), binary(), atom()) :: {:ok, t()} | {:error, term()}

Set the index_status of an existing memory and persist it.

Saves with skip_embeddings: true: status transitions don't change the text, so regenerating the vector would be wasted work.

slug_to_title(slug)

@spec slug_to_title(binary()) :: binary()

Converts a slug back to a title by replacing hyphens with spaces and capitalizing each word.

stale?(scope, title)

@spec stale?(scope(), binary()) :: boolean()

Returns true when the memory at {scope, title} has a stored vector that can't be used with the current model - either the embedding is missing or its dimension doesn't match. Missing memories return false (nothing to reindex).

title_to_slug(title)

@spec title_to_slug(binary()) :: binary()

Converts a title to a slug by lowercasing it, replacing non-word characters with hyphens, and trimming leading/trailing hyphens.

unmarshal(json)

@spec unmarshal(binary()) :: {:ok, t()} | {:error, term()}

Deserializes the given JSON binary to a Memory struct.

validate_title(title)

@spec validate_title(binary()) :: :ok | {:error, [binary()]}