Commit c588640
Changed files (7)
lib
elelem
lib/elelem/toolbox/memory.rb
@@ -0,0 +1,164 @@
+# frozen_string_literal: true
+
+module Elelem
+ module Toolbox
+ class Memory < Tool
+ MEMORY_DIR = ".elelem_memory"
+ MAX_MEMORY_SIZE = 1_000_000
+
+ def initialize(configuration)
+ @configuration = configuration
+ @tui = configuration.tui
+
+ super("memory", "Persistent memory for learning and context retention", {
+ type: :object,
+ properties: {
+ action: {
+ type: :string,
+ enum: %w[store retrieve list search forget],
+ description: "Memory action: store, retrieve, list, search, forget"
+ },
+ key: {
+ type: :string,
+ description: "Unique key for storing/retrieving memory"
+ },
+ content: {
+ type: :string,
+ description: "Content to store (required for store action)"
+ },
+ query: {
+ type: :string,
+ description: "Search query for finding memories"
+ }
+ },
+ required: %w[action]
+ })
+ ensure_memory_dir
+ end
+
+ def call(args)
+ action = args["action"]
+
+ case action
+ when "store"
+ store_memory(args["key"], args["content"])
+ when "retrieve"
+ retrieve_memory(args["key"])
+ when "list"
+ list_memories
+ when "search"
+ search_memories(args["query"])
+ when "forget"
+ forget_memory(args["key"])
+ else
+ "Invalid memory action: #{action}"
+ end
+ rescue StandardError => e
+ "Memory error: #{e.message}"
+ end
+
+ private
+
+ attr_reader :configuration, :tui
+
+ def ensure_memory_dir
+ Dir.mkdir(MEMORY_DIR) unless Dir.exist?(MEMORY_DIR)
+ end
+
+ def memory_path(key)
+ ::File.join(MEMORY_DIR, "#{sanitize_key(key)}.json")
+ end
+
+ def sanitize_key(key)
+ key.to_s.gsub(/[^a-zA-Z0-9_-]/, "_").slice(0, 100)
+ end
+
+ def store_memory(key, content)
+ return "Key and content required for storing" unless key && content
+
+ total_size = Dir.glob("#{MEMORY_DIR}/*.json").sum { |f| ::File.size(f) }
+ return "Memory capacity exceeded" if total_size > MAX_MEMORY_SIZE
+
+ memory = {
+ key: key,
+ content: content,
+ timestamp: Time.now.iso8601,
+ access_count: 0
+ }
+
+ ::File.write(memory_path(key), JSON.pretty_generate(memory))
+ "Memory stored: #{key}"
+ end
+
+ def retrieve_memory(key)
+ return "Key required for retrieval" unless key
+
+ path = memory_path(key)
+ return "Memory not found: #{key}" unless ::File.exist?(path)
+
+ memory = JSON.parse(::File.read(path))
+ memory["access_count"] += 1
+ memory["last_accessed"] = Time.now.iso8601
+
+ ::File.write(path, JSON.pretty_generate(memory))
+ memory["content"]
+ end
+
+ def list_memories
+ memories = Dir.glob("#{MEMORY_DIR}/*.json").map do |file|
+ memory = JSON.parse(::File.read(file))
+ {
+ key: memory["key"],
+ timestamp: memory["timestamp"],
+ size: memory["content"].length,
+ access_count: memory["access_count"] || 0
+ }
+ end
+
+ memories.sort_by { |m| m[:timestamp] }.reverse
+ JSON.pretty_generate(memories)
+ end
+
+ def search_memories(query)
+ return "Query required for search" unless query
+
+ matches = Dir.glob("#{MEMORY_DIR}/*.json").filter_map do |file|
+ memory = JSON.parse(::File.read(file))
+ if memory["content"].downcase.include?(query.downcase) ||
+ memory["key"].downcase.include?(query.downcase)
+ {
+ key: memory["key"],
+ snippet: memory["content"][0, 200] + "...",
+ relevance: calculate_relevance(memory, query)
+ }
+ end
+ end
+
+ matches.sort_by { |m| -m[:relevance] }
+ JSON.pretty_generate(matches)
+ end
+
+ def forget_memory(key)
+ return "Key required for forgetting" unless key
+
+ path = memory_path(key)
+ return "Memory not found: #{key}" unless ::File.exist?(path)
+
+ ::File.delete(path)
+ "Memory forgotten: #{key}"
+ end
+
+ def calculate_relevance(memory, query)
+ content = memory["content"].downcase
+ key = memory["key"].downcase
+ query = query.downcase
+
+ score = 0
+ score += 3 if key.include?(query)
+ score += content.scan(query).length
+ score += (memory["access_count"] || 0) * 0.1
+ score
+ end
+ end
+ end
+end
\ No newline at end of file
lib/elelem/toolbox/prompt.rb
@@ -4,6 +4,7 @@ module Elelem
module Toolbox
class Prompt < Tool
def initialize(configuration)
+ @configuration = configuration
super("prompt", "Ask the user a question and get their response.", {
type: :object,
properties: {
@@ -16,8 +17,8 @@ module Elelem
})
end
- def call(agent, **args)
- agent.tui.prompt(args[:question])
+ def call(args)
+ @configuration.tui.prompt(args["question"])
end
end
end
lib/elelem/configuration.rb
@@ -51,6 +51,7 @@ module Elelem
Toolbox::File.new(self),
Toolbox::Web.new(self),
Toolbox::Prompt.new(self),
+ Toolbox::Memory.new(self),
] + mcp_tools
)
end
lib/elelem/system_prompt.erb
@@ -10,6 +10,7 @@ You are a self-improving coding assistant with the ability to modify your own so
- `exec command="shell command"` - Run commands/tests
- `file action=read|write path=filepath content=...` - Read/write files
- `web action=search|fetch query=... url=...` - Internet access
+- `memory action=store|retrieve|search key=... content=...` - Persistent memory
- `prompt question="..."` - Ask user questions
Context: <%= Time.now.strftime("%Y-%m-%d %H:%M:%S") %> | <%= Dir.pwd %> | <%= `uname -a`.strip %>
lib/elelem/toolbox.rb
@@ -5,3 +5,4 @@ require_relative "toolbox/file"
require_relative "toolbox/web"
require_relative "toolbox/mcp"
require_relative "toolbox/prompt"
+require_relative "toolbox/memory"
COMMANDMENTS.md
@@ -16,6 +16,7 @@ Change one thing at a time, test it, then move to the next. Small steps prevent
- `file`: Only `action=read|write`, `path=filepath`, optional `content` for write
- `exec`: Only `command="shell command"`
- `web`: Only `action=search|fetch`, optional `url` or `query`
+- `memory`: Only `action=store|retrieve|list|search|forget`, `key` for storage/retrieval
- `prompt`: Only `question="what to ask user"`
## VI. Thou Shalt Track Progress
@@ -30,7 +31,10 @@ When uncertain, use `prompt` to ask the user for clarification rather than guess
## IX. Thou Shalt Validate Completion
Don't stop until the task is actually complete. Test that your changes solve the original problem.
-## X. Thou Shalt Evolve
+## X. Thou Shalt Remember and Learn
+Store insights, solutions, and patterns in memory. Use `memory action=store key="topic" content="lesson learned"` to build persistent knowledge across sessions.
+
+## XI. Thou Shalt Evolve
Your goal is continuous self-improvement. Each completed task should leave you more capable than before.
---
elelem.gemspec
@@ -56,6 +56,7 @@ Gem::Specification.new do |spec|
"lib/elelem/toolbox/web.rb",
"lib/elelem/toolbox/mcp.rb",
"lib/elelem/toolbox/prompt.rb",
+ "lib/elelem/toolbox/memory.rb",
"lib/elelem/tools.rb",
"lib/elelem/tui.rb",
"lib/elelem/version.rb",