Packages
Jido plugin and actions that adapt the Gralkor memory server into a Jido agent. Drop in the plugin for recall-on-query and capture-on-completion; add the actions to your ReAct tools list for explicit memory_search / memory_add.
Current section
Files
Jump to
Current section
Files
lib/gralkor/learning_entity.ex
defmodule Gralkor.LearningEntity do
@moduledoc """
The plugin's built-in graphiti custom entity type for ERL.
`Learning` is declared as a graphiti custom entity type (the same shape a
consumer's `use Gralkor.Ontology` entity takes) and merged onto every learning
write's `entity_types` at the write boundary — additively over the consumer's
configured ontology (or `nil`), so ERL is not gated on a configured ontology.
Declaring `Learning` in `entity_types` causes graphiti's extractor to emit a
`Learning`-typed node per learning episode and stamp the `"Learning"` label on
it, so `SearchFilters(node_labels: ["Learning"])` (ex-recall) reliably returns
only learning nodes.
See `ex-learning-entity` in `TEST_TREES.md`.
"""
@learning_name "Learning"
@description "An experiential lesson the agent learned from attempting to solve a problem. " <>
"Extract a Learning entity from any text that records what was learned while " <>
"solving or attempting a task: the kind of problem faced, the approach taken, " <>
"whether it succeeded, and the reusable lesson. There is exactly one Learning " <>
"per such record."
@spec spec() :: %{name: String.t(), description: String.t(), fields: [map()]}
def spec do
%{
name: @learning_name,
description: @description,
fields: [
%{name: :problem_kind, type: :string, required: false, doc: "the kind of problem approached"},
%{name: :approach, type: :string, required: false, doc: "the approach taken"},
%{name: :success, type: :boolean, required: false, doc: "whether it succeeded"},
%{name: :lesson, type: :string, required: false, doc: "what was learned"}
]
}
end
@doc """
Union the `Learning` entity type onto a consumer's `entity_types` list.
Additive — a consumer that intentionally declared its own `Learning` entity is
not overridden.
"""
@spec merge_entity_types([map()]) :: [map()]
def merge_entity_types(entity_types) when is_list(entity_types) do
if Enum.any?(entity_types, &(&1.name == @learning_name)) do
entity_types
else
entity_types ++ [spec()]
end
end
@doc """
Merge `Learning` onto a consumer ontology payload (from `__ontology__/0`) or
`nil`, preserving `edge_types`, `edge_type_map`, and `excluded_entity_types`.
`nil` → a payload carrying only the `Learning` entity type, so ERL applies even
when no consumer ontology is configured.
"""
@spec merge_ontology_payload(map() | nil) :: map()
def merge_ontology_payload(nil) do
%{
entity_types: [spec()],
edge_types: [],
edge_type_map: [],
excluded_entity_types: nil
}
end
def merge_ontology_payload(payload) when is_map(payload) do
%{payload | entity_types: merge_entity_types(payload.entity_types || [])}
end
end