Commit 703899d
Changed files (6)
lib
lib/elelem/agent.rb
@@ -7,16 +7,8 @@ module Elelem
def initialize(client)
@conversation = Conversation.new
@client = client
-
- exec_tool = build_tool("execute", "Execute shell commands directly. Returns stdout, stderr, and exit code. Commands run in a shell context. Examples: 'date', 'git status', 'ls -la'. Use for: checking system state, running tests, managing services. Tip: Check exit_status in response to determine success.", { cmd: { type: "string" }, args: { type: "array", items: { type: "string" } }, env: { type: "object", additionalProperties: { type: "string" } }, cwd: { type: "string", description: "Working directory for command execution (defaults to current directory if not specified)" }, stdin: { type: "string" } }, ["cmd"])
- grep_tool = build_tool("grep", "Search all git-tracked files using git grep. Returns file paths with matching line numbers. Use this to discover where code/configuration exists before reading files. Examples: search 'def method_name' to find method definitions. Much faster than reading multiple files.", { query: { type: "string" } }, ["query"])
- ls_tool = build_tool("list", "List all git-tracked files in the repository, optionally filtered by path. Use this to explore project structure or find files in a directory. Returns relative paths from repo root. Tip: Use this before reading if you need to discover what files exist.", { path: { type: "string" } })
- patch_tool = build_tool("patch", "Apply a unified diff patch via 'git apply'. Use this for surgical edits to existing files rather than rewriting entire files. Generates proper git diffs. Format: standard unified diff with --- and +++ headers. Tip: More efficient than write for small changes to large files.", { diff: { type: "string" } }, ["diff"])
- read_tool = build_tool("read", "Read complete contents of a file. Requires exact file path. Use grep or list first if you don't know the path. Best for: understanding existing code, reading config files, reviewing implementation details. Tip: For large files, grep first to confirm relevance.", { path: { type: "string" } }, ["path"])
- write_tool = build_tool("write", "Write complete file contents (overwrites existing files). Creates parent directories automatically. Best for: creating new files, replacing entire file contents. For small edits to existing files, consider using patch instead.", { path: { type: "string" }, content: { type: "string" } }, ["path", "content"])
-
@tools = {
- read: [grep_tool, ls_tool, read_tool],
+ read: [grep_tool, list_tool, read_tool],
write: [patch_tool, write_tool],
execute: [exec_tool]
}
@@ -204,6 +196,65 @@ module Elelem
{ error: error.message, name: name, args: args }
end
+ def exec_tool
+ build_tool(
+ "execute",
+ "Execute shell commands directly. Commands run in a shell context. Examples: 'date', 'git status'.",
+ {
+ cmd: { type: "string" },
+ args: { type: "array", items: { type: "string" } },
+ env: { type: "object", additionalProperties: { type: "string" } },
+ cwd: { type: "string", description: "Working directory (defaults to current)" },
+ stdin: { type: "string" }
+ },
+ ["cmd"]
+ )
+ end
+
+ def grep_tool
+ build_tool(
+ "grep",
+ "Search all git-tracked files using git grep. Returns file paths with matching line numbers.",
+ { query: { type: "string" } },
+ ["query"]
+ )
+ end
+
+ def list_tool
+ build_tool(
+ "list",
+ "List all git-tracked files in the repository, optionally filtered by path.",
+ { path: { type: "string" } }
+ )
+ end
+
+ def patch_tool
+ build_tool(
+ "patch",
+ "Apply a unified diff patch via 'git apply'. Use for surgical edits to existing files.",
+ { diff: { type: "string" } },
+ ["diff"]
+ )
+ end
+
+ def read_tool
+ build_tool(
+ "read",
+ "Read complete contents of a file. Requires exact file path.",
+ { path: { type: "string" } },
+ ["path"]
+ )
+ end
+
+ def write_tool
+ build_tool(
+ "write",
+ "Write complete file contents (overwrites existing files). Creates parent directories automatically.",
+ { path: { type: "string" }, content: { type: "string" } },
+ ["path", "content"]
+ )
+ end
+
def build_tool(name, description, properties, required = [])
{
type: "function",
lib/elelem/system_prompt.erb
@@ -1,1 +1,5 @@
You are a reasoning coding and system agent.
+
+- Less is more
+- No code comments
+- No trailing whitespace
lib/elelem/tool.rb
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module Elelem
- class Tool
- attr_reader :name, :description, :parameters
-
- def initialize(name, description, parameters, &block)
- @name = name
- @description = description
- @parameters = parameters
- @block = block
- end
-
- def valid?(args)
- JSON::Validator.validate(parameters, args, insert_defaults: true)
- end
-
- def call(*args)
- @block.call(*args)
- end
-
- def to_h
- {
- type: "function",
- function: {
- name: name,
- description: description,
- parameters: parameters
- }
- }
- end
- end
-end
lib/elelem/tools.rb
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Elelem
- class Tools
- def initialize(tools)
- @tools = tools
- end
-
- def add(name, description, parameters, &block)
- @tools << Tool.new(name, description, parameters, &block)
- end
-
- def execute(tool_call)
- name, args = parse(tool_call)
-
- tool = tools.find { |tool| tool.name == name }
- return "Invalid function name: #{name}" if tool.nil?
- return "Invalid function arguments: #{args}" unless tool.valid?(args)
-
- tool.call(args)
- end
-
- def to_h
- tools.map(&:to_h)
- end
-
- private
-
- attr_reader :tools
-
- def parse(tool_call)
- name = tool_call.dig("function", "name")
- arguments = tool_call.dig("function", "arguments")
-
- [name, arguments.is_a?(String) ? JSON.parse(arguments) : arguments]
- end
- end
-end
lib/elelem.rb
@@ -16,8 +16,6 @@ require "timeout"
require_relative "elelem/agent"
require_relative "elelem/application"
require_relative "elelem/conversation"
-require_relative "elelem/tool"
-require_relative "elelem/tools"
require_relative "elelem/version"
Reline.input = $stdin
elelem.gemspec
@@ -38,8 +38,6 @@ Gem::Specification.new do |spec|
"lib/elelem/application.rb",
"lib/elelem/conversation.rb",
"lib/elelem/system_prompt.erb",
- "lib/elelem/tool.rb",
- "lib/elelem/tools.rb",
"lib/elelem/version.rb",
]
spec.bindir = "exe"