内容
# minicode
`minicode` 是一个从零实现、便于阅读和测试的命令行编程 Agent。项目不依赖 LangChain,核心目标是展示流式 Function Calling、工具安全边界、审批暂停/恢复、会话持久化和结构化运行 Trace 的运行机制。
## 当前里程碑:核心可用版
已实现:
- OpenAI/vLLM 兼容的流式 Chat Completions 客户端;
- 按 tool-call index 拼接被任意切分的 `id`、函数名和 JSON 参数;
- 可多轮自主执行的 Agent Loop;
- `read_file`、`list_files`、`write_file`、`run_shell` 工具;
- 基于解析后绝对路径的工作区边界检查;
- 写文件与 Shell 命令的一次性权限审批;
- SQLite WAL 会话、消息、运行、工具调用和审批状态;
- `(run_id, tool_call_id)` 唯一约束,避免同一运行内的工具重复执行;
- JSONL EventBus Trace;
- 不需要 API Key 的确定性离线演示与测试模型。
- TCP + newline-delimited JSON-RPC Daemon/Client;
- 多客户端按 session 订阅同一事件流;
- 事件序列可从轮转 JSONL 日志恢复,支持 Daemon 重启后的 `after_sequence` 回放;
- `run.cancel` 父 Agent 协作式取消,取消请求持久化并在安全执行边界生效;
- Daemon token 握手、消息大小限制和 allowed-root 工作区约束;
- 同一 session 的 Agent 请求串行化,跨 session 可并发;
- MCP stdio 初始化、工具发现、分页 `tools/list` 和动态工具注册;
- MCP 工具默认走权限审批,调用超时或断连不会自动重放。
当前安全边界属于“受限本地执行”,不是容器或虚拟机级强隔离。高风险任务仍建议放在 Docker、WSL 或独立工作区中运行。
## 快速开始
```powershell
conda activate adaptive-router
python -m pip install -e ".[dev]"
minicode demo --workspace .
```
连接 OpenAI 兼容 API:
```powershell
$env:MINICODE_BASE_URL = "http://127.0.0.1:8000/v1"
$env:MINICODE_MODEL = "Qwen/Qwen2.5-1.5B-Instruct"
$env:MINICODE_API_KEY = "EMPTY"
minicode chat --workspace C:\path\to\repository
```
商业 API 也可使用同样的环境变量接入。API Key 不写入项目文件。
## Daemon / Client
先启动 Daemon。若不指定 token,会随机生成并显示一次:
```powershell
$env:MINICODE_BASE_URL = "http://127.0.0.1:8000/v1"
$env:MINICODE_MODEL = "Qwen/Qwen2.5-1.5B-Instruct"
minicode-daemon --allowed-root C:\path\to\projects --port 8765
```
然后在另一个终端连接:
```powershell
$env:MINICODE_DAEMON_TOKEN = "复制 Daemon 显示的 token"
minicode-client --workspace C:\path\to\projects\repo
```
Daemon 只接受启动时 `--allowed-root` 内的工作区。不同客户端可以订阅同一个 session 的事件,并由另一个客户端处理待审批操作。
## MCP stdio
参考 [mcp.example.json](mcp.example.json) 配置 Server:
```powershell
minicode-daemon `
--allowed-root C:\path\to\projects `
--mcp-config .\mcp.example.json
```
MCP 工具会以 `mcp_<server_id>__<tool_name>` 注册。第三方 MCP Server 的只读声明不被默认信任,因此当前版本所有 MCP 工具都需要一次性审批。
## Skills 渐进式加载
Skill 放在工作区根目录的 `.minicode/skills/<skill-name>/SKILL.md`。格式示例见 [examples/skills](examples/skills):
```markdown
---
name: python-testing
description: Run focused Python tests before claiming success.
triggers: pytest, coverage, 测试
---
# Instructions
...
```
启动时只读取 frontmatter 元数据。用户任务与 trigger/description 匹配后,才读取并注入对应正文。Skill 名称、元数据长度、文件大小和真实解析路径均有限制;指向可信 Skill 根目录之外的链接不会加载。
## 上下文压缩与统计
设置估算上下文预算:
```powershell
$env:MINICODE_TOKEN_BUDGET = "12000"
```
压缩遵守以下边界:
- 数据库中的原始消息不删除、不覆盖;
- 当前 run 从最新用户指令开始的轨迹全部原样保留;
- assistant tool calls 与 tool results 必须严格一一对应;
- 等待审批期间禁止同一 session 开启第二个 run;
- 只对更早的已完成消息生成确定性事实记录;
- 事件字段明确标记为 `estimated` 和 `heuristic_v1`,不冒充供应商账单 Token。
- 如果当前任务本身超过预算,报告 `within_budget=false`,但不会为了满足数字而删除当前指令。
运行确定性对照实验:
```powershell
python scripts/benchmark_context.py --turns 30 --budget 4000
```
接入真实模型后,应优先采用 Provider 返回的 prompt/completion usage;启发式估算只作为不提供 usage 时的回退口径。
## 子 Agent 隔离执行
父 Agent 可以通过 `delegate_tasks` 一次委派最多 4 个相互独立的调查任务:
```json
{
"tasks": [
{"task_id": "tests", "instruction": "检查测试结构和失败风险"},
{"task_id": "api", "instruction": "检查 API 调用链"}
]
}
```
隔离边界:
- 每个子 Agent 使用独立 session、run、trace 和模型客户端;
- 子 Agent 看不到父会话历史,只接收明确下发的 task/context;
- 子 Agent 工具是严格白名单:只有 `read_file` 和 `list_files`;
- 子 Agent 不能写文件、执行 Shell、调用 MCP 或递归创建子 Agent;
- 全局并发上限默认为 3,不是每个父任务各自 3;
- 返回顺序始终与提交顺序一致,单个子任务失败不会隐藏其他成功结果;
- 父会话只接收结构化最终结果,子 Agent 的中间轨迹保存在各自 session;
- 父事件包含 delegation、parent invocation、child session/run/trace 和耗时关联字段。
子 Agent 现在运行在独立 Python 进程中。deadline 到达后先发送协作式取消;宽限期内未退出则回收整个进程树。超时强杀返回 `execution_state=unknown`,不会把无法确认的外部请求描述成确定完成。全局并发上限适用于单个 Daemon/CLI 实例;多个独立 Daemon 各自拥有调度额度。
## 核心状态流
```text
user message committed
↓
model streaming → text deltas / tool-call deltas
↓
assistant message committed
↓
safe read tool ──────────────→ execute → tool result
│
write/shell tool
↓
persist awaiting_approval → return control to client
↓
approve/reject → persist decision → execute or deny
↓
tool result committed → next model turn → completed
```
重要不变量:
1. 工具参数只有在完整流结束并解析为 JSON object 后才可能执行;
2. 未批准的副作用工具执行次数为零;
3. 同一 run 内的同一 `tool_call_id` 最多执行一次;
4. 文件工具对工作区之外的路径读写会被拒绝;Shell 本身不是文件沙箱,必须审批且不会继承 API Key/Daemon Token;
5. 审批状态先持久化,再把审批事件交给客户端。
## 当前验证结果
- Python 3.11 下完整回归:105 passed,0 failed,0 skipped;
- 语句覆盖率:80%;CLI 78%、Client 53%、Daemon 68%。覆盖率是工程基线,不等同于“无缺陷”或强鲁棒性证明;
- Qwen2.5-1.5B-Instruct + vLLM 0.7.3 固定 3 项只读任务:工具序列、工具结果覆盖和最终答案均为 3/3;
- 其中 1/3 请求因 vLLM Hermes 流式工具参数不完整而在任何工具执行前安全回退到一次非流式请求。
- MCP stdio 真实模型固定评测:工具发现、审批、exact-once 调用和工具结果均为 3/3;无矛盾最终答案为 1/3,说明 1.5B 模型可能在拿到正确工具结果后产生自相矛盾的解释。
- 写入权限真实模型评测:批准、拒绝、等待审批取消三种场景均保持审批前零写入;批准后内容精确匹配,拒绝与取消后目标文件均不存在。
- TCP Daemon 运行时重建评测:待审批 run、session/run/approval ID 和事件回放均成功恢复,重建后批准只写入一次;当前验证的是同一评测进程内完整销毁并重建运行时,不是 OS 强杀测试。
- 独立 Daemon 子进程异常退出评测:不同 PID 间成功恢复待审批 run 和事件序列,批准后精确写入一次且重复批准被拒绝。测试位于审批前零副作用边界,不外推到执行中副作用的回滚。
- 进程隔离 Sub-Agent 真实模型评测:父工具序列、子进程完成、独立 child session、证据传递和父最终答案均为 3/3;三次均使用了执行前安全非流式回退。
- 双 Sub-Agent 真实并发评测:并发时间重叠、独立 session、提交顺序返回、双份证据和父答案连续 3/3;并发重叠不等同于单 GPU 推理获得线性加速。
- 执行中故障注入:外部副作用已开始而结果未落库时强杀 worker,恢复后 invocation=`execution_unknown`、run 失败关闭、无工具结果伪造且不自动重放。
- 受控 Shell 真实模型评测:批准、拒绝、取消均通过,批准输出正确且父进程测试秘密未泄漏,三种场景工作区均未改变。
- 多 Sub-Agent 部分失败评测:成功 sibling 保留和 timeout 隔离均为 3/3;严格成功为 0/3,因为 1.5B 将指定 task_id `success/timeout` 改写成 `task1/task2`。
真实模型评测详情见 [docs/live_model_evaluation.md](docs/live_model_evaluation.md)。当前小样本已覆盖读取、检索、写入审批、受控 Shell、fake stdio MCP、单/双 Sub-Agent、部分失败、Daemon 恢复和 execution_unknown;仍不代表任意外部系统的事务回滚能力。
面试或录屏可按 [五分钟演示流程](docs/demo_walkthrough.md) 依次展示离线 Agent Loop、真实模型工具调用、审批、MCP、Sub-Agent 和崩溃恢复。
架构与设计边界见 [项目架构](docs/project_architecture.md),可直接用于简历的证据支持版描述见 [简历项目描述](docs/resume_project_final.md)。
最终缺陷与发布边界见 [最终审计](docs/final_audit.md),所有可引用数字见 [指标与证据清单](docs/metrics_evidence.md)。
## 运行取消语义
Daemon 暴露 `run.cancel`,交互客户端可使用 `/cancel <run_id>`。取消请求会写入 SQLite;若 Daemon 在执行线程观察请求前重启,恢复流程仍会把该 run 收敛为 `cancelled`。
这是协作式取消,不是 Python 线程强制终止:
- 尚未开始的工具不会在观察到取消后执行;
- 流式模型会在下一条 delta 或模型返回时观察取消;
- 已经进入的模型请求或工具调用要等其返回或自身超时;
- 已经发生的文件写入、Shell 或外部副作用无法回滚;
- 等待审批的 run 可立即取消,同时审批和 invocation 会标为 `cancelled`。
## 后续里程碑
- 提升 CLI/Daemon 边缘路径测试覆盖率,并整理可复现演示与简历指标。
## 代码仓库混合检索
`search_code` 工具会增量扫描当前 workspace,并组合三类信号:
- Python AST 函数、异步函数和类符号;
- 路径、符号及代码正文的关键词/IDF 得分;
- 无外部依赖的稳定 Hash 向量余弦相似度。
结果包含文件路径、起止行号、符号、代码类型、各分项得分和预览。`.git`、`.minicode`、虚拟环境、构建目录、大文件及越界链接默认不会进入索引。
运行确定性检索基准:
```powershell
python scripts/benchmark_code_search.py
```
该脚本使用合成代码库验证 Recall@1、MRR@5 和检索延迟;正式项目指标仍需在固定真实仓库和人工标注查询集上报告。
## Agent 轨迹评测
轨迹评测不仅检查最终文本,还检查:
- run 最终状态;
- 工具选择与调用顺序;
- 审批是否按预期触发;
- 每个 tool call 是否有对应结果;
- 是否调用禁止工具;
- 工具调用次数是否超过预算。
运行离线确定性评测:
```powershell
python scripts/evaluate_agent_traces.py
```
当前脚本覆盖直接回答、安全读取、批准写入、拒绝写入和非完整模型响应。它验证的是运行时不变量,不代表真实模型任务能力。
## 运行要求与恢复语义
- Python 3.10 或更高版本;当前验证环境为 Python 3.11。
- 同一个 state 目录只应由一个 Daemon 实例管理。
- Client 断开不会取消已经提交的 Agent run;任务继续运行,其状态可由重新连接的客户端读取。
- Daemon/CLI 重启时,遗留的 `ready/streaming/executing` 状态会失败关闭;仍处于 `pending` 的人工审批会保留。
- 实际工具已经开始但结果未持久化时标记为 `execution_unknown`,不会自动重放副作用。