tool set refactor
This commit is contained in:
@@ -2,12 +2,12 @@
|
||||
|
||||
## About
|
||||
|
||||
Bantam is a minimalist, dependency-free AI agent specification with reference implementations in **Go** (`main.go` + `term_*.go`, module `code.luxferre.top/luxferre/bantam`) and **Perl 5** as **MicroBantam** (`mb`, under 100 SLOC). It provides an agentic loop capable of autonomous tool execution, direct shell interaction, real-time response streaming, markdown terminal rendering with box-drawing tables, Fibonacci backoff network resilience, context window auto-discovery, token usage tracking with prompt cache breakdowns, conversation compaction, and subagent delegation using any OpenAI-compatible completions API.
|
||||
Bantam is a minimalist, dependency-free AI agent specification with reference implementations in **Go** (`main.go` + `term_*.go`, module `code.luxferre.top/luxferre/bantam`) and **Perl 5** as **MicroBantam** (`mb`, under 100 SLOC). It provides an agentic loop capable of autonomous tool execution, direct shell interaction, file writing/editing, real-time response streaming, markdown terminal rendering with box-drawing tables, Fibonacci backoff network resilience, context window auto-discovery, token usage tracking with prompt cache breakdowns, and conversation compaction using any OpenAI-compatible completions API.
|
||||
|
||||
The entire philosophy of Bantam is built upon two principles:
|
||||
|
||||
1. The structure must be as simple as possible for anyone to be able to reimplement the agent from a plain algorithm description.
|
||||
2. The agent only needs to provide two tools: a tool to call shell commands and a tool to call itself. In theory, this should be sufficient to give LLMs the ability to handle tasks of any complexity.
|
||||
2. The agent only needs to provide two tools: a tool to call shell commands (`shell_exec`) and a tool to write/edit files (`write_file`). In theory, this should be sufficient to give LLMs the ability to handle tasks of any complexity.
|
||||
|
||||
Because of the second principle, Bantam itself was named after Victorinox Bantam Alox, a small and lightweight Swiss army knife with only two tools.
|
||||
|
||||
@@ -35,7 +35,7 @@ The Go port is a single `main.go` plus four platform files (`term_linux.go`, `te
|
||||
|
||||
### Running Bantam
|
||||
|
||||
All implementations read `model.cfg` (or `.bantam.cfg`, which takes priority if present) and `.bantamsys.txt` from the current working directory.
|
||||
All implementations read `model.cfg` (or `.bantam.cfg`, which takes priority if present) from the current working directory.
|
||||
|
||||
1. Configure `model.cfg` (or `.bantam.cfg`, which takes priority) with your API settings:
|
||||
```ini
|
||||
@@ -93,14 +93,14 @@ Using these rules, everyone can build their own copy of Bantam from scratch in l
|
||||
|
||||
### High-Level Overview
|
||||
|
||||
1. **Initialization**: Read `.bantamsys.txt` and the config file (`.bantam.cfg` if present, else `model.cfg`). Discover context window size from the `/models` endpoint (or fallback to `context_window` from `model.cfg` or 200,000 tokens). Prepare an array of messages starting with the system prompt `{"role": "system", "content": system_prompt}`.
|
||||
1. **Initialization**: Read the config file (`.bantam.cfg` if present, else `model.cfg`). Discover context window size from the `/models` endpoint (or fallback to `context_window` from `model.cfg` or 200,000 tokens). Prepare an array of messages starting with the built-in system prompt `{"role": "system", "content": system_prompt}`.
|
||||
2. **Input Processing**: Take user prompt (via command-line file parameter or interactive stdin). If prefixed with `!`, execute the command directly via `shell_exec` without appending to conversation context. Otherwise, append `{"role": "user", "content": prompt}`, and invoke `AL(cfg, messages)`.
|
||||
3. **Agentic Loop (`AL`)**:
|
||||
- Send `messages` and tool definitions to the OpenAI-compatible `/chat/completions` API endpoint with custom `User-Agent` headers and `stream_options: {"include_usage": true}`.
|
||||
- Send `messages` and tool definitions (`shell_exec`, `write_file`) to the OpenAI-compatible `/chat/completions` API endpoint with custom `User-Agent` headers and `stream_options: {"include_usage": true}`.
|
||||
- Support context cancellation (e.g. on `SIGINT` / Ctrl+C) to cleanly abort in-flight requests without appending incomplete messages.
|
||||
- On network or HTTP failure, retry using Fibonacci backoff delays (`1s, 1s, 2s, 3s, 5s, 8s, 13s, 21s, 34s`).
|
||||
- If `stream=true`, parse SSE data chunks (`data: {...}`) in real-time to stream reasoning content (`reasoning_content`) and response text directly to stdout, bracketing the reasoning block with `--- reasoning start ---` / `--- reasoning end ---` markers, rendering Markdown and tables constrained to terminal width.
|
||||
- Reconstruct the assistant message and track usage tokens (`prompt_tokens`, `completion_tokens`, cached tokens). If `tool_calls` exist, trace the call (`[tool call: name(args)]`), validate JSON arguments, execute the requested tool (`shell_exec` or `run_subagent`), trace the result (`[tool result: name]`), append the tool response `{"role": "tool", "tool_call_id": id, "content": result}`, and repeat the loop.
|
||||
- Reconstruct the assistant message and track usage tokens (`prompt_tokens`, `completion_tokens`, cached tokens). If `tool_calls` exist, trace the call (`[tool call: name(args)]`), validate JSON arguments, execute the requested tool (`shell_exec` or `write_file`), trace the result (`[tool result: name]`), append the tool response `{"role": "tool", "tool_call_id": id, "content": result}`, and repeat the loop.
|
||||
- If no tool calls remain or `max_al_iterations` is reached, return the updated messages list and turn usage stats.
|
||||
4. **Post-Turn Reporting & Compaction**:
|
||||
- Display token usage and context window percentage.
|
||||
@@ -109,7 +109,7 @@ Using these rules, everyone can build their own copy of Bantam from scratch in l
|
||||
|
||||
### Main program
|
||||
|
||||
1. Read system prompt from `.bantamsys.txt` (default if missing).
|
||||
1. Initialize system prompt from built-in default.
|
||||
2. Read model parameters from the config file (`.bantam.cfg` if present, else `model.cfg`) in `key=value` format and discover context window size.
|
||||
3. Prepare a new message list with the system prompt (`role: "system"`).
|
||||
4. Read the first command-line parameter. If non-empty, read user prompt from the specified file. If prefixed with `!`, execute the shell command directly via `shell_exec` and exit. Otherwise, append to `messages` (`role: "user"`), run `AL(cfg, messages)`, display token usage, and exit.
|
||||
@@ -126,7 +126,7 @@ Using these rules, everyone can build their own copy of Bantam from scratch in l
|
||||
3. If there are pending `tool_calls` in the assistant response:
|
||||
- For each tool call, output a trace log (`[tool call: name(args)]`).
|
||||
- Sanitize tool arguments to filter out non-printable and space-like Unicode characters (protecting against indirect prompt injection), and validate JSON arguments. If invalid, format a tool-error response so the LLM can self-correct.
|
||||
- Execute tool action (`shell_exec` or `run_subagent`).
|
||||
- Execute tool action (`shell_exec` or `write_file`).
|
||||
- Sanitize the tool result output to strip any non-printable and space-like Unicode characters (leaving only ASCII space, tab, newline, and printable Unicode characters).
|
||||
- Output a trace log of the result (`[tool result: name]`).
|
||||
- Append tool result message (`role: "tool"`, `tool_call_id`, `content`: result string) to `messages`.
|
||||
@@ -158,11 +158,15 @@ When enabled, the interactive console uses a subtle ANSI palette: the pending-re
|
||||
|
||||
### Tool call definitions
|
||||
|
||||
#### `run_subagent` tool
|
||||
#### `write_file` tool
|
||||
|
||||
- Parameters: `prompt` (string)
|
||||
- Parameters:
|
||||
- `path` (string, required): JSON-escaped file path to write to (must be created unless existing).
|
||||
- `offset` (integer, optional, default 0): byte offset to start writing from.
|
||||
- `del_bytes` (integer, optional, default 0): bytes to delete starting from the `offset` prior to writing.
|
||||
- `content` (string, required, may be empty): JSON-escaped content to write to the file.
|
||||
- Return value: string
|
||||
- Action: run `AL(cfg, [{"role": "system", "content": system_prompt + "\n\nImportant: this is a child agent"}, {"role": "user", "content": prompt}])` subject to recursion depth limit (`MAX_DEPTH = 5`) and return the text content of the last `assistant`-role message.
|
||||
- Action: write `content` into the file at `path` starting at `offset` after deleting `del_bytes` bytes (creating the file and any necessary parent directories).
|
||||
|
||||
#### `shell_exec` tool
|
||||
|
||||
@@ -172,11 +176,11 @@ When enabled, the interactive console uses a subtle ANSI palette: the pending-re
|
||||
|
||||
## MicroBantam
|
||||
|
||||
MicroBantam (`mb`) is a compressed Perl 5 reference implementation of the same agent in **under 100 SLOC**, written to stay readable while keeping the full agentic core. It reads the config file (`.bantam.cfg` if present, else `model.cfg`) and `.bantamsys.txt` from the current working directory.
|
||||
MicroBantam (`mb`) is a compressed Perl 5 reference implementation of the same agent in **under 100 SLOC**, written to stay readable while keeping the full agentic core. It reads the config file (`.bantam.cfg` if present, else `model.cfg`) from the current working directory.
|
||||
|
||||
### Features
|
||||
|
||||
- Full agentic loop: LLM calls, `shell_exec` / `run_subagent` tool execution with JSON argument validation (invalid args are fed back so the model can self-correct), and the 5-level subagent recursion depth limit
|
||||
- Full agentic loop: LLM calls, `shell_exec` / `write_file` tool execution with JSON argument validation (invalid args are fed back so the model can self-correct)
|
||||
- Indirect prompt injection defense: sanitizes tool parameters and tool outputs by filtering non-printable and space-like Unicode characters, preserving standard space, tab, newline, and printable Unicode characters
|
||||
- A `...requesting...` in-flight indicator: in-place on a TTY (`\r` overwrite, erased on completion), a plain line when output is piped
|
||||
- Session management: `/save`, `/list`, `/load <id>` (exact id only, no prefix matching), `/cfg <param> [val]`, and auto-save to `~/.bantam/sessions/autosave.json` after every turn and on exit; session ids get `-1`, `-2`, ... suffixes on same-second collisions
|
||||
@@ -203,14 +207,14 @@ MicroBantam (`mb`) is a compressed Perl 5 reference implementation of the same a
|
||||
|
||||
- `main.go`, `term_linux.go`, `term_bsd.go`, `term_windows.go`, `term_other.go` — Go implementation (stdlib only, module `code.luxferre.top/luxferre/bantam`)
|
||||
- `mb` — MicroBantam, compressed Perl 5 implementation (core modules only, under 100 SLOC)
|
||||
- `model.cfg` (or `.bantam.cfg`, which takes priority), `.bantamsys.txt` — shared configuration and system prompt
|
||||
- `model.cfg` (or `.bantam.cfg`, which takes priority) — configuration file
|
||||
- `README.md` — this document
|
||||
|
||||
## Extra tools
|
||||
|
||||
The `extras/` directory contains small, dependency-light shell scripts that extend Bantam without changing its core. Because Bantam's only built-in tools are `shell_exec` and `run_subagent`, these helpers can be invoked directly by the agent through `shell_exec` to give it real-world capabilities (web search, live weather) that the base model alone does not have. They are plain `/bin/sh` scripts depending only on `curl` (and `jq` where noted), so the agent can discover and run them just like any other command.
|
||||
The `extras/` directory contains small, dependency-light shell scripts that extend Bantam without changing its core. Because Bantam's built-in tools are `shell_exec` and `write_file`, these helpers can be invoked directly by the agent through `shell_exec` to give it real-world capabilities (web search, live weather) that the base model alone does not have. They are plain `/bin/sh` scripts depending only on `curl` (and `jq` where noted), so the agent can discover and run them just like any other command.
|
||||
|
||||
If you keep your own collection of helper scripts, point Bantam at them with the `BANTAM_TOOLS_DIR` environment variable or the `bantam_tools_dir` key in the config file (`.bantam.cfg` if present, else `model.cfg`). When either is defined (environment variable taking precedence over the config key), the Go port appends the line `Extra shell tools can be found at <dir>` to the loaded system prompt at startup, so the agent is aware of where to look for them. This hint is propagated to child agents as well (via the `run_subagent` system prompt). The `extras/` scripts shipped here are just examples of what such a directory can contain.
|
||||
If you keep your own collection of helper scripts, point Bantam at them with the `BANTAM_TOOLS_DIR` environment variable or the `bantam_tools_dir` key in the config file (`.bantam.cfg` if present, else `model.cfg`). When either is defined (environment variable taking precedence over the config key), the Go port appends the line `Extra shell tools can be found at <dir>` to the system prompt at startup, so the agent is aware of where to look for them. The `extras/` scripts shipped here are just examples of what such a directory can contain.
|
||||
|
||||
### `extras/websearch`
|
||||
|
||||
@@ -254,7 +258,6 @@ Options include `-l/--location`, `-u/--units` (`m`/`u`/`M`), `-L/--lang`,
|
||||
`-A` (force ANSI) and `-h/--help`. Environment overrides: `WTTRAPI` (default
|
||||
`https://wttr.in`) and `WEATHER_TIMEOUT` (default `20`s).
|
||||
|
||||
Dependencies: `curl`, `jq` (only required for the JSON format).
|
||||
Dependencies: `curl`, `jq` (only required for the JSON format).
|
||||
|
||||
### `extras/context7`
|
||||
@@ -291,9 +294,9 @@ Dependencies: `curl`, `jq`.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Does Bantam support `AGENTS.md` etc?
|
||||
### Does Bantam support `AGENTS.md`?
|
||||
|
||||
The default system prompt instructs the agent to respect `AGENTS.md`/`GEMINI.md`/`CLAUDE.md` files.
|
||||
The default system prompt instructs the agent to respect `AGENTS.md` contents in the project.
|
||||
|
||||
### How do I tell Bantam about extra shell tools?
|
||||
|
||||
@@ -301,7 +304,7 @@ Set the `BANTAM_TOOLS_DIR` environment variable (or the `bantam_tools_dir` key i
|
||||
|
||||
### Is there any common config place for Bantam?
|
||||
|
||||
No, loading the config file (`.bantam.cfg` if present, else `model.cfg`) and `.bantamsys.txt` is deliberately only supported from the current working directory. This allows natural separation of configs and system prompts per project. In case there's no `.bantamsys.txt` inside the project, the concise and sensible default system prompt will be loaded. In case there's no config file inside the project, Bantam will use the free Big Pickle model from OpenCode Zen with the temperature 0.7. Big Pickle has been chosen as the default because it has no set expiration date, unlike other OpenCode's keyless tiers.
|
||||
No, loading the config file (`.bantam.cfg` if present, else `model.cfg`) is deliberately only supported from the current working directory. This allows natural separation of configs per project. In case there's no config file inside the project, Bantam will use the free Big Pickle model from OpenCode Zen with the temperature 0.7. Big Pickle has been chosen as the default because it has no set expiration date, unlike other OpenCode's keyless tiers.
|
||||
|
||||
### Why no MCP support?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user