FIX SOME BUGS

This commit is contained in:
2026-09-12 10:14:55 +02:00
parent 02d48a304a
commit 8f1c3207c9
15 changed files with 1356 additions and 82 deletions
+62 -9
View File
@@ -1,18 +1,52 @@
# sjcode
ein terminal coding agent, der die ollama API nutzt
a terminal coding agent, powered by the ollama API
## What makes it an agent
The client is not a chat front end: the model can **really work in your
codebase**. It runs shell commands, reads and edits files — on your machine,
in the directory you started `./coder` from. Every model reply can contain
tool calls; the client executes them and feeds the real output back to the
model until the task is done.
Tools the agent can use:
| tool | what it does | asks first |
|---------|--------------------------------------------------|------------|
| `run` | run one shell command in the project directory | yes |
| `read` | read a file (numbered lines, `start`/`limit`) | no |
| `files` | list project files (skips `.git`, caches, ...) | no |
| `write` | create a file, or overwrite a small one | yes |
| `edit` | exact-text replace in a file, shows a diff | yes |
Before every `run`/`write`/`edit` you see exactly what will happen (command
line, or a unified diff for file changes) and press Enter to allow it, `n` to
decline, `a` to stop the agent — or just type a short instruction ("use ripgrep
instead") and the model adapts. `--yes` (or `/auto` in the session) runs
everything without asking; the sandbox keeps all file tools inside the project
directory.
## Setup
```bash
cp config.toml.example config.toml # then edit port / model / limits
python3 server/server.py # starts the daemon + admin CLI
cp server/config.toml.example server/config.toml # then edit port/model/limits
python3 server/server.py # starts the daemon + admin CLI
```
`config.toml` is machine-local and git-ignored; `config.toml.example` is the
template. On first start the daemon creates the SQLite database (`sjcode.db`).
## Daemon (server.py)
Pick a coder model in `[ollama] model` — one that follows structured output
well, e.g. `qwen2.5-coder:7b` or bigger. The agent transcript is long, so the
daemon requests a large context window from ollama:
```toml
[ollama]
num_ctx = 16384 # context window; do not go below 8192 for agent mode
```
## Daemon (server/server.py)
On startup it prints its settings and drops into a minimal admin CLI
(accounts are stored in SQLite):
@@ -32,12 +66,18 @@ On startup it prints its settings and drops into a minimal admin CLI
While the CLI runs, an HTTP API is served in the background:
- `POST /login` — `{"username", "password"}` → `{"token", ...}`
- `POST /chat` — `{"token", "message", "model"?}` → `{"response", ...}`
- `POST /chat` — `{"token", "message", "model"?, "stream"?}` → reply as JSON,
or (with `"stream": true`) as NDJSON lines `{"chunk": ...}` ending with one
final `{"response", "used_minutes", "remaining_minutes", ...}` line
- `GET /models?token=...` — list ollama models
- `GET /status` — health check
Every user row stores: `username`, `password_hash`, `last_logged_in`,
`role`, `used_today` (minutes of AI usage; resets on a new day).
`SJCODE_CONFIG=/path/to/config.toml` lets you run a second daemon (tests,
staging) next to a regular one.
## Roles and limits
In `config.toml` each role gets a daily limit in minutes:
@@ -56,6 +96,7 @@ Login and every chat request are blocked once `used_today` reaches the limit.
./coder # or: python3 client.py
python3 client.py 10.0.0.5:8420 # explicit daemon address
python3 client.py --model qwen3-coder # skip the model picker
python3 client.py --yes # auto-approve every tool call (careful)
python3 client.py --no-probe # skip the reachability check (use behind
# HTTP proxies that answer on every port)
```
@@ -66,7 +107,10 @@ ones, or add a new one (`n`). Every server you use is saved in
model, so the next start is just Enter-Enter. Addresses without a port use
8420; `host:port`, `http(s)://...` URLs and IPv6 literals are accepted.
After login and model choice you get the agent banner and a chat REPL.
After login and model choice you get the agent banner and a REPL. Type tasks,
not chat messages — "rename the function foo to bar in all files" is a task,
"what is a monad" is just a question the agent answers in place.
Commands:
| command | effect |
@@ -76,14 +120,23 @@ Commands:
| `/models` | list models on the server |
| `/model <n>` | switch model (saved for this server) |
| `/limit` | remaining minutes today (last known) |
| `/auto` | toggle confirmations (auto-approve all) |
| `/state` | auto mode, project dir, history size |
| `/cwd` | show the project directory |
| `/clear` | forget the conversation history |
| `/quit` | exit |
Anything else is sent to the model. The client keeps the last few turns as
context (the daemon API itself is stateless) and renders the reply in the
agent style (`✓` lines for actions the model reports).
The agent keeps the last few finished tasks as context. It stops after 30
model round-trips per task; the daemon API itself is stateless.
## Requirements
- Python 3.11+ (stdlib only; `tomllib` is included)
- ollama listening on the address from `config.toml`
## Tests
```bash
python3 -m unittest test_client.py -v # unit tests (no network)
python3 test_e2e.py # fake ollama + daemon + client
```