Packages

fnord

0.9.29

AI code archaeology

Current section

Files

Jump to
fnord lib memory migration.ex
Raw

lib/memory/migration.ex

defmodule Memory.Migration do
@moduledoc """
Helpers for repairing and migrating memory index statuses.
This module provides programmatic functions (not a mix task) so migration
can be invoked in an escript environment or in tests. The default behavior
is a dry-run listing of candidate memories; pass `apply?: true` to perform
an in-place repair (set index_status to :analyzed).
"""
@doc """
Scan global, project, and session memories for nil index_status.
When `project` is nil, the current selected project is used (via
Store.get_project()). Returns {:ok, report_map} where report_map
contains lists of affected memories.
"""
def migrate_nil_statuses(project \\ nil, opts \\ []) do
apply? = Keyword.get(opts, :apply?, false)
report = %{
global: find_nil_status_memories(:global),
project: find_nil_status_project_memories(project),
session: find_nil_status_session_memories(project)
}
if apply? do
apply_status_repairs(report, project)
{:ok, Map.put(report, :applied, true)}
else
{:ok, Map.put(report, :applied, false)}
end
end
# --------------------------------------------------------------------------
# Scanning
# --------------------------------------------------------------------------
defp find_nil_status_memories(:global) do
{:ok, titles} = Memory.Global.list()
titles
|> Enum.filter(&has_nil_status?(:global, &1))
|> Enum.map(fn title -> {:global, title} end)
end
defp find_nil_status_project_memories(project) do
case Store.get_project(project) do
{:ok, _} ->
{:ok, titles} = Memory.Project.list()
titles
|> Enum.filter(&has_nil_status?(:project, &1))
|> Enum.map(fn title -> {:project, title} end)
_ ->
[]
end
end
defp find_nil_status_session_memories(project) do
case Store.get_project(project) do
{:ok, proj} ->
proj
|> Store.Project.Conversation.list()
|> Enum.flat_map(&session_memories_with_nil_status/1)
_ ->
[]
end
end
defp has_nil_status?(scope, title) do
case Memory.read(scope, title) do
{:ok, mem} -> is_nil(mem.index_status)
_ -> false
end
end
defp session_memories_with_nil_status(conv) do
case Store.Project.Conversation.read(conv) do
{:ok, data} ->
data.memory
|> Enum.filter(fn
%Memory{scope: :session, index_status: nil} -> true
_ -> false
end)
|> Enum.map(fn m -> {conv.id, m.title} end)
_ ->
[]
end
end
# --------------------------------------------------------------------------
# Applying repairs
# --------------------------------------------------------------------------
defp apply_status_repairs(report, project) do
repair_scoped_memories(report.global)
repair_scoped_memories(report.project)
repair_session_memories(project)
end
defp repair_scoped_memories(candidates) do
Enum.each(candidates, fn {scope, title} ->
Memory.set_status(scope, title, :analyzed)
end)
end
defp repair_session_memories(project) do
case Store.get_project(project) do
{:ok, proj} ->
proj
|> Store.Project.Conversation.list()
|> Enum.each(&repair_conversation_session_memories/1)
_ ->
:ok
end
end
defp repair_conversation_session_memories(conv) do
case Store.Project.Conversation.read(conv) do
{:ok, data} ->
updated_mem =
Enum.map(data.memory, fn
%Memory{scope: :session, index_status: nil} = m ->
%{m | index_status: :analyzed}
other ->
other
end)
data
|> Map.put(:memory, updated_mem)
|> then(&Store.Project.Conversation.write(conv, &1))
_ ->
:ok
end
end
end