token accounting cleanup

This commit is contained in:
Luxferre
2026-08-18 10:17:52 +03:00
parent 4a936e850d
commit a34ee1cf3c
6 changed files with 251 additions and 30 deletions
+5 -5
View File
@@ -2,7 +2,7 @@
## 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, prefix-cache-friendly 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, 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.
The entire philosophy of Bantam is built upon two principles:
@@ -64,7 +64,7 @@ All implementations read the same `model.cfg` and `system.txt` from the current
- `/save` — save the entire conversation to a new session file (auto-id like `20260808-190038`) and generate its summary
- `/list` — list saved sessions (newest first) with their ids, timestamps, message counts and summaries
- `/load <id>` — load a saved session (exact id or unique prefix) and continue from there
- `/compact` — compact context down to the system message and a concise summary using the LLM; the compaction prompt is appended directly to the existing message prefix to guarantee a 100% prompt cache hit
- `/compact` — compact context down to the system message and a concise summary using the LLM; the compaction prompt is appended to the conversation to derive the summary, then the conversation is reset to `[system, summary-user-message]` (a fresh prefix, so downstream prompt-cache hits depend on the provider and are not guaranteed)
- `/cfg <param> [val]` — inspect or update a configuration parameter in `model.cfg` live
- `!<cmd>` — execute a shell command directly through `shell_exec` without adding the result to the conversation context (Go port)
- `/help` — show all supported commands
@@ -104,7 +104,7 @@ Using these rules, everyone can build their own copy of Bantam from scratch in l
4. **Post-Turn Reporting & Compaction**:
- Display token usage and context window percentage.
- If context usage is >= 60%, prompt user to compact.
- Compaction appends `"You are now acting as a compaction engine. Summarize the preceding conversation concisely but completely..."` as a user message to the conversation, invokes the LLM (ensuring zero prompt cache misses), and resets the conversation to the system prompt and the resulting summary.
- Compaction appends `"You are now acting as a compaction engine. Summarize the preceding conversation concisely but completely..."` as a user message to the conversation, invokes the LLM, and then resets the conversation to the system prompt plus a `user` message carrying the resulting summary. (The compaction prompt is not retained; the post-compaction conversation is a new prefix, so prompt-cache hits are provider-dependent.)
### Main program
@@ -112,7 +112,7 @@ Using these rules, everyone can build their own copy of Bantam from scratch in l
2. Read model parameters from `model.cfg` (`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.
5. Read user prompt from standard input (with `readline` line editing and history in `~/.bantam_history`; **Ctrl+J** inserts a real newline into the line being edited). If equal to `/quit` or EOF, exit. If equal to `/clear`, reset `messages` to step 3 and return to step 5. If equal to `/save`, write the whole `messages` array to `~/.bantam/sessions/<id>.json` (with an auto-generated summary) and return to step 5. If equal to `/list`, print saved sessions and their summaries and return to step 5. If starting with `/load`, replace `messages` with the saved session's messages (by exact id or unique prefix) and return to step 5. If equal to `/compact`, ask the LLM to summarize the conversation by appending the compaction prompt to preserve KV cache, replace `messages` with `[system, summary-user-message]`, and return to step 5. If starting with `/cfg`, display the current value (`/cfg <param>`) or update `model.cfg` live (`/cfg <param> <val>`) and return to step 5. If starting with `!`, execute the command directly via `shell_exec` without adding the result to `messages` and return to step 5. If equal to `/help`, print the command list and return to step 5. After every user turn and on exit, auto-save `messages` to `~/.bantam/sessions/autosave.json`.
5. Read user prompt from standard input (with `readline` line editing and history in `~/.bantam_history`; **Ctrl+J** inserts a real newline into the line being edited). If equal to `/quit` or EOF, exit. If equal to `/clear`, reset `messages` to step 3 and return to step 5. If equal to `/save`, write the whole `messages` array to `~/.bantam/sessions/<id>.json` (with an auto-generated summary) and return to step 5. If equal to `/list`, print saved sessions and their summaries and return to step 5. If starting with `/load`, replace `messages` with the saved session's messages (by exact id or unique prefix) and return to step 5. If equal to `/compact`, ask the LLM to summarize the conversation by appending the compaction prompt to derive the summary, replace `messages` with `[system, summary-user-message]`, and return to step 5. If starting with `/cfg`, display the current value (`/cfg <param>`) or update `model.cfg` live (`/cfg <param> <val>`) and return to step 5. If starting with `!`, execute the command directly via `shell_exec` without adding the result to `messages` and return to step 5. If equal to `/help`, print the command list and return to step 5. After every user turn and on exit, auto-save `messages` to `~/.bantam/sessions/autosave.json`.
6. Append user prompt to `messages` (`role: "user"`), run `AL(cfg, messages)`, display token usage, check 60% context threshold for auto-compaction, and go to step 5.
### Agentic loop (`AL(cfg, messages)`) function
@@ -179,7 +179,7 @@ MicroBantam (`mb`) is a compressed Perl 5 reference implementation of the same a
- 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
- Interactive mode (`/quit`, `/clear`, `/save`, `/list`, `/load <id>`, `/cfg`, `/help`) and file input mode
- Same built-in default system prompt and `OPENAI_API_KEY` fallback as the Go implementation
- Automatic recovery from `Invalid assistant message: content or tool_calls must be set` API errors: strips the last assistant message and retries
- Automatic recovery from `Invalid assistant message: content or tool_calls must be set` API errors: strips the last assistant message and retries (matches the Go port; note that a 4xx response other than this specific error aborts the run with an `API error` message, unlike the Go port which retries only on 5xx/408/429)
### What it drops