Commit abb2232
Changed files (6)
lib/elelem/agent.rb
@@ -3,6 +3,7 @@
module Elelem
class Agent
COMMANDS = %w[/clear /context /exit /help].freeze
+ MAX_LINES = 30
attr_reader :history, :client, :toolbox, :terminal
@@ -56,7 +57,7 @@ module Elelem
tool_calls.each do |tc|
name, args = tc[:name], tc[:arguments]
terminal.say "\n#{format_tool_display(name, args)}"
- result = toolbox.run(name, args)
+ result = truncate(toolbox.run(name, args))
terminal.say format_tool_result(name, result)
ctx << { role: "tool", tool_call_id: tc[:id], content: result.to_json }
errors += 1 if result[:error]
@@ -95,10 +96,21 @@ module Elelem
result[:error] ? " ! #{text.lines.first&.strip}" : text
end
+ def truncate(result)
+ %w[stdout stderr].each do |k|
+ next unless result[k].is_a?(String) && result[k].lines.size > MAX_LINES
+ result[k] = result[k].lines.first(MAX_LINES).join + "… (truncated)"
+ end
+ result
+ end
+
def system_prompt
+ branch = `git branch --show-current 2>/dev/null`.strip
+ dirty = `git status --porcelain 2>/dev/null`.lines.first(5).map(&:strip).join(", ")
<<~PROMPT.strip
Terminal agent. Act directly, verify your work. Stay grounded - only respond to what is asked.
pwd: #{Dir.pwd}
+ #{"git: #{branch}" + (dirty.empty? ? "" : " [#{dirty}]") unless branch.empty?}
PROMPT
end
end
lib/elelem/toolbox.rb
@@ -21,23 +21,17 @@ module Elelem
required: ["cmd"],
fn: ->(a) { Elelem.sh(a["cmd"], args: a["args"] || [], stdin: a["stdin"]) }
},
- "web_fetch" => {
- desc: "Fetch URL content",
- params: { url: { type: "string" } },
- required: ["url"],
- fn: ->(a) { r = Net::Hippie::Client.new.get(a["url"]); { status: r.code.to_i, body: r.body } }
- },
- "web_search" => {
- desc: "Search web via DuckDuckGo",
+ "grep" => {
+ desc: "Search git-tracked files",
params: { query: { type: "string" } },
required: ["query"],
- fn: ->(a) { q = CGI.escape(a["query"]); JSON.parse(Net::Hippie::Client.new.get("https://api.duckduckgo.com/?q=#{q}&format=json&no_html=1").body) }
+ fn: ->(a) { Elelem.sh("git", args: ["grep", "-nI", a["query"]]) }
},
- "eval" => {
- desc: "Execute Ruby code",
- params: { ruby: { type: "string" } },
- required: ["ruby"],
- fn: nil
+ "list" => {
+ desc: "List git-tracked files",
+ params: { path: { type: "string" } },
+ required: [],
+ fn: ->(a) { Elelem.sh("git", args: a["path"] ? ["ls-files", "--", a["path"]] : ["ls-files"]) }
}
}.freeze
@@ -70,7 +64,6 @@ module Elelem
name = ALIASES.fetch(name, name)
tool = tools[name]
return { error: "unknown tool: #{name}" } unless tool
- return { result: binding.eval(args["ruby"]) } if name == "eval"
tool[:fn].call(args)
rescue => e
lib/elelem.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-require "cgi"
require "fileutils"
require "json"
-require "net/hippie"
require "net/llm"
require "open3"
require "pathname"
spec/elelem/toolbox_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Elelem::Toolbox do
describe "#to_h" do
it "returns all tools in API format" do
tool_names = subject.to_h.map { |t| t.dig(:function, :name) }
- expect(tool_names).to include("read", "write", "exec", "web_fetch", "web_search", "eval")
+ expect(tool_names).to include("read", "write", "exec", "grep", "list")
end
end
@@ -26,9 +26,9 @@ RSpec.describe Elelem::Toolbox do
expect(result[:error]).to include("unknown tool")
end
- it "executes eval tool" do
- result = subject.run("eval", { "ruby" => "2 + 2" })
- expect(result[:result]).to eq(4)
+ it "executes grep tool" do
+ result = subject.run("grep", { "query" => "RSpec.describe" })
+ expect(result["stdout"]).to include("toolbox_spec.rb")
end
end
end
elelem.gemspec
@@ -40,10 +40,8 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
- spec.add_dependency "cgi", "~> 0.1"
spec.add_dependency "fileutils", "~> 1.0"
spec.add_dependency "json", "~> 2.0"
- spec.add_dependency "net-hippie", "~> 1.0"
spec.add_dependency "net-llm", "~> 0.5", ">= 0.5.0"
spec.add_dependency "open3", "~> 0.1"
spec.add_dependency "pathname", "~> 0.1"
Gemfile.lock
@@ -2,10 +2,8 @@ PATH
remote: .
specs:
elelem (0.8.0)
- cgi (~> 0.1)
fileutils (~> 1.0)
json (~> 2.0)
- net-hippie (~> 1.0)
net-llm (~> 0.5, >= 0.5.0)
open3 (~> 0.1)
pathname (~> 0.1)
@@ -15,7 +13,6 @@ GEM
remote: https://rubygems.org/
specs:
base64 (0.3.0)
- cgi (0.5.1)
date (3.5.1)
diff-lcs (1.6.2)
erb (6.0.1)