Comparing changes
v0.4.1
→
v0.4.2
12 commits
12 files changed
Commits
Changed files (12)
lib/elelem/agent.rb
@@ -66,6 +66,7 @@ module Elelem
end
def format_tool_call_result(result)
+ return if result.nil?
return result["stdout"] if result["stdout"]
return result["stderr"] if result["stderr"]
return result[:error] if result[:error]
@@ -80,7 +81,7 @@ module Elelem
content = ""
tool_calls = []
- print "Thinking..."
+ print "Assistant> Thinking..."
client.chat(messages + turn_context, tools) do |chunk|
msg = chunk["message"]
if msg
lib/elelem/conversation.rb
@@ -45,19 +45,19 @@ module Elelem
case mode.sort
when [:read]
- "#{base}\n\nRead and analyze. Understand before suggesting action."
+ "#{base}\n\nYou may read files on the system."
when [:write]
- "#{base}\n\nWrite clean, thoughtful code."
+ "#{base}\n\nYou may write files on the system."
when [:execute]
- "#{base}\n\nUse shell commands creatively to understand and manipulate the system."
+ "#{base}\n\nYou may execute shell commands on the system."
when [:read, :write]
- "#{base}\n\nFirst understand, then build solutions that integrate well."
+ "#{base}\n\nYou may read and write files on the system."
when [:execute, :read]
- "#{base}\n\nUse commands to deeply understand the system."
+ "#{base}\n\nYou may execute shell commands and read files on the system."
when [:execute, :write]
- "#{base}\n\nCreate and execute freely. Have fun. Be kind."
+ "#{base}\n\nYou may execute shell commands and write files on the system."
when [:execute, :read, :write]
- "#{base}\n\nYou have all tools. Use them wisely."
+ "#{base}\n\nYou may read files, write files and execute shell commands on the system."
else
base
end
lib/elelem/system_prompt.erb
@@ -1,5 +1,15 @@
-You are a reasoning coding and system agent working from: <%= Dir.pwd %>.
+You are a reasoning coding and system agent.
-- Less is more
-- No code comments
-- No trailing whitespace
+## System
+
+Operating System: <%= `uname -a` %>
+USER: <%= ENV['USER'] %>
+HOME: <%= ENV['HOME'] %>
+SHELL: <%= ENV['SHELL'] %>
+PATH: <%= ENV['PATH'] %>
+PWD: <%= ENV['PWD'] %>
+LANG: <%= ENV['LANG'] %>
+EDITOR: <%= ENV['EDITOR'] %>
+LOGNAME: <%= ENV['LOGNAME'] %>
+TERM: <%= ENV['TERM'] %>
+MAIL: <%= ENV['MAIL'] %>
lib/elelem/tool.rb
@@ -11,7 +11,9 @@ module Elelem
end
def call(args)
- return ArgumentError.new(args) unless valid?(args)
+ unless valid?(args)
+ return { error: "Invalid args for #{@name}", received: args.keys, expected: @schema.dig(:function, :parameters, :required) }
+ end
@block.call(args)
end
lib/elelem/toolbox.rb
@@ -8,7 +8,7 @@ module Elelem
full_path.exist? ? { content: full_path.read } : { error: "File not found: #{path}" }
end
- EXEC_TOOL = Tool.build("execute", "Run shell commands. For git: execute({\"cmd\": \"git\", \"args\": [\"log\", \"--oneline\"]}). Returns stdout/stderr/exit_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"]) do |args|
+ BASH_TOOL = Tool.build("bash", "Run shell commands. For git: bash({\"cmd\": \"git\", \"args\": [\"log\", \"--oneline\"]}). Returns stdout/stderr/exit_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"]) do |args|
Elelem.shell.execute(
args["cmd"],
args: args["args"] || [],
@@ -42,7 +42,7 @@ module Elelem
@tools_by_name = {}
@tools = { read: [], write: [], execute: [] }
add_tool(eval_tool(binding), :execute)
- add_tool(EXEC_TOOL, :execute)
+ add_tool(BASH_TOOL, :execute)
add_tool(GREP_TOOL, :read)
add_tool(LIST_TOOL, :read)
add_tool(PATCH_TOOL, :write)
lib/elelem/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Elelem
- VERSION = "0.4.1"
+ VERSION = "0.4.2"
end
spec/elelem/agent_spec.rb
@@ -28,8 +28,8 @@ RSpec.describe Elelem::Agent do
read_history = conversation.history_for([:read])
write_history = conversation.history_for([:write])
- expect(read_history[0][:content]).to include("Read and analyze")
- expect(write_history[0][:content]).to include("Write clean, thoughtful code")
+ expect(read_history[0][:content]).to include("You may read files on the system")
+ expect(write_history[0][:content]).to include("You may write files on the system")
expect(read_history[0][:content]).not_to eq(write_history[0][:content])
end
end
spec/elelem/conversation_spec.rb
@@ -10,43 +10,43 @@ RSpec.describe Elelem::Conversation do
expect(history.length).to eq(1)
expect(history[0][:role]).to eq("system")
- expect(history[0][:content]).to include("Read and analyze")
+ expect(history[0][:content]).to include("You may read files on the system")
end
it "returns history with mode-specific system prompt for write mode" do
history = conversation.history_for([:write])
- expect(history[0][:content]).to include("Write clean, thoughtful code")
+ expect(history[0][:content]).to include("You may write files on the system")
end
it "returns history with mode-specific system prompt for execute mode" do
history = conversation.history_for([:execute])
- expect(history[0][:content]).to include("Use shell commands creatively")
+ expect(history[0][:content]).to include("You may execute shell commands on the system")
end
it "returns history with mode-specific system prompt for read+write mode" do
history = conversation.history_for([:read, :write])
- expect(history[0][:content]).to include("First understand, then build solutions")
+ expect(history[0][:content]).to include("You may read and write files on the system")
end
it "returns history with mode-specific system prompt for read+execute mode" do
history = conversation.history_for([:read, :execute])
- expect(history[0][:content]).to include("Use commands to deeply understand")
+ expect(history[0][:content]).to include("You may execute shell commands and read files on the system")
end
it "returns history with mode-specific system prompt for write+execute mode" do
history = conversation.history_for([:write, :execute])
- expect(history[0][:content]).to include("Create and execute freely")
+ expect(history[0][:content]).to include("You may execute shell commands and write files on the system")
end
it "returns history with mode-specific system prompt for all tools mode" do
history = conversation.history_for([:read, :write, :execute])
- expect(history[0][:content]).to include("You have all tools")
+ expect(history[0][:content]).to include("You may read files, write files and execute shell commands on the system")
end
it "returns base system prompt for unknown mode" do
@@ -182,7 +182,7 @@ RSpec.describe Elelem::Conversation do
parsed = JSON.parse(json)
expect(parsed).to be_an(Array)
expect(parsed.length).to eq(2)
- expect(parsed[0]["content"]).to include("Read and analyze")
+ expect(parsed[0]["content"]).to include("You may read files on the system")
end
end
end
spec/elelem/toolbox_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Elelem::Toolbox do
tool_names = tools.map { |t| t.dig(:function, :name) }
expect(tool_names).to include("grep", "list", "read")
- expect(tool_names).not_to include("write", "patch", "execute")
+ expect(tool_names).not_to include("write", "patch", "bash")
end
it "returns write tools for write mode" do
@@ -19,7 +19,7 @@ RSpec.describe Elelem::Toolbox do
tool_names = tools.map { |t| t.dig(:function, :name) }
expect(tool_names).to include("patch", "write")
- expect(tool_names).not_to include("grep", "execute")
+ expect(tool_names).not_to include("grep", "bash")
end
it "returns execute tools for execute mode" do
@@ -27,7 +27,7 @@ RSpec.describe Elelem::Toolbox do
tools = subject.tools_for(mode)
tool_names = tools.map { |t| t.dig(:function, :name) }
- expect(tool_names).to include("execute")
+ expect(tool_names).to include("bash")
expect(tool_names).not_to include("grep", "write")
end
@@ -36,7 +36,7 @@ RSpec.describe Elelem::Toolbox do
tools = subject.tools_for(mode)
tool_names = tools.map { |t| t.dig(:function, :name) }
- expect(tool_names).to include("grep", "list", "read", "patch", "write", "execute")
+ expect(tool_names).to include("grep", "list", "read", "patch", "write", "bash")
end
it "returns combined tools for build mode" do
@@ -45,7 +45,7 @@ RSpec.describe Elelem::Toolbox do
tool_names = tools.map { |t| t.dig(:function, :name) }
expect(tool_names).to include("grep", "read", "write", "patch")
- expect(tool_names).not_to include("execute")
+ expect(tool_names).not_to include("bash")
end
end
CHANGELOG.md
@@ -1,9 +1,25 @@
## [Unreleased]
+## [0.4.2] - 2025-12-01
+
+### Changed
+- Renamed `exec` tool to `bash` for clarity
+- Improved system prompt with iterative refinements
+- Added environment context variables to system prompt
+
## [0.4.1] - 2025-11-26
### Added
-- Updated version to 0.4.1
+- `elelem files` subcommand: generates Claude‑compatible XML file listings.
+- Rake task `files:prompt` to output a ready‑to‑copy list of files for prompts.
+
+### Changed
+- Refactor tool‑call formatting to a more compact JSON payload for better LLM parsing.
+- Updated CI and documentation to use GitHub instead of previous hosting.
+- Runtime validation of command‑line parameters against a JSON schema.
+
+### Fixed
+- Minor documentation and CI workflow adjustments.
## [0.4.0] - 2025-11-10
@@ -122,16 +138,3 @@
- Initial release
-## [0.4.2] - 2025-11-27
-
-### Added
-- `elelem files` subcommand: generates Claude‑compatible XML file listings.
-- Rake task `files:prompt` to output a ready‑to‑copy list of files for prompts.
-
-### Changed
-- Refactor tool‑call formatting to a more compact JSON payload for better LLM parsing.
-- Updated CI and documentation to use GitHub instead of previous hosting.
-- Runtime validation of command‑line parameters against a JSON schema.
-
-### Fixed
-- Minor documentation and CI workflow adjustments.
Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- elelem (0.4.1)
+ elelem (0.4.2)
erb
fileutils
json
README.md
@@ -125,13 +125,13 @@ seven tools, each represented by a JSON schema that the LLM can call.
| Tool | Purpose | Parameters |
| ---- | ------- | ---------- |
+| `bash` | Run shell commands | `cmd`, `args`, `env`, `cwd`, `stdin` |
| `eval` | Dynamically create new tools | `code` |
| `grep` | Search Git‑tracked files | `query` |
| `list` | List tracked files | `path` (optional) |
+| `patch` | Apply a unified diff via `git apply` | `diff` |
| `read` | Read file contents | `path` |
| `write` | Overwrite a file | `path`, `content` |
-| `patch` | Apply a unified diff via `git apply` | `diff` |
-| `execute` | Run shell commands | `cmd`, `args`, `env`, `cwd`, `stdin` |
## Tool Definition