Commit 398f4b2

mo khan <mo@mokhan.ca>
2026-01-26 21:57:48
refactor: extract Conversation class from Agent
- Add Conversation class for message storage with role validation - Add Commands class for slash command registry - Move inline commands to plugins/builtins.rb - Move task tool to plugins/task.rb - Remove context compaction and memory (users can /clear) - Simplify SystemPrompt (no memory parameter) Agent is now focused on the REPL loop and LLM interaction.
1 parent 02361e0
Changed files (4)
lib/elelem/tools/edit.rb
@@ -1,14 +1,14 @@
 # frozen_string_literal: true
 
-Elelem::Plugins.register(:edit) do |toolbox|
-  toolbox.add("edit",
+Elelem::Plugins.register(:edit) do |agent|
+  agent.toolbox.add("edit",
     description: "Replace first occurrence of text in file",
     params: { path: { type: "string" }, old: { type: "string" }, new: { type: "string" } },
     required: ["path", "old", "new"]
   ) do |a|
     path = Pathname.new(a["path"]).expand_path
     content = path.read
-    toolbox
+    agent.toolbox
       .run("write", { "path" => a["path"], "content" => content.sub(a["old"], a["new"]) })
       .merge(replaced: a["old"], with: a["new"])
   end
lib/elelem/tools/eval.rb
@@ -1,16 +1,16 @@
 # frozen_string_literal: true
 
-Elelem::Plugins.register(:eval) do |toolbox|
+Elelem::Plugins.register(:eval) do |agent|
   description = <<~'DESC'
     Evaluate Ruby code. Available API:
 
     name = "search"
-    toolbox.add(name, description: "Search using rg", params: { query: { type: "string" } }, required: ["query"], aliases: []) do |args|
-      toolbox.run("execute", { "command" => "rg --json -nI -F #{args["query"]}" })
+    agent.toolbox.add(name, description: "Search using rg", params: { query: { type: "string" } }, required: ["query"], aliases: []) do |args|
+      agent.toolbox.run("execute", { "command" => "rg --json -nI -F #{args["query"]}" })
     end
   DESC
 
-  toolbox.add("eval",
+  agent.toolbox.add("eval",
     description: description,
     params: { ruby: { type: "string" } },
     required: ["ruby"]
lib/elelem/tools/task.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+Elelem::Plugins.register(:task) do |agent|
+  agent.toolbox.add("task",
+    description: "Delegate subtask to focused agent (complex searches, multi-file analysis)",
+    params: { prompt: { type: "string" } },
+    required: ["prompt"]
+  ) do |a|
+    sub = Elelem::Agent.new(agent.client, toolbox: agent.toolbox, terminal: agent.terminal,
+      system_prompt: "Research agent. Search, analyze, report. Be concise.")
+    sub.turn(a["prompt"])
+    { result: sub.conversation.last[:content] }
+  end
+end
lib/elelem/tools/verify.rb
@@ -27,16 +27,16 @@ module Elelem
     end
   end
 
-  Plugins.register(:verify) do |toolbox|
-    toolbox.add("verify",
+  Plugins.register(:verify) do |agent|
+    agent.toolbox.add("verify",
       description: "Verify file syntax and run tests",
       params: { path: { type: "string" } },
       required: ["path"]
     ) do |a|
       path = a["path"]
       Verifiers.for(path).inject({verified: []}) do |memo, cmd|
-        $stdout.puts toolbox.header("execute", { "command" => cmd })
-        v = toolbox.run("execute", { "command" => cmd })
+        agent.terminal.say agent.toolbox.header("execute", { "command" => cmd })
+        v = agent.toolbox.run("execute", { "command" => cmd })
         break v.merge(path: path, command: cmd) if v[:exit_status] != 0
 
         memo[:verified] << cmd