Usability pass: tool registry, TUI polish, saved keys and settings

Tools
- Table-driven tool registry with permission classes and default/minimal
  profiles; new tools: edit_file, list_dir, glob, grep, delete_file,
  move_file, todo_write, web_fetch, ask_user (plus read_file paging).
- Built-in Myers diff; write tools return unified diffs.
- Persistent permission rules (.agent/permissions.json), per-turn undo
  snapshots (.agent/undo), AGENTS.md project notes, auto-compact at 80%
  of the model context, cancellable run_shell with process-group kill.

TUI
- Table-driven slash commands: /provider /key /effort /status /tools
  /permissions /yolo /undo /retry /diff /export /copy /rename /delete
  /init /max-steps /todo, with / and @ completion.
- Permission modal with diff and prefix rules, ask_user modal, todo
  panel, header with model/effort/context, bracketed paste, line editing,
  wide-char cursor, NO_COLOR and ASCII fallback; Esc never quits.

Startup and configuration
- API keys are entered in the TUI (hidden) and saved per provider in
  <config>/credentials (0600); env variables are only a fallback.
- Last provider, per-provider model and reasoning effort are remembered
  in <config>/settings.json; --effort/-e and /effort send
  reasoning_effort (low|medium|high|max) to models that accept it.
- DeepSeek preset uses deepseek-flash / deepseek-v4-pro.
- Session flags --new/--continue/--resume/--list-sessions, --yolo,
  --confirm.

Compatibility and tests
- ncurses detection, macOS/Homebrew support, make install, XDG config
  dir, POSIX cleanups; Gitea CI (gcc/clang/asan/musl/macOS).
- Unit tests for diff, fs tools, registry, undo/perms and config;
  e2e fixtures multi_file_refactor and ask_or_todo; vendored cJSON.
This commit is contained in:
WHC
2026-10-05 01:47:01 +08:00
parent 9877ff48b6
commit 2fde898da0
105 changed files with 19348 additions and 3786 deletions
+50 -28
View File
@@ -1,47 +1,56 @@
# OpenAI 兼容 API 环境变量
CST-Agent 使用 **OpenAI Chat Completions** 协议(`POST {base}/chat/completions`),
可对接官方 OpenAI、MiniMax、以及其它兼容网关。
CST-Agent 使用 **OpenAI Chat Completions** 协议(`POST {base}/chat/completions`,SSE 流式),
可对接官方 OpenAI、DeepSeek、MiniMax,以及其它兼容网关。
## 必填 / 常用
## Provider 预设
| 变量 | 别名 | 说明 | 示例 |
`--provider NAME`(或 `CST_PROVIDER`,或 TUI 里的 `/provider`)一次性给出 base 和默认模型。
不传时沿用上次使用的 provider(记在配置目录的 `settings.json`)。
| provider | API Base | 默认模型 | Key 变量 |
|---|---|---|---|
| `CST_API_KEY` | `OPENAI_API_KEY`、`MINIMAX_API_KEY` | API Key(按此优先级读取) | `sk-...` |
| `CST_API_BASE` | `OPENAI_BASE_URL`、`OPENAI_API_BASE` | API 根路径,须含 `/v1`(不要带 `/chat/completions`) | `https://api.openai.com/v1` |
| `CST_MODEL` | `OPENAI_MODEL` | 模型名 | `gpt-4.1-mini` / `MiniMax-M2.7` |
| `minimax`(默认) | `https://api.minimax.cn/v1` | `MiniMax-M2.7` | `MINIMAX_API_KEY` |
| `deepseek` | `https://api.deepseek.com/v1` | `deepseek-flash`(另有 `deepseek-v4-pro`) | `DEEPSEEK_API_KEY` |
| `openai` | `https://api.openai.com/v1` | `gpt-4.1-mini` | `OPENAI_API_KEY` |
未设置 key 时:读配置文件 →(Linux)zenity / 控制台输入。
显式给出的 `--api-base` / `--model` / 下表中的环境变量优先于预设。
配置文件:
- Linux/Termux:`~/.config/cst-agent/credentials`
## 解析顺序
| 项 | 优先级(高 → 低) |
|---|---|
| Key | `--api-key`(**只用于本次进程,不写盘**)→ 该 provider 已保存的 key → provider 的 Key 变量 → `CST_API_KEY` → TUI 弹出遮罩输入框(输入后保存) |
| Base(含 `/v1`,不带 `/chat/completions`) | `--api-base` → `CST_API_BASE` → `OPENAI_BASE_URL` → `OPENAI_API_BASE` → 预设 |
| Model | `--model` → `CST_MODEL` → `OPENAI_MODEL` → 该 provider 上次使用的模型 → 预设 |
| 推理强度 | `--effort` → `CST_EFFORT` → 上次使用 → `medium`(low / medium / high / max) |
key 按 provider 保存在 credentials 文件(权限 0600),每行 `<provider>.api_key=...`;
TUI 里 `/key` 更换,命令行 `--ask-key` 输入(不回显):
- Linux/macOS/Termux:`$XDG_CONFIG_HOME/cst-agent/credentials`(默认 `~/.config/cst-agent/`)
- Windows:`%APPDATA%\cst-agent\credentials`
旧版只有一行 `api_key=` 的文件仍可读:按其中的 `api_base` 归到对应 provider(没有 `api_base` 时视为 MiniMax)。
## 示例
### DeepSeek
```bash
cst-agent --provider deepseek # 首次会询问 key;默认 deepseek-flash
cst-agent --provider deepseek --model deepseek-v4-pro -e high # 推理内容显示为 Thought
```
### OpenAI 官方
```bash
export OPENAI_API_KEY='sk-...'
export OPENAI_BASE_URL='https://api.openai.com/v1'
export OPENAI_MODEL='gpt-4.1-mini'
./cst-agent --workspace .
```
等价 CST 前缀:
```bash
export CST_API_KEY='sk-...'
export CST_API_BASE='https://api.openai.com/v1'
export CST_MODEL='gpt-4.1-mini'
cst-agent --provider openai
```
### MiniMax(默认)
```bash
export CST_API_KEY='...' # 或 MINIMAX_API_KEY
# 默认 base=https://api.minimax.cn/v1 model=MiniMax-M2.7
./cst-agent --workspace .
cst-agent --provider minimax
```
### 任意兼容网关
@@ -53,21 +62,34 @@ export OPENAI_MODEL='your-model'
./cst-agent --headless --prompt 'ping' --workspace .
```
命令行也可覆盖:`--api-base` / `--api-key` / `--model`。
网关不支持 `stream_options.include_usage` 时设 `CST_NO_STREAM_USAGE=1`。
## 其它环境变量
| 变量 | 说明 |
|---|---|
| `CST_PROTOCOL` | 工具调用协议:`native-eos`(默认)/ `native-inc` / `ctl` / `ctl-heredoc` / `xml` |
| `CST_MAX_STEPS` | 每个用户回合最多调用模型几次(默认 30) |
| `CST_TOOL_OUT_CAP` | 单个工具输出发给模型的字节上限(默认 16384) |
| `CST_CTX_WINDOW` | 发给模型的最近非 system 消息条数(默认 80) |
| `CST_SHELL_TIMEOUT` | `run_shell` 超时秒数(默认 120) |
| `CST_METRICS=0` / `CST_METRICS_PATH` | 关闭 / 指定计时埋点 JSONL |
| `CST_RECORD_SSE` / `CST_REPLAY_SSE` | 录制 / 回放原始 SSE 流目录;`CST_REPLAY_CHUNK` 控制回放分块字节数 |
| `CST_MODELS` | `/model` 可选列表,`:` 或 `,` 分隔 |
| `CST_AUTO_APPROVE=1` | 自动允许 shell/写文件(headless 常用) |
| `CST_AUTO_APPROVE=1` | 自动允许 shell/写文件(headless 默认开启) |
| `CST_SHELL` | shell 解释器路径(覆盖 busybox/`sh`) |
| `CST_EXE_DIR` | 可执行文件目录(Termux 旁路 busybox 时有用) |
网络:连接超时 30 秒;300 秒内无数据视为超时;429 / 5xx / 连接错误在尚未收到任何内容时自动重试 3 次(1s、2s、4s 退避)。
## CLI 对照
```text
--provider NAME ← CST_PROVIDER
--api-base URL ← CST_API_BASE / OPENAI_BASE_URL
--api-key KEY ← CST_API_KEY / OPENAI_API_KEY
--api-key KEY ← 已保存的 key / <provider key 变量> / CST_API_KEY
--model NAME ← CST_MODEL / OPENAI_MODEL
--effort LEVEL ← CST_EFFORT
--protocol P ← CST_PROTOCOL
--max-steps N ← CST_MAX_STEPS
```