Metadata-Version: 2.4
Name: damnatiox-agent
Version: 0.1.1
Summary: A terminal-first Python Agent with tools, RAG, validation and session context.
Author: jame100101
Project-URL: Repository, https://github.com/jame100101/agent_learning
Project-URL: Issues, https://github.com/jame100101/agent_learning/issues
Keywords: agent,cli,deepseek,rag,tools,tui
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.14
Description-Content-Type: text/markdown
Requires-Dist: numpy<3,>=2.5.1
Requires-Dist: openai<3,>=2.47
Requires-Dist: prompt-toolkit<4,>=3.0.52
Requires-Dist: PyYAML<7,>=6.0.3
Requires-Dist: rich<16,>=15
Requires-Dist: sentence-transformers<6,>=5.6
Provides-Extra: dev
Requires-Dist: build<2,>=1.3; extra == "dev"
Requires-Dist: pytest<10,>=9.1; extra == "dev"
Requires-Dist: ruff<0.16,>=0.15; extra == "dev"
Requires-Dist: twine<7,>=6; extra == "dev"

<div align="center">
  <h1>DX · DamnatioX Agent</h1>
  <p><strong>终端优先的 Python Agent：RAG、Tools、Coding Harness、Skills、上下文压缩与回答校验。</strong></p>
  <p>它是一个非常暴躁的 agent · 测试版本，Agent 链路和边界判断仍在完善</p>

  <p>
    <a href="https://pypi.org/project/damnatiox-agent/"><img src="https://img.shields.io/pypi/v/damnatiox-agent?logo=pypi&label=PyPI" alt="PyPI version"></a>
    <a href="https://pypi.org/project/damnatiox-agent/"><img src="https://img.shields.io/pypi/pyversions/damnatiox-agent?logo=python" alt="Python versions"></a>
    <a href="https://github.com/jame100101/agent_learning/actions/workflows/ci.yml"><img src="https://github.com/jame100101/agent_learning/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
    <a href="https://pypi.org/project/damnatiox-agent/"><img src="https://img.shields.io/pypi/dm/damnatiox-agent?label=downloads" alt="PyPI downloads"></a>
  </p>

  <p>
    <a href="#安装与首次启动">⚡ Quick Start</a> |
    <a href="#完整运行链路">🧠 Architecture</a> |
    <a href="#工具调用">🛠 Tools</a> |
    <a href="#skills">🧩 Skills</a> |
    <a href="#打包github-actions-与-pypi-发布">📦 Release</a>
  </p>

  <p>
    <img src="https://img.shields.io/badge/DeepSeek-V4-f97316" alt="DeepSeek V4">
    <img src="https://img.shields.io/badge/RAG-Evidence-2563eb" alt="RAG Evidence">
    <img src="https://img.shields.io/badge/Tool-Calling-0891b2" alt="Tool Calling">
    <img src="https://img.shields.io/badge/Coding-Agent-7c3aed" alt="Coding Agent">
    <img src="https://img.shields.io/badge/TUI-prompt--toolkit-374151" alt="prompt-toolkit TUI">
  </p>
</div>

---

## 整体架构

当前实现以 `AgentChain` 为单轮编排入口，以 prompt-toolkit 全屏布局和 Rich
命令渲染组成 `DamnatioX Agent` 终端前端。会话历史、当前轮执行状态、工具
结果和事实证据分别存储，历史工具结果不会直接成为下一轮事实依据。

## 安装与首次启动

DamnatioX 以 `damnatiox-agent` 作为 Python 分发名，以 `damnatiox` 作为终端
命令。当前代码使用 Python 3.14 语法：

```powershell
pipx install damnatiox-agent
damnatiox
```

需要显式指定解释器时：

```powershell
pipx install --python C:\Python314\python.exe damnatiox-agent
```

从源码开发或验证：

```powershell
py -3.14 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
.\.venv\Scripts\damnatiox.exe
```

### PyPI 安装包与知识库样例

结论：通过 PyPI 或 `pipx` 安装时，`data/` 中的知识库样例会随 wheel 一起下载。
已核验 PyPI `0.1.0`，安装包包含以下只读资源：

| 内容 | Wheel 内位置 | 是否随安装下载 |
|---|---|---|
| 知识库样例 | `damnatiox_agent/resources/data/*.md` | 是 |
| 默认分块 | `damnatiox_agent/resources/vector_store/chunks.json` | 是 |
| 默认向量 | `damnatiox_agent/resources/vector_store/embeddings.npy` | 是 |
| 用户 API Key | `~/.damnatiox/config.json` | 否，本机首次启动时创建 |
| 会话和模型偏好 | 工作区 `.damnatiox/` | 否，本机运行时创建 |
| 独立计算器样例脚本 | `calculator.py` | `0.1.1` 起移除 |

运行时优先使用当前工作区已有的 `vector_store/`；工作区没有索引时读取 wheel
内置的样例索引。PyPI 安装方式见上方 Quick Start。

首次启动凭据链路如下。DeepSeek 地址固定为 `https://api.deepseek.com`，界面只
收集 API Key：

```mermaid
flowchart TD
    A["执行 damnatiox"] --> B{"DEEPSEEK_API_KEY 是否存在"}
    B -->|"是"| F["创建 DeepSeek Client"]
    B -->|"否"| C["读取 ~/.damnatiox/config.json"]
    C --> D{"api_key 是否存在"}
    D -->|"是"| F
    D -->|"否"| E["在 TUI 密码输入框中填写并原子保存"]
    E --> F
    F --> G["加载 AgentChain 并启动全屏 TUI"]
```

`DEEPSEEK_API_KEY` 适合临时运行和自动化，不写入配置文件；交互输入保存到用户
目录的 `~/.damnatiox/config.json`。项目的 `.gitignore` 排除了该目录、旧版
`config.py` 和 `.env*`，API Key 也不会写入日志或构建产物。

## 完整运行链路

```mermaid
flowchart TD
    UI["DamnatioX TUI：输入、状态、工具卡片、回答"] --> A["用户输入"]
    A --> B["创建 TurnState"]
    S["SessionState：摘要、最近对话、未完成任务、用户约束"] --> C
    SK["SkillManager：元数据目录、显式选择、按需正文"] --> C
    B --> C["Input Context Builder"]
    C --> D["Router：chat / rag / tools / research"]

    D -->|"chat"| X["Answer Context Builder"]
    D -->|"rag / tools"| E{"是否复杂任务"}
    D -->|"research"| F["Planner"]

    E -->|"否"| G["Tool Selector：选择一个或多个工具"]
    E -->|"是"| F

    F --> H["生成 PlanStep 和完成条件"]
    G --> H
    H --> I{"Loop Guard：模型轮次、重试和重规划预算"}

    I -->|"允许执行"| JB["Tool Batch Scheduler：校验、指纹、缓存和能力策略"]
    I -->|"达到预算"| X

    JB --> JC{"是否包含写入或独占屏障"}
    JC -->|"否"| JD["独立批次：parallel_safe 并发，否则顺序执行"]
    JC -->|"是"| JE["连续独立段内并发，写入和命令逐项执行"]
    JD --> K["RAG / Search / DB / File / Browser / Coding / PowerShell"]
    JE --> K
    K --> L["按原 tool_call 顺序提交 ToolResult 到 TurnState"]
    L --> M["Tool Failure Policy"]

    M -->|"success / partial"| N["Current-turn Evidence Registry"]
    M -->|"retryable error"| I
    M -->|"empty / fatal / repeated"| O{"是否选择其他工具"}
    O -->|"是"| F
    O -->|"否"| X

    N --> P["证据去重、过滤、重排和预算裁剪"]
    P --> X

    X --> Q["构建回答上下文"]
    Q --> R["生成 Draft"]
    R --> T["格式与确定性校验"]

    T -->|"格式问题"| R
    T -->|"通过"| U["事实与引用校验"]

    U -->|"需要补充证据"| V{"仍有重规划预算"}
    V -->|"是"| F
    V -->|"否"| W["基于现有证据收敛回答"]

    U -->|"仅回答内容问题"| R
    U -->|"通过"| Y["最终回答"]
    W --> Y

    Y --> Z["Session Memory Writer"]
    Z --> AA["生成精简 TurnRecord"]
    AA --> AB["更新 SessionState"]
    AB --> AC{"上下文是否超过预算"}
    AC -->|"是"| AD["更新 SessionSummary 并裁剪旧 TurnRecord"]
    AC -->|"否"| AE["等待下一次用户输入"]
    AD --> AE
```

### 链路分段说明

1. **启动阶段**
   - 从环境变量或 `~/.damnatiox/config.json` 解析 API Key；首次使用时直接在
     prompt-toolkit 密码输入框完成配置。
   - 使用固定 DeepSeek API 地址创建兼容 Client，然后绘制 DamnatioX 首帧。
   - 加载 `vector_store/`；索引缺失时从 `data/` 构建。
   - 扫描项目和用户 Skill 目录，只登记通过校验的 `SKILL.md`。
   - 创建进程级 `SessionContext`、`SkillManager`、`ToolExecutor` 和
     `AgentChain`。

2. **Input Context 与 Router**
   - 每次输入创建独立 `TurnState` 和 `TurnRagContext`。
   - Input Context Builder 只加入结构化摘要、最近对话和当前输入。
   - `/skills` 选中的 Skill 只在当前请求上下文中披露完整正文；未选 Skill
     只保留名称和说明，不进入模型 Prompt。
   - Router 使用严格 JSON 返回 `chat / rag / tools / research`、复杂度、置信度、
     原因和建议工具；连续解析失败时使用确定性规则回退。
   - `rag` 只代表“应该尝试知识库”。随后真实执行一次轻量检索，由
     RAG Coverage Gate 根据空结果、错误和最低相关分判断知识库是否收录。

3. **计划和执行阶段**
   - `chat` 直接进入回答上下文；简单 `rag/tools` 使用单步计划。
   - `research` 和复杂任务调用严格结构化 Planner，生成有序 `PlanStep` 描述、
     完成条件和工具白名单；当前执行器合并所有步骤的工具名作为本轮全局
     allowlist，尚未维护逐步推进的 step cursor。该 allowlist 既过滤传给模型的
     Tool Schema，也在 ToolExecutor 执行前再次强制检查。
   - 回答模型可在一次响应中给出多个互不依赖的读取调用；Scheduler 把混合调用
     切成连续独立段和写入/命令屏障。段内只有全部工具声明 `parallel_safe` 时才
     使用最多 4 个 worker；RAG 等只读但未声明线程安全的工具顺序执行，同时仍
     保留同批其他独立查询的结果。
   - Loop Guard 默认以模型轮次、可重试错误和重新规划次数收敛链路，不再用固定
     20 秒 API 超时中断已经成功的工具任务。
   - Search、SQLite、File、Browser 和 Python Code 已与 RAG、Calculator 一起
     注册到现有 ToolExecutor。
   - Coding 请求继续复用同一个执行入口，可组合 Glob、Grep、Read、Write、
     Edit、受约束 Command、结构化只读 PowerShell 和 Python Interpreter；
     MCP 继续保留为后续扩展槽位。

4. **Tool Executor 和 Failure Policy**
   - 所有工具先在主线程完成注册检查、JSON 参数校验、规范化参数指纹、单轮缓存
     和同批 single-flight 去重；worker 只运行工具函数，不修改 `TurnState`。
   - 纯计算、Search、静态 Browser、SQLite、File/Glob/Grep 和结构化只读
     PowerShell 可受控并发；RAG、写入、编辑、Command 和未知工具默认独占。
   - 批次完成后严格按模型原始 `tool_call` 顺序登记 Evidence 和 ToolResult，
     因此并发完成顺序不会改变 `E1/E2`、消息顺序或 workspace revision；写入
     屏障成功后才准备后续读取，从而避免旧 revision 的 cache/single-flight 污染。
   - 进程工具随后进入 `tool/sandbox.py` 的命令白名单、工作区路径、精简环境、
     非交互 stdin、超时和输出预算检查。
   - 所有执行结果统一转换为 `ToolResult`，状态为 `success`、`partial`、
     `empty`、`retryable_error`、`fatal_error` 或 `repeated`。
   - 独立段中的失败彼此隔离：成功的兄弟调用继续保留；全独立批次只有全部失败
     时才聚合失败上下文。若后面还有写入或命令屏障，任一前置读取失败都会先把
     控制权交还模型，避免在不完整输入上执行副作用。屏障自身失败也会停止后续
     副作用，但仍为每个原始 `tool_call_id` 生成 `TOOL_CALL_SKIPPED` 结果。
   - single-flight/cache 副本复用首个相同指纹的失败决策，一次物理失败只消耗
     一次重试预算；单个模型响应最多执行 16 个工具调用，超出的调用同样生成
     可观测的 skipped 结果。
   - 成功、部分成功和空的可缓存只读结果可在同轮复用；瞬时失败释放相同参数
     指纹供受预算控制的重试。RAG 继续复用原有查询缓存和最多 3 次实际检索限制。
   - `execution_ms`、物理 `batch_wall_ms/batch_size/parallel_width`、模型响应级
     `logical_batch_wall_ms/logical_batch_size`、`cache_hit` 和
     `single_flight_hit` 写入结果元数据，便于后续基准测试。

5. **Evidence 和回答阶段**
   - 任何携带非空 Evidence 的工具结果都写入仅属于当前 `turn_id` 的 Registry；
     失败状态也可因此保留可观测的进程信息。
   - Evidence Registry 分配 `E1` 等引用编号，完成去重、分数过滤、排序和字符
     预算裁剪，并为最近的编辑与验证结果分别预留项目数和字符份额。
   - Answer Context Builder 使用会话摘要和最近对话理解意图，但只把当前轮
     Evidence 作为工具及知识库事实依据。
   - 工具循环中的即时结果通过 `role=tool` 结构化 JSON 直接交给下一次模型调用；
     消息保留 `data` 和紧凑 Evidence 引用，Evidence 正文只在当前轮 Registry
     保存，避免同一大段工具输出在一条消息内出现两次。
   - Coding 路线还会动态注入当前工作目录、Git 分支、最近提交和工作区变更
     概览；相同 `workspace_revision` 的回答修复循环复用一次快照，工作区变化后
     才重新读取 Git 状态。

6. **校验和会话写回**
   - 候选回答依次经过精确输出、JSON、空内容和长度等确定性检查。
   - 所有用户输入（包括完整问候语）至少经过 LLM Router 和回答模型，不再按问候
     文本设置本地特例。
   - 简单 `chat` 在确定性格式检查通过后直接收敛；复杂 `chat`、RAG、工具和
     Research 继续进入通用质量 Validator，避免对短问题固定增加评价器循环。
   - 通用质量 Validator 使用隔离后的当前轮证据上下文。
   - Grounding Validator 逐项检查事实断言和 `[E1]` 引用；缺少证据时可在预算
     内补充检索，否则生成明确说明证据不足的收敛回答。
   - 最终回答通过后才生成精简 `TurnRecord`；上下文估算达到 700,000 tokens
     时调用 LLM 更新结构化 `SessionSummary`，并尽量压缩到 500,000 tokens。

## 当前已知状态与问题

下表记录第二至第四阶段完成后的实际状态。

| 环节 | 状态 | 当前表现与后续处理方向 |
|---|---|---|
| 四分类 Router | 已实现 | 严格解析 JSON，返回置信度、复杂度、原因和建议工具，并具有确定性回退。 |
| 知识库覆盖判断 | 已实现基础版 | `rag` 路线执行真实检索后，按错误、空结果和默认 `0.5` 分数阈值判断覆盖；阈值仍需用正式评估集校准。 |
| 统一工具结果 | 已实现 | RAG 和普通工具都返回 `ToolResult`，失败、空结果和重复调用具有明确状态。 |
| 当前轮 Evidence 隔离 | 已实现 | Validator 只接收当前 `turn_id` 的 Evidence；历史对话只用于理解意图。 |
| 引用和事实校验 | 已实现基础版 | 本地检查引用编号，LLM 逐项输出 claim 支撑关系；仍需扩大事实校验回归集。 |
| Planner | 已实现基础版 | 复杂任务可生成最多 6 个有序步骤描述；当前使用全步骤工具并集作为 allowlist，逐步推进、PlanStep DAG 和多 Agent Researcher 仍在后续阶段。 |
| Tool Batch Scheduler | 已实现受控并发版 | 连续独立段有界并发、非线程安全读取顺序执行、写入与未知工具作为失败屏障、结果顺序提交、single-flight、同轮缓存和批次级单次重规划。 |
| Coding Agent | 已实现增强版 | 已具备并行只读定位、Glob、Grep、按行读取、原子写入、唯一文本编辑、受约束 argv 命令、项目脚本验证和结构化只读 PowerShell。 |
| Skills | 已实现显式选择版 | 支持多目录发现、安全 YAML 校验、最多 5 个启用项、渐进正文披露、工具名交集和 `/skills` 选择。 |
| DamnatioX TUI | 已实现全屏版 | 固定输入栏、完整持久化会话历史、稳定滚轮浏览、模型/effort 选择浮层、显式思考显示开关、工具活动、时间统计和真实流式回答。 |
| 工具覆盖范围 | 已实现首版 | 已注册 RAG、网页搜索、SQLite、文件与 Coding、静态网页读取、Python 执行、计算器和文本长度工具；Browser 暂不执行 JavaScript。 |

### 本轮链路评估与优化依据

本轮没有把整条链路替换成另一套框架，而是针对实际热路径做局部优化：

| 观察点 | 修改前 | 当前处理 | 仍保留的边界 |
|---|---|---|---|
| 同一模型响应中的多个工具 | 逐个串行 | 按 capability 切成独立段与副作用屏障，段内有界并发 | 只并发明确声明安全的连续独立调用 |
| 工具线程与共享状态 | 执行和提交耦合 | `prepare → run → ordered commit` 两阶段 | `AgentChain` 本身仍是单会话单轮执行器 |
| 同参数重复读取 | 直接返回 `repeated` | 成功/空只读结果同轮缓存，批内 single-flight | 写入、命令和未知工具保留重复保护 |
| 批次失败 | 每个失败都可能重新规划 | 相同物理失败只计一次预算；保留成功兄弟结果；前置读取或屏障失败时跳过后续副作用 | Planner 尚未形成带依赖边的 DAG |
| 回答上下文工作区状态 | 每次修复读取三次 Git | 按 `workspace_revision` 复用快照 | 外部进程绕过工具改文件时需下一轮刷新 |
| 即时 Tool Message | `data` 和 Evidence 正文重复 | `data` + Evidence ID/URI 紧凑索引 | Validator 仍从 Registry 读取完整正文 |
| 普通短请求 | 固定 Prompt 偏长且总进入评价器 | System Prompt 本地估算约 247 tokens；简单 chat 只保留 Router、回答模型和确定性检查 | 复杂任务与带证据任务仍保留独立质量/事实校验 |

简单与复杂任务现在采用同一个 LLM Router，不使用文本关键词为问候建立旁路。
Router 返回 `complex_task=false` 的 `chat` 时，主链路执行一次回答生成和确定性
格式门后结束；`complex_task=true`、`research`、RAG 和工具路线继续使用 Planner、
工具反馈、质量评价和证据校验。该分层遵循“先用最简单可行流程，只有在任务确实
需要时再增加 Agent 循环”的原则，同时保留复杂编码与多来源研究的规划入口。

实现策略与以下公开实现相符：

- [AI Agent Book Coding Agent](https://bojieli.github.io/ai-agent-book/book/chapter5/)
  给出 Code Interpreter、Shell、Read、Write、Edit、Glob、Grep 的极简工具集，
  并强调用测试、类型系统和版本控制形成 Harness 反馈。
- [Codex API 的类型化请求接口](https://github.com/openai/codex/blob/main/codex-rs/codex-api/README.md)
  在 Responses 请求中保留 `parallel_tool_calls`，并把工具、推理和流事件放入
  统一协议层。
- [Claude 并行 Tool Use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use)
  采用同一 assistant 消息发出多个调用、随后返回对应结果的批次结构。
- [Hermes Agent Loop](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/developer-guide/agent-loop.md)
  对多工具使用 `ThreadPoolExecutor`，交互型工具保持串行，并按原调用顺序
  重新插入结果。

因此当前并发单元是“同一次模型响应中的独立工具调用”，不是多轮 Prompt、
PlanStep 或多个会话同时写入一个 `TurnState`。这种边界先解决可测量的工具等待
时间，同时保持 Evidence ID、工具消息和 Coding 工作区写入顺序稳定。

### 本轮冗余检查

本轮移除了几条已经退出主链路的旧路径：

- 删除旧三分类 `router_classify()`，统一使用四分类 `route_request()`。
- 删除 `systemprompt.py` 中旧 Router 模板和旧 RAG 字符串拼接模板。
- 删除模块级 `_vectorstore`、`set_vectorstore()` 和旧字符串版
  `search_knowledge_base()`；RAG 继续由 ToolExecutor 专用适配器执行。
- `rag/__init__.py` 改用延迟导出，保留原公开导入方式，同时让普通链路测试
  跳过提前加载 SentenceTransformer。
- 清理 RAG Pipeline、Embedding 和 API 冒烟脚本中的未使用 import。
- 精简通用 Validator 的消息快照，只处理当前隔离上下文实际传入的字典消息。

Router、Planner、ToolExecutor、Evidence、三层答案校验和会话写回顺序保持原样。

### 集中式提示词

所有静态模型提示词和动态消息模板现在集中在 `systemprompt.py`。Router、Planner、
回答上下文、摘要器、质量 Validator、Grounding Validator 和回答修复模块只导入
各自需要的常量，业务模块不再维护独立提示词副本。`systemprompt` 小写名称继续
作为 `SYSTEM_PROMPT` 的兼容别名。

主回答提示包含 DamnatioX 的暴躁、嘴臭但心软角色口吻；Router、Planner、摘要和
Validator 使用各自的纯结构化提示，避免人格文字污染 JSON。主提示仍要求 JSON、
精确文本和用户指定语气优先，当前基础 System Prompt 本地估算约 247 tokens。

## DamnatioX Agent TUI

首次创建源码开发环境：

```powershell
py -3.14 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
```

`pyproject.toml` 声明运行依赖、`damnatiox` console script 和 `dev` 依赖组，
因此新环境安装后即可走格式化、静态检查、测试和构建入口。

运行入口：

```powershell
.\.venv\Scripts\damnatiox.exe
```

TUI 是 `AgentChain` 的独立前端层。它负责全屏终端展示、底部 Composer、
输入队列和本地 Slash Commands；Router、Planner、工具执行、Evidence 和
Validator 仍由原链路负责。前端与链路之间只增加单向 `StreamEvent`，没有改变
现有工具、RAG 和校验顺序：

```text
prompt-toolkit full-screen TUI
    ├─ 初始化：自适应立体 DAMNATIOX AGENT、工具、Skill 和会话信息
    ├─ 介绍滚出视口后：固定单宽 DX 立体标识、性格标签、模型与工作区
    ├─ 上部：会话、思考过程、工具活动、流式回答
    ├─ 底部：多行 Composer、命令补全和运行状态
    └─ AgentChain.run_with_stream
         ├─ Router / Planner / Validator：同步 JSON
         ├─ ToolExecutor：结构化 ToolResult
         └─ 回答模型：reasoning_content / content 流式增量
```

| 命令 | 功能 |
|---|---|
| `/help` | 显示命令帮助 |
| `/status` | 显示模型、工作区、Git 和会话状态 |
| `/tools` | 显示全部已注册工具 |
| `/skills` | 显示带编号的 Skill 列表和当前启用状态 |
| `/skills <编号或名称>` | 启用或停用一个 Skill |
| `/skills off <名称>` | 停用指定 Skill；另支持 `clear` 和 `reload` |
| `/diff` | 查看当前 Git 工作区差异 |
| `/context` | 查看当前上下文估算、各层占用和自动压缩阈值 |
| `/compact` | 立即调用 LLM 生成结构化摘要并压缩当前会话 |
| `/sessions` | 列出当前项目保存的会话 |
| `/resume [session-id]` | 恢复指定会话；省略 ID 时恢复最近的其他会话 |
| `/model [v4pro|v4flash]` | 选择 DeepSeek V4 Pro/Flash；全屏模式省略参数时打开选择浮层 |
| `/effort [low|high|max]` | 选择官方 reasoning effort；省略参数时打开选择浮层 |
| `/thinking on`、`/thinking off` | 明确打开或关闭 TUI 思考流展示；模型 Thinking Mode 保持启用 |
| `/verbose` | 切换完整链路事件显示 |
| `/clear` | 清空终端显示并保留当前会话 |
| `/new` | 保存当前会话并创建新会话 |
| `/quit`、`/exit` | 结束程序 |

交互按键：

| 按键 | 功能 |
|---|---|
| `Enter` | 发送输入 |
| `Alt+Enter` | 在 Composer 内换行 |
| `PageUp`、`PageDown`、鼠标滚轮 | 浏览当前 Session 的全部已保存和本次运行历史 |
| `Ctrl+Home`、`Ctrl+End` | 跳到历史开头或回到最新输出 |
| `Ctrl+L` | 清空当前终端对话显示，保留 Session |
| `Ctrl+C` | 保存当前已完成轮次并立即结束程序 |
| `Ctrl+D` | 输入栏为空且 Agent 空闲时结束程序 |

Agent 工作期间仍可继续输入，后续内容进入当前进程的输入队列。底部状态栏持续
显示当前阶段、已运行时间、排队数量、思考开关和流式状态。手动滚动到历史区域
后，流式刷新会保留阅读位置并显示 `history paused`；回到底部后继续自动追踪
最新增量。启动或 `/resume` 时，归档轮次与最近轮次都会恢复到 transcript；滚轮
每个事件直接移动 3 行可见起点，同时用 transcript 光标锁定阅读位置。
因此第一个滚轮事件就会改变视口，刷新也会保留当前历史位置。完成后的 Markdown、
用户输入和思考文本会按终端宽度转成可滚动行。

从 PowerShell 直接续聊：

```powershell
# 恢复当前项目最近保存的会话
.\.venv\Scripts\python.exe .\main.py --continue

# 恢复指定 session ID
.\.venv\Scripts\python.exe .\main.py --resume session-xxxxxxxxxxxx
```

会话保存在项目的 `.damnatiox/sessions/`，模型偏好保存在
`.damnatiox/settings.json`，该目录已经加入 `.gitignore`。
持久化内容包括结构化摘要、最近轮次、归档轮次、上下文预算配置和最近一轮
API usage；载入会话时 System Prompt 始终使用当前代码版本。

当前上下文预算适用于 `deepseek-v4-pro` 和 `deepseek-v4-flash`：

| 预算 | 数值 | 用途 |
|---|---:|---|
| 模型上下文窗口 | 1,000,000 tokens | DeepSeek V4 Pro/Flash 官方范围 |
| 官方最大输出 | 384,000 tokens | 输入与输出共同占用 1,000,000 token 上下文 |
| Prompt ceiling 目标 | 840,000 tokens | 为输出、工具结果和本轮动态内容预留空间；当前用于预算观测，并非请求发送前的硬截断器 |
| 自动压缩触发点 | 700,000 tokens | 达到后自动摘要旧轮次 |
| 自动压缩目标 | 500,000 tokens | 一次压缩尽量回落到该值 |
| 最近轮次安全上限 | 200 | 极短对话场景的额外轮数保护 |
| 结构化摘要字符上限 | 32,000 | 控制摘要自身大小 |

`/context` 和自动压缩共用 `context/context_budget.py`。本地估算采用无需加载
Tokenizer 的混合近似：ASCII 约按 4 字符/token，中文等非 ASCII 字符约按
1 字符/token，再加入每条消息的轻量开销。它用于压缩阈值，不再把 UTF-8
字节数直接当作 token。

`context/token_usage.py` 统一包装 OpenAI 兼容客户端，并读取服务端响应的
`usage`。`/context` 会把两个概念分开显示：

- **Base context estimate**：下一轮会重复发送的 System Prompt、结构化摘要和
  最近会话记录的本地近似占用。
- **Last turn exact usage**：上一轮 Router、Planner、生成、Validator、压缩器等
  全部模型请求的服务端精确累计值。
- **Last request exact usage**：上一轮最后一次模型请求自身的精确 prompt、
  completion 和 total tokens。
- **Prompt cache**：服务端返回 cache hit/miss 时单独显示；没有该字段时不猜测。

此前仅输入“你好”时，`System 792` 来自 776 个 ASCII 字符加旧消息开销被按
逐字节计数，并不代表服务端 tokenizer 的真实结果。现在同一 System Prompt 的
本地估算约为 247 tokens；问候语与其他输入一样经过 LLM Router 和回答模型，
但简单 `chat` 不再额外调用质量评价器。`/context` 继续显示服务端精确 usage，
用于区分“当前上下文占用”和“一轮中多次模型调用的累计消耗”。

TUI 保持前后端分离：

- prompt-toolkit 使用 alternate screen、固定底部 Composer、滚动对话区、命令
  补全、历史建议、鼠标滚动和差分重绘。
- 初始界面用 `█` 与 `▓` 生成右下阴影的立体 `DAMNATIOX AGENT`，并列出
  模型、effort、工作区、工具、当前 Skill 和 Session。终端变窄时标题会拆分，
  较窄时收敛为立体 `DX` 与普通品牌名。
- 当启动介绍被后续对话完全推出视口后，顶部自动切换为三行固定栏。
  固定栏使用无阴影的加粗 `DX`，保持原有位置与高度，并在现有三行内显示
  “它是一个非常暴躁的agent”与“测试版本，agent链路和边界判断并未完善”。
- Composer 初始高度为一行，显式换行或内容按终端宽度折行时自动增长，最高六行。
- Rich 负责 `/context`、`/status`、`/diff` 等命令和最终 Markdown 的终端宽度
  感知渲染；系统消息渲染会先为 `◆ ` 前缀预留宽度。终端列数变化时，
  `before_render` 会重建 transcript；`/help`、`/status`、`/tools`、`/skills`、
  `/diff`、`/context` 和 `/sessions` 会以新列宽重新生成 Rich 表格，而不是把旧边框
  强制截断或二次换行。最终 Markdown 表格同样按新列宽重排。
- `reasoning_content` 和 `content` 分别产生 `thinking_delta` 与 `answer_delta`；
  工具调用分片在 `chain/streaming.py` 中重建后继续进入原 ToolExecutor。
- 思考标题使用紫色粗体，思考正文使用紫灰色斜体和左侧竖线；最终回答使用终端
  高对比浅色前景。链路完成后，最终 `TurnOutcome.answer` 会替换临时思考区，
  并以单宽 `└ Worked for` 显示总时间和实际输出流时间，避免 emoji
  字形回退导致的字符重叠。
- `/thinking off` 只过滤 TUI 的 `thinking_*` 事件；流重建仍保存
  `reasoning_content`，工具调用后的下一次请求可按 DeepSeek 协议完整回传。
  Router、Planner、Validator 等结构化调用始终保持非流式。
- `/model` 可切换 `deepseek-v4-pro` 与 `deepseek-v4-flash`；`/effort`
  支持官方 `low/high/max`。当前官方映射中 Pro 的 `low` 实际采用 `high`，
  `/status` 和选择表会同时显示 requested/effective 值。
- `/effort` 作用于启用 Thinking 的回答、工具循环收敛和回答修复请求；Router、
  Planner、结构化质量判断、Grounding Validator 与上下文压缩保持 Thinking disabled，
  以减少结构化控制阶段的延迟和输出波动。
- 详细 Router/Validator 事件继续由 `/verbose` 控制。
- `main.py` 只负责启动，依赖初始化位于 `tui/bootstrap.py`。
- OpenAI 兼容客户端不设置固定请求时限，SDK 对瞬时连接、限流和服务端状态错误
  最多自动重试 3 次；Agent 链路由模型步骤、工具错误、重规划和修复轮次收敛。
- 启动阶段只读取 RAG 索引；SentenceTransformer 和 BGE 模型推迟到第一次
  知识库检索时导入和加载，已缓存模型优先使用本地文件。
- 非 TTY、管道和重定向输入继续使用原有线性 Rich 界面。

设计参考：

- [AI Agent Book：Coding Agent 与代码生成](https://bojieli.github.io/ai-agent-book/book/chapter5/)
- [Anthropic：Building effective agents](https://www.anthropic.com/engineering/building-effective-agents)
- [DeepSeek Chat Completion usage](https://api-docs.deepseek.com/api/create-chat-completion)
- [DeepSeek Models & Pricing](https://api-docs.deepseek.com/quick_start/pricing/)
- [DeepSeek Thinking Mode 与流式 reasoning_content](https://api-docs.deepseek.com/guides/thinking_mode/)
- [DeepSeek 请求等待和 keep-alive](https://api-docs.deepseek.com/quick_start/rate_limit/)
- [Claude Code CLI reference](https://docs.anthropic.com/en/docs/claude-code/cli-usage)
- [Codex CLI slash commands](https://developers.openai.com/codex/cli/slash-commands)
- [Codex Skills](https://developers.openai.com/codex/skills)
- [Agent Skills specification](https://agentskills.io/specification)
- [Claude Code Skills](https://code.claude.com/docs/en/slash-commands)
- [Claude Code sandboxing](https://code.claude.com/docs/en/sandboxing)
- [Hermes Agent TUI](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/tui.md)
- [prompt-toolkit full-screen applications](https://python-prompt-toolkit.readthedocs.io/en/stable/pages/full_screen_apps.html)
- [OpenClaw TUI](https://docs.openclaw.ai/tui)
- [OpenClaw session compaction](https://docs.openclaw.ai/reference/session-management-compaction)
- [OpenClaw context breakdown](https://docs.openclaw.ai/concepts/context)
- [DeepSeek V4 models and context length](https://api-docs.deepseek.com/quick_start/pricing/)

## RAG 执行链路

`rag/rag_execution.py` 负责一条独立的 RAG 子链路：

1. 校验并规范化查询。
2. 使用 `规范化 query + top_k` 生成缓存键。
3. 查询当前用户轮次的缓存。
4. 缓存未命中时调用 `VectorStore.query()`。
5. 将结果整理成统一结构。
6. 将异常转换成结构化错误结果。

`ToolExecutor` 通过适配器调用该子链路，再把结果转换成统一 `ToolResult` 和
当前轮 `Evidence`。底层向量检索实现保持独立。

### 单轮缓存生命周期

- 每次读取一个新的用户 prompt 后创建一个 `TurnRagContext`。
- `rag` 路线的覆盖检索和本轮后续所有 RAG 工具调用共享该对象。
- 同一轮内，相同的规范化 query 和 `top_k` 直接复用缓存。
- 用户输入下一个 prompt 时创建新对象，上一轮缓存随之失效。
- 每轮最多执行 3 次实际向量检索；缓存命中不占用新的检索次数。

### RAG 返回结构

成功示例：

```json
{
  "ok": true,
  "query": "示例查询",
  "cached": false,
  "hits": [
    {
      "evidence_id": "example.md:12",
      "source": "example.md",
      "chunk_id": 12,
      "score": 0.836,
      "content": "检索到的文本"
    }
  ],
  "meta": {
    "top_k": 3,
    "duration_ms": 28
  }
}
```

失败示例：

```json
{
  "ok": false,
  "query": "示例查询",
  "cached": false,
  "hits": [],
  "error": {
    "code": "RAG_QUERY_FAILED",
    "message": "错误信息"
  },
  "meta": {
    "top_k": 3,
    "duration_ms": 1
  }
}
```

底层 `evidence_id` 用于描述原始片段；进入 Evidence Registry 后会重新分配
当前轮引用编号 `E1`、`E2`。引用编号只在当前 `turn_id` 内有效。

## 工具调用

| 工具名 | 功能 |
|---|---|
| `calculator` | 计算受限的基础算术表达式 |
| `get_text_length` | 计算字符串长度 |
| `search_knowledge_base` | 检索本地知识库 |
| `search_web` | 通过 DuckDuckGo HTML 搜索网页，返回去重后的标题、摘要和 URL |
| `query_sqlite` | 通过只读连接查询项目目录内的 SQLite 数据库 |
| `read_file` | 按行读取项目目录内的 UTF-8 文本文件 |
| `browse_web_page` | 读取 http/https 静态页面的标题和可见正文 |
| `execute_python` | 在临时目录中执行经过 AST 校验、仅暴露安全 builtins 与 `math` 的确定性 Python 代码 |
| `glob_files` | 按 Glob 模式浏览项目文件结构 |
| `grep_files` | 在项目文本文件中搜索字符串或正则表达式并返回行号 |
| `write_file` | 原子创建文件；覆盖已有文件时要求显式 `overwrite=true` |
| `replace_in_file` | 使用唯一 `old_text` 锚点执行确定性局部编辑 |
| `run_command` | 按 coding policy 白名单运行测试、编译、Ruff、只读 Git 或项目 Python 脚本 |
| `run_powershell` | 执行固定查询 cmdlet 和参数组成的结构化只读 PowerShell pipeline |

工具参数先经过 `validation/tool_validation.py`：

- 解析 JSON。
- 拒绝重复字段和非标准数值。
- 校验必填字段、额外字段、类型、枚举和长度等约束。
- 参数错误以对应工具结果返回给模型。

每个模型产生的 function `tool_call` 都对应一条 `role: "tool"` 消息。消息内容
统一包含工具名、状态、数据、Evidence、错误和元数据。

`calculator` 使用 Python AST 解析表达式，只执行声明支持的基础算术运算，
并限制表达式长度、节点数量、指数和结果范围。

新工具保持同一条执行路径：

```text
一个 assistant 消息中的 function calls
    → AgentChain 按 capability 切分连续独立段与副作用屏障
    → ToolExecutor：Schema 校验 / 参数指纹 / cache / single-flight
    → 独立段全部 parallel_safe：最多 4 个 worker 并发运行
      RAG 等独立但非线程安全的段：完整顺序运行并聚合失败
      Write / Edit / Command / unknown：逐项执行，失败后停止后续副作用
    → 主线程：按原 tool_call 顺序提交 ToolResult
    → Current-turn Evidence Registry
```

`ToolFunctionResult` 只负责让普通工具声明结构化数据、来源和引用要求；
Evidence ID 仍由 ToolExecutor 按当前 `turn_id` 分配。

并发策略定义在 `tool/tool_capabilities.py`。调度维度与失败维度彼此分离：
`parallel_safe` 决定线程池，`failure_barrier` 决定失败后是否阻断后续副作用，
`observes_workspace` 决定指纹是否包含当前 revision。未知工具默认
`effect="exclusive"`、`parallel_safe=False`、`cacheable=False`；新增工具只有在
实现本身不写共享状态、参数相互独立且结果可重复读取时，才显式开启并发。当前
`execute_python` 运行于独立受限进程，因此按纯计算工具处理；`run_command` 即使
执行只读子命令也保持独占，因为同一入口还承载测试、格式化和项目脚本，同时它
会观察 workspace revision，以便编辑后用相同命令重新测试。

首版工具边界：

- Search、Database、File、Browser 和 Coding 工具实现使用 Python 标准库；
  TUI 将 prompt-toolkit 和 Rich 作为显式运行依赖。
- Search 使用 DuckDuckGo HTML，无额外 Python 依赖；网络错误进入现有工具失败策略。
- SQLite 使用标准库 `sqlite3` 和只读 URI，最多返回 200 行。
- File 只读取项目目录内文件，单次最多 500 行、2,000,000 字节。
- Browser 读取静态 HTML、JSON 或纯文本，过滤脚本和样式，正文最多 20,000 字符。
- Code 使用 `sys.executable -I -c` 在临时目录执行，超时最多 10 秒，
  stdout 与 stderr 分别执行首尾保留的长度裁剪。
- Glob 和 Grep 默认跳过 `.git`、`.venv`、缓存、`node_modules` 和向量索引目录。
- Write 采用同目录临时文件加 `os.replace` 原子落盘；Python、JSON、TOML 写入后
  立即返回语法检查结果。
- Edit 要求 `old_text` 在目标文件中恰好出现一次，并返回统一 Diff 与新旧哈希。
- Command 使用参数数组和 `shell=False`，工作目录限制在项目内，超时最多 60 秒；
  只开放 Python `unittest/pytest/ruff/compileall`、项目内 `.py` 脚本、直接
  `ruff/pytest` 和只读 Git 子命令。
- PowerShell 只接受 `pipeline=[{"cmdlet": ..., "parameters": ...}]`，开放
  `Get-Location`、`Get-ChildItem`、`Get-Content`、`Select-String`、
  `Select-Object`、`Sort-Object`、`Measure-Object`、`Test-Path`、
  `Resolve-Path`、`Get-FileHash` 和 `ConvertTo-Json`。路径参数统一解析到
  项目目录，文本参数始终作为单引号 literal。
- 当前轮工作区维护轻量 `workspace_revision`；文件写入或编辑成功后，允许 Read、
  Glob、Grep、Command 和 PowerShell 使用相同参数复查新状态。可能写入工作区的
  测试、格式化、编译和项目脚本即使非零退出或超时也会推进 revision，因为失败
  前可能已经产生局部变更。
- `execute_python` 拒绝 import、文件入口、私有/栈帧反射和危险 builtins，只暴露
  受限内建函数及 `math`，并限制静态序列重复、`range` 数量和 256 MiB 进程内存；
  它与项目脚本使用不同执行策略。

### Coding 进程策略边界

`tool/sandbox.py` 是应用层 policy sandbox：

1. 拒绝 `cmd`、PowerShell、Bash、WSL 等通用 shell host 进入 `run_command`。
2. 拒绝 Python `-c`、任意模块、Git 写操作、Git `-C`、外部路径和未知程序。
3. 裸 Python 固定到当前解释器，Ruff/Pytest 固定到项目 `.venv`，Git 与
   PowerShell 拒绝解析到工作区内的同名程序；短选项附加路径也逐项校验。
4. 只使用校验后的 argv，固定 `shell=False` 和 `stdin=DEVNULL`。
5. File/Edit/PowerShell 路径会保护 `.git`、`.venv`、`.damnatiox`、
   `config.py`、`.env*` 和常见私钥/证书文件；Glob/Grep 同样跳过这些内容。
6. 子进程只继承 PATH、系统目录、临时目录、语言和编码等必要环境；API Key、
   代理和用户级 Python 包配置不进入子进程。
7. Windows 子进程先挂入带 `KILL_ON_JOB_CLOSE` 的 Job Object 再恢复运行；
   stdout/stderr 由独立线程持续排空，仅在内存中保留有界首尾内容，超时或父进程
   退出都会清理后台后代。POSIX 使用独立进程组执行同类清理。
8. 超时映射为 `retryable_error`，程序缺失映射为 `fatal_error`，非零退出保留为
   带 `COMMAND_NONZERO_EXIT` 原因的 `partial`，继续进入现有 Failure Policy。
9. Ruff 在用户参数前固定注入 `--isolated --no-cache`；只读 `check` 另加
   `--no-fix`。Pytest 同样在用户参数前注入空配置与 `no:cacheprovider`，并关闭
   外部插件自动加载，避免项目配置隐式改变执行行为。
10. Ruff/Pytest 拒绝 `--` 选项终止符；路径检查同时覆盖 Windows 盘符相对路径、
    当前盘根路径、UNC、用户目录和父目录穿越，固定强化参数不会退化成位置参数。

该层用于缩小模型可表达的命令面，并不等同于 Windows AppContainer、受限 Token
或虚拟机。白名单内的项目测试和项目脚本仍是项目代码；若后续需要硬隔离，再把
同一 `ToolExecutor` 入口连接到独立容器或 Windows 受限进程服务，Router 和主链路
保持不变。

### Coding Agent 最小循环

```mermaid
flowchart LR
    A["理解编码任务"] --> B["同批 Glob / Grep / Read 并行定位"]
    B --> C["补读存在依赖的上下文"]
    C --> PS["可选：结构化 PowerShell 只读查询"]
    PS --> D["Write 或唯一文本 Edit"]
    D --> E["即时 Syntax Feedback"]
    E -->|"通过"| F["受约束 Command 运行 Ruff / Compile / Tests"]
    E -->|"有问题"| C
    F -->|"失败"| B
    F -->|"通过"| G["基于 ToolResult 收敛回答"]
```

该循环没有引入新的编排器，而是复用当前 `Planner → Tool Batch Scheduler
→ ToolExecutor → ToolResult
→ Evidence → Validator` 路径。简单任务由模型按需裁剪步骤，复杂任务仍受原有
步数、重试和重新规划预算约束；写入、编辑和验证命令仍按依赖顺序执行。

## Skills

Skills 是对现有链路的工作流说明层，不是另一套 Agent Loop。`SkillManager`
扫描以下位置，后面的项目级定义覆盖同名用户级定义：

```text
~/.codex/skills/<name>/SKILL.md
~/.agents/skills/<name>/SKILL.md
<project>/.claude/skills/<name>/SKILL.md
<project>/.agents/skills/<name>/SKILL.md
```

`SKILL.md` 使用 YAML frontmatter：

```markdown
---
name: debug
description: 系统化复现、定位并修复代码缺陷。
allowed-tools: glob_files, grep_files, read_file, run_command
user-invocable: true
disable-model-invocation: false
---
# Debug workflow

1. 先复现。
2. 再定位和最小修改。
3. 最后执行针对性验证。
```

加载规则：

- 只扫描每个搜索根目录的直接子目录，要求 `name` 与目录名一致。
- 使用 `yaml.safe_load`，限制文件、frontmatter、正文、名称、说明和工具数量。
- 无效 Skill 单独记录为 load issue，不影响其他有效项。
- `/skills` 只展示元数据；启用后才把正文放进当前轮 system context。Router
  接收精简元数据，复杂任务 Planner 接收已选工作流正文；Router 服务异常时，
  `allowed-tools` 也会作为确定性 fallback 的工具提示。
- 最多同时启用 5 个 Skill；`allowed-tools` 只保留 ToolExecutor 已注册名称，
  它作为工作流提示，不绕过 Router、Planner、Schema 校验或进程 policy。
- Skill 中出现的命令在加载阶段只是文本；真实操作仍要经过 function call 和
  统一 ToolExecutor。

当前随项目提供 `debug`、`code-review` 和 `python-quality` 三个示例。选中状态
在当前 TUI 进程中持续生效，直到再次切换、执行 `/skills clear` 或结束进程；
Skill 正文不写入 `TurnRecord` 和会话摘要。

## 最终回答校验

最终回答进入会话历史前依次执行：

1. `validation/validation_pipeline.py` 检查空内容、长度、精确输出和 JSON 格式。
2. 简单 `chat` 在第 1 层通过后收敛；复杂 `chat`、RAG、工具与 Research 进入
   `validation/response_validation.py` 的通用质量检查。
3. 带当前轮 Evidence 的路线由 Grounding Validator 严格返回 claim、支撑状态
   和 `evidence_ids`；无 Evidence 的普通 chat 使用本地引用检查。
4. 引用编号在本地检查，未知引用和需要引用却缺失引用都会触发修复。
5. 缺少证据时，在重新规划预算内补充 RAG；预算结束后只输出现有证据可支持
   的内容并明确说明证据缺口。

所有校验和修复请求均关闭工具调用。

冗余检查后继续保留三层职责：

- 确定性校验处理精确文本、枚举和 JSON。
- 通用质量 Validator 处理要求覆盖和内部一致性。
- Grounding Validator 处理当前轮事实、来源和引用。

三层职责仍然保留，但按任务复杂度启用。精确输出（例如只返回 `1`、`2` 或 `3`）
始终由确定性层检查并在不符合时重新生成；评价器循环只用于有明确质量收益的复杂
回答，事实与引用评价只消费当前轮 Evidence。

编码工具已经成功创建或编辑文件，而独立回答 Validator 恰好用完本轮预算时，
链路会依据真实 `write_file` / `replace_in_file` 结果生成确定性完成说明：

- 只采用状态为 `success` / `partial` 且语法检查未失败的写入结果。
- 完成说明只包含真实路径、创建/更新/编辑状态和语法检查结果。
- 通过 `quality_validator/local_fallback` 事件保留 Validator 结束原因。
- 文件操作成功状态与最终说明校验状态分别处理，避免把已完成写入展示成链路失败。

## 文件结构

```text
main.py                   # 源码运行兼容入口
systemprompt.py           # 全部静态模型提示词和动态消息模板
pyproject.toml            # 包元数据、依赖、damnatiox 入口和 Ruff 配置
requirements.txt          # 当前 Python 3.14 开发环境兼容锁
.github/workflows/        # Push/PR CI 与 GitHub Release → PyPI
.agents/skills/           # 项目级 SKILL.md 工作流定义

damnatiox_agent/
├─ cli.py                 # 安装后的 console script 入口
├─ paths.py               # 工作区、用户状态和包内资源路径
└─ resources/             # Wheel 随附的默认 RAG 文档与向量索引

chain/
├─ agent_chain.py         # 完整单轮链路编排
├─ chain_models.py        # TurnState、ToolResult、PlanStep 等共享模型
├─ model_profile.py       # DeepSeek 模型目录、selector 和 effort 映射
├─ streaming.py           # reasoning、回答增量和工具调用流重建
├─ router.py              # 四分类 Router 和 RAG Coverage Gate
├─ planner.py             # 结构化复杂任务 Planner
├─ execution_policy.py    # Loop Guard 和 Tool Failure Policy
└─ evidence_registry.py   # 当前轮 Evidence 登记、去重、排序和裁剪

context/
├─ app_config.py          # ~/.damnatiox/config.json 凭据读写
├─ context_state.py       # SessionContext、SessionSummary、TurnRecord
├─ context_budget.py      # 模型窗口预算估算和 /context 快照
├─ token_usage.py         # API usage 精确采集和单轮聚合
├─ context_builder.py     # 输入上下文、Router 上下文和消息转换
├─ context_compression.py # LLM 结构化会话摘要压缩
├─ runtime_settings.py    # 独立于会话的模型偏好原子持久化
├─ session_store.py       # 项目本地会话保存、列表和恢复
├─ environment_context.py # 动态目录、Git 分支、提交与变更状态
└─ answer_context.py      # 回答上下文、工作区状态与隔离校验上下文

rag/
├─ document_loader.py   # 文档加载
├─ chunk.py             # 文本分块
├─ embedding.py         # 向量化
├─ retrieve.py          # 相似度检索
├─ vector_store.py      # VectorStore
├─ rag_pipeline.py      # 索引构建与查询入口
└─ rag_execution.py     # 单轮 RAG 缓存、执行和结构化结果

skill/
├─ models.py            # Skill 定义、来源、加载问题和异常
└─ manager.py           # 多目录发现、选择、重载和渐进上下文披露

tool/
├─ tools.py             # 全部工具 JSON Schema
├─ tools_function.py    # 普通工具函数映射
├─ tool_output.py       # 普通工具的结构化数据和来源协议
├─ local_tools.py       # File、SQLite 和 Python Code
├─ coding_tools.py      # Glob、Grep、Write、Edit 和 Command
├─ sandbox.py           # Coding command 白名单、环境和工作区策略
├─ powershell_tools.py  # 结构化只读 PowerShell pipeline
├─ process_runner.py    # 有界输出、超时和子进程树清理
├─ python_sandbox.py    # execute_python 的 AST 与 builtins 策略
├─ web_tools.py         # Search 和静态 Browser
├─ tool_capabilities.py # 并发、缓存和工作区副作用的保守策略
└─ tool_executor.py     # 批量调度、统一执行、顺序提交和结果适配

tui/
├─ app.py               # DamnatioX 交互循环和 Slash Commands
├─ bootstrap.py         # API、RAG、Session、ToolExecutor 初始化
├─ credential_setup.py  # 首次启动 TUI 密码输入和 API Key 解析
├─ fullscreen.py        # 全屏 Transcript、Composer、状态栏和流式事件
├─ welcome.py           # 自适应 DAMNATIOX AGENT 启动画面
├─ markdown_rendering.py # 终端宽度感知 Markdown 和表格布局
└─ rendering.py         # Banner、状态、工具卡片、回答与 Diff 渲染

validation/
├─ tool_validation.py       # 工具参数解析和校验
├─ tool_completion.py       # 编码工具成功后的本地完成说明回退
├─ response_validation.py   # 通用回答质量校验与有限修复
└─ validation_pipeline.py   # 确定性格式、事实和引用校验

data/                   # 知识库源文件
vector_store/           # 持久化向量索引
.damnatiox/sessions/    # 本地会话 JSON（Git 忽略）
.damnatiox/settings.json # 模型与 effort 偏好（Git 忽略）
~/.damnatiox/config.json # 用户级 DeepSeek API Key（仓库外）
```

## 主要配置

| 参数 | 默认值 | 说明 |
|---|---:|---|
| `ChainConfig.model` | `deepseek-v4-pro` | `/model` 可切换为 `deepseek-v4-flash` |
| `ChainConfig.reasoning_effort` | `high` | `/effort` 可选 `low/high/max` |
| `ChainConfig.max_model_steps` | 30 | 单轮回答/工具循环的模型步骤上限 |
| `ChainConfig.total_timeout_seconds` | `None` | 默认关闭整轮 wall-clock 时限 |
| `ChainConfig.api_timeout_seconds` | `None` | 默认关闭单次模型 API 固定时限 |
| `ChainConfig.compression_timeout_seconds` | `None` | 默认关闭摘要 API 固定时限 |
| `ChainConfig.max_retryable_errors` | 3 | 可重试工具错误预算 |
| `ChainConfig.max_replans` | 5 | 重新规划和补充证据预算 |
| `ChainConfig.max_answer_repairs` | 3 | 格式与事实回答修复预算 |
| `ChainConfig.max_tool_calls_per_batch` | 16 | 单个模型响应实际执行的工具调用上限；其余调用生成 skipped 结果 |
| `ChainConfig.min_rag_score` | 0.5 | RAG 覆盖和 Evidence 过滤阈值 |
| `DEFAULT_TOP_K` | 3 | 每次 RAG 返回片段数 |
| `MAX_RAG_RETRIEVALS_PER_TURN` | 3 | 单轮实际 RAG 检索上限 |
| `ToolExecutor.max_parallel_tools` | 4 | 单个 `parallel_safe` 独立段的最大 worker 数 |

模型请求和整轮链路改为“轮次优先”，对应 Coding Agent 中常见的全局最大迭代、
每类错误独立计数和失败后继续收敛。Python 子进程、项目命令、静态网页读取等
本地工具仍保留各自的资源时限，防止卡住的外部进程占用执行器。

## 当前自动化验证

```powershell
.\.venv\Scripts\python.exe -m unittest discover -s tests -v
.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\python.exe -m ruff format --check .
.\.venv\Scripts\python.exe -m ruff check .
.\.venv\Scripts\python.exe -m build
.\.venv\Scripts\python.exe -m twine check .\dist\*
```

## 打包、GitHub Actions 与 PyPI 发布

`.github/workflows/ci.yml` 在 `main` push 和 Pull Request 时执行 Ruff、编译、
全量测试、wheel/sdist 构建与 Twine 元数据检查。`.github/workflows/publish.yml`
只在 GitHub Release 发布时运行，先构建并传递唯一的 distribution artifact，
再使用 OIDC 和 PyPI Trusted Publishing 上传，不读取 PyPI API Token。

PyPI 账号中需要一次性创建 pending Trusted Publisher：

| 字段 | 值 |
|---|---|
| PyPI project name | `damnatiox-agent` |
| GitHub owner | `jame100101` |
| Repository | `agent_learning` |
| Workflow | `publish.yml` |
| Environment | `pypi` |

同时在 GitHub 仓库创建名为 `pypi` 的 Environment，建议为该 Environment 配置
发布审批。之后每次版本更新沿用固定流程：

1. 修改 `damnatiox_agent/__init__.py` 中的 `__version__`。
2. 执行 Ruff、全量测试、`python -m build` 和 `python -m twine check dist/*`。
3. 提交并推送 `main`，等待 `CI` workflow 全部完成。
4. 创建与版本一致的 Git tag 和 GitHub Release，例如 `v0.1.0`。
5. `Publish to PyPI` workflow 经 `pypi` Environment 后构建并发布。
6. 用 `pipx upgrade damnatiox-agent` 验证已发布版本和 `damnatiox --version`。

流程依据 [PyPA 的 GitHub Actions + Trusted Publishing 指南](https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/)。

当前回归集包含 234 个测试，另含 75 组参数化子测试，覆盖：

- chat、rag、tools 三条完整模拟链路；
- 高相关和低置信度 RAG Coverage Gate；
- Router、Planner、Loop Guard 和失败预算；
- 普通工具、RAG、参数错误、重复保护、同轮 cache、批内 single-flight 和统一
  ToolResult；
- Search/Browser 解析、SQLite 只读查询、文件范围和 Python 执行；
- Glob/Grep 定位、原子写入、唯一文本编辑、语法反馈、命令 policy、结构化
  PowerShell、执行期计划白名单、可信可执行入口、Python AST/内存边界、失败映射、
  工作区 revision、有界输出、进程超时和后台子进程清理；
- Skill 安全解析、目录优先级、选择预算、渐进披露、工具交集、TUI 选择、
  重载后补全刷新和当前轮上下文注入；
- DamnatioX 本地命令、上下文查看、会话保存/恢复和无副作用入口导入；
- 用户级 API Key 缺省、环境变量优先级、首次 TUI 输入、原子持久化、损坏配置
  恢复、凭据脱敏，以及 wheel 资源和 console script 启动；
- `/model`、`/effort` 直接切换、全屏选择浮层、requested/effective 映射和
  `.damnatiox/settings.json` 原子持久化；
- 当前轮 Evidence 去重、过滤、预算裁剪、最终编辑/验证保留和历史隔离；
- 精确输出、枚举、JSON、引用编号和逐 claim 支撑校验；
- SessionContext 和结构化摘要压缩的成功及失败事务。
- 中英文 token 本地估算、服务端精确 usage 聚合、问候语 LLM 路由、简单 chat
  自适应收敛和无 wall-clock 默认预算。
- 提示词集中存放、动态模板边界、角色标记和基础 prompt token 预算。
- reasoning/content 增量、流式工具调用重建、流式 usage、全屏布局、思考开关、
  完整 Session 历史恢复、全范围滚轮、Ctrl+C 退出、自适应 Composer 和 Markdown
  表格重排、窗口缩放后的 Rich 重渲染、直接视口滚动、自适应启动页和
  无阴影 DX 固定顶栏与测试版本提示。
- 独立只读工具真实并发、最大 worker 数、反序完成后的顺序提交、RAG 串行失败
  隔离、副作用失败屏障、批次调用上限、single-flight 失败预算去重、写后 cache
  失效、改后同命令复测、Evidence ID 稳定和 workspace snapshot revision 缓存。

## RAG 测试与验收标准

RAG 目前没有统一的全球认证标准或固定及格分数。项目采用“固定测试集、分层
指标、人工抽检、版本回归和线上监控”的工程评估方法。RAGAS、LangSmith、
TruLens、DeepEval 和 ARES 属于常用评估框架或方法；TREC RAG Track 提供研究
级数据集与评测流程，但不作为本项目的强制产品认证标准。

评估时必须分别测量 Router、Retriever、回答生成、工具调用、Validator 和系统
性能，不能只用一个总分代表完整链路。

### 1. 测试集结构

每条测试数据建议包含以下字段：

```json
{
  "id": "rag_001",
  "messages": [
    {
      "role": "user",
      "content": "根据知识库解释 Git"
    }
  ],
  "expected_route": "rag",
  "expected_tools": [
    "search_knowledge_base"
  ],
  "expected_sources": [
    "git.md"
  ],
  "required_facts": [
    "Git 是分布式版本控制系统"
  ],
  "forbidden_claims": [],
  "reference_answer": "Git 是一种分布式版本控制系统。",
  "should_answer": true
}
```

测试集由以下三种数据组成：

1. 人工编写并核对的高质量样例。
2. 脱敏后的真实用户问题和失败案例。
3. 从知识库生成并经人工抽检的合成样例。

每次发现新的线上问题，都应将其整理为固定回归样例。测试数据、知识库版本、
模型版本、Embedding 版本、Prompt 版本、分块参数和 `top_k` 必须一起记录，
保证不同实验结果可复现、可比较。

第一版建议至少准备 100 条用例：

| 类型 | 建议数量 |
|---|---:|
| 普通常识，应直接回答 | 15 |
| 明确要求读取知识库 | 20 |
| 知识库中不存在答案 | 10 |
| 包含相似但错误的干扰片段 | 10 |
| 多轮追问 | 10 |
| 跨轮证据隔离 | 10 |
| 普通工具调用 | 10 |
| RAG 与其他工具组合 | 10 |
| 全库统计问题 | 5 |

### 2. Router 评估

Router 测试集必须覆盖四分类、复杂度、建议工具和结构化解析失败回退：

```text
什么是 Git？                    → chat
根据知识库解释 Git              → rag
计算 2 + 3                     → tools
比较多个来源并形成研究报告       → research
Git 在知识库里吗？              → rag，再由 Coverage Gate 判断 covered
```

Router 记录以下指标：

| 指标 | 含义 |
|---|---|
| Accuracy | 全部路由结果的正确比例 |
| Precision | 被判为某类的问题中实际属于该类的比例 |
| Recall | 实际属于某类的问题中被正确识别的比例 |
| Macro-F1 | 对每个类别分别计算 F1 后取平均，避免大类别掩盖小类别 |
| Confusion Matrix | 观察 `chat`、`rag`、`tools` 和 `research` 的具体混淆方向 |
| Coverage Accuracy | `rag` 路线中 covered、empty、low_confidence 和 error 的判断准确率 |

`rag Recall` 和 Coverage Accuracy 是关键指标。前者判断是否应该尝试知识库，
后者判断真实检索结果是否足以支撑回答，两者应分别评估。

### 3. Retriever 评估

Retriever 只评估“正确文档或片段是否被检索出来”，不评价最终回答措辞。

| 指标 | 定义 |
|---|---|
| Hit@K | 前 K 个结果中是否至少出现一个正确片段 |
| Recall@K | 前 K 个结果召回的相关片段数除以全部相关片段数 |
| Precision@K | 前 K 个结果中的相关片段数除以 K |
| MRR | 第一个正确结果排名倒数的平均值 |
| nDCG@K | 同时考虑结果相关等级和排序位置 |

Retriever 测试必须保存预期的 `source` 或 `evidence_id`，不能仅凭最终回答是否
看起来正确来推断检索质量。测试时至少覆盖：

- 同义改写、缩写、大小写和中英文混合。
- 拼写错误和额外空白。
- 相似主题文档造成的干扰。
- 一个答案分布在多个片段中的多跳问题。
- 空知识库、空结果和低相关度结果。
- 不同 chunk 大小、overlap、Embedding、检索算法和 `top_k` 的对照实验。

### 4. 回答生成评估

生成层至少分成四个维度：

| 指标 | 比较对象 | 检查内容 |
|---|---|---|
| Answer Correctness | 回答与参考答案 | 关键事实是否正确 |
| Answer Relevance | 回答与用户问题 | 是否直接回应问题 |
| Faithfulness / Groundedness | 回答与本轮证据 | 回答中的事实是否有证据支持 |
| Completeness | 回答与必需事实集合 | 是否覆盖所有关键要求 |

如果回答支持来源引用，还应增加：

| 指标 | 含义 |
|---|---|
| Citation Precision | 已给出的引用中真正支持对应结论的比例 |
| Citation Recall | 应当引用的关键结论中实际附带有效引用的比例 |
| Citation Validity | 回答中引用的 `evidence_id` 是否真实存在于本轮 Registry |

生成质量可以使用人工评分、确定性规则和 LLM Judge 组合测量。LLM Judge 的模型、
Prompt 和输出 Schema 必须固定，并使用人工标注样本定期校准。不能把 Judge 的
一次输出直接当作绝对真值。

### 5. 工具与 Agent 评估

搜索、数据库、文件、浏览器、代码执行和 RAG 工具统一记录：

| 指标 | 含义 |
|---|---|
| Tool Selection Accuracy | 是否选择了正确工具 |
| Argument Validation Pass Rate | 工具参数是否符合 Schema |
| Tool Call Precision | 实际工具调用中必要调用的比例 |
| Tool Call Recall | 所有必要工具调用中实际执行的比例 |
| Tool Result Utilization | 最终回答是否正确使用工具结果 |
| Redundant Call Rate | 相同参数和结果的非必要重复调用比例 |
| Agent Goal Success Rate | 整体任务是否完成 |

工具测试还必须包含参数缺失、额外字段、错误类型、超长输入、工具异常、超时、
空结果、重复调用和多个工具组合调用。

### 6. Validator 评估

Validator 本身作为独立模型组件进行评估。测试集中应同时包含：

1. 完全正确的回答。
2. 明显错误的回答。
3. 部分正确但遗漏关键事实的回答。
4. 事实正确但缺少本轮证据支持的回答。
5. 格式错误但语义正确的回答。
6. 已经正确、不应继续改写的回答。

记录以下指标：

| 指标 | 含义 |
|---|---|
| False Rejection Rate | 正确回答被判为失败的比例 |
| False Acceptance Rate | 错误回答被放行的比例 |
| Repair Success Rate | 修复后真正通过人工标准的比例 |
| Over-repair Rate | 原回答正确但被修坏的比例 |
| Average Repair Count | 每个回答平均重新生成次数 |

每次校验都应记录 `valid`、错误代码、错误原因、`retry_instruction`、修复前后
回答和修复次数，以区分真实修复和 Validator 波动。跨轮对话中，Validator 只能
把本轮 RAG 与工具结果当作当前事实证据；历史回答和历史工具结果只能作为会话
背景，不能作为本轮证据。

### 7. 确定性格式校验

枚举、固定字符串、JSON、字段类型、长度、数值范围等要求优先使用确定性代码，
语义一致性再交给 LLM Validator。

例如 Router 只接受：

```python
candidate.strip() in {"1", "2", "3"}
```

推荐校验顺序：

```text
确定性格式检查
    ↓
证据与事实校验
    ↓
失败后有限修复
    ↓
再次执行确定性格式检查
    ↓
最终输出
```

### 8. 系统性能与稳定性

每次评估同时记录：

- p50、p95 和最大响应延迟。
- 每轮输入、输出和总 Token 数量。
- 单次请求及完整任务成本。
- RAG 与其他工具的调用次数。
- 缓存命中率和重复调用率。
- API、解析、工具执行和 Validator 错误率。
- 超时、最大步数终止和修复次数分布。

质量指标提高但延迟、成本或错误率显著恶化时，不能直接认定新版本整体优于
基线版本。

### 9. 项目初始验收门槛

以下数值是本项目的第一版工程门槛，不属于统一行业标准。积累真实问题和人工
标注后，应根据业务风险调整：

| 指标 | 初始门槛 |
|---|---:|
| Router Macro-F1 | `>= 0.90` |
| `rag` Recall | `>= 0.95` |
| RAG Coverage Accuracy | `>= 0.90` |
| Retrieval Hit@3 | `>= 0.90` |
| Retrieval Recall@5 | `>= 0.90` |
| Faithfulness | `>= 0.95` |
| Answer Correctness | `>= 0.90` |
| 工具参数 Schema 通过率 | `= 1.00` |
| 预期工具调用成功率 | `>= 0.95` |
| 跨轮证据污染失败数 | `= 0` |
| Validator False Acceptance Rate | `<= 0.02` |
| Validator False Rejection Rate | `<= 0.05` |

除绝对门槛外，每次改动还必须与上一稳定版本对比。核心指标下降、已有固定用例
失败或跨轮证据污染测试失败时，本次改动不进入稳定版本。

### 10. 当前项目固定回归样例

至少保留以下用例：

```text
什么是 Markdown？                    → chat
什么是 Git？                         → chat
根据知识库解释 Git                   → rag、covered，并命中 Git 来源
Git 不是在知识库里吗？               → rag，并执行本轮覆盖检索
计算 2 + 3                           → tools，并调用 calculator
比较多个来源并形成报告                → research，并生成 PlanStep
知识库一共有多少字？                 → 全库统计工具，不使用 Top-K 推断
先询问 Markdown，再询问 Git          → Markdown 证据不污染 Git 回答
检索 example2.md 后询问 Git          → 重新检索 Git，不复用历史证据
只返回数字 1、2、3 中的一个          → 确定性枚举校验通过
RAG 检索为空                         → 明确报告证据为空，不编造来源
工具参数错误                         → 返回结构化参数错误并保持消息协议完整
```

### 11. 标准评估流程

```text
冻结测试集、知识库和模型配置
    ↓
运行 Router 单项评估
    ↓
运行 Retriever 单项评估
    ↓
运行生成、引用和 Validator 评估
    ↓
运行工具及多轮端到端评估
    ↓
与上一稳定版本比较
    ↓
人工抽检失败样例
    ↓
输出指标、失败分类和实验配置
```

调优时一次只改变一个主要变量，例如 chunk 大小、Embedding、`top_k`、Router
Prompt 或生成模型。多个变量同时改变会增加归因难度。

### 12. 参考评估体系

- [RAGAS Metrics](https://docs.ragas.io/en/stable/concepts/metrics/available_metrics/)
- [RAGAS Testset Generation](https://docs.ragas.io/en/stable/concepts/test_data_generation/)
- [LangSmith RAG Evaluation](https://docs.langchain.com/langsmith/evaluate-rag-tutorial)
- [ARES: An Automated Evaluation Framework for RAG Systems](https://arxiv.org/abs/2311.09476)
- [TREC RAG Track](https://trec.nist.gov/data/rag.html)

## 后续任务

第二至第四阶段已经完成以下基础能力：

- `TurnState`、统一 `ToolResult`、当前轮 `EvidenceRegistry`；
- 四分类 Router、RAG Coverage Gate、Planner、Loop Guard；
- 工具失败、空结果、重复调用、重试和重新规划预算；
- Answer Context、确定性格式、事实与引用校验；
- 短期上下文、会话 `TurnRecord` 和 LLM 结构化摘要。
- Search、SQLite、File、静态 Browser 和 Python Code 首版工具。
- Glob、Grep、Write、Edit、受约束 Command 和结构化 PowerShell 组成的
  Coding Agent 工具箱。
- 项目/用户 Skills 发现、安全解析、显式选择和按需上下文披露。
- DamnatioX Agent 全屏 TUI、真实流式回答、可选思考展示、到底自动跟随、
  模型/effort 选择和动态工作区状态。
- 同响应独立只读工具的受控并发、顺序提交、缓存、single-flight 和批次级
  失败聚合。

### 已接入工具与下一步扩展

以下工具已进入统一执行入口：

| 工具 | 当前返回内容 |
|---|---|
| Search | 标题、摘要、URL、排序和 Evidence |
| SQLite | 字段、数据行、截断状态、查询耗时和 Evidence |
| File | 规范化项目路径、文本、行号和 Evidence |
| Browser | 静态页面正文、内容类型、URL 和 Evidence |
| Code | 退出码、stdout、stderr、耗时和 Evidence |
| Glob / Grep | 项目相对路径、真实行号、匹配数量、截断状态和 Evidence |
| Write / Edit | 原子写入结果、Diff、SHA-256 和即时语法反馈 |
| Command | policy 校验后的 argv、cwd、退出码、stdout/stderr、耗时、影响类型和截断状态 |
| PowerShell | 只读 pipeline、规范化参数、退出码、stdout/stderr、耗时和 Evidence |

MCP、JavaScript 浏览器交互、数据库连接池和持久终端进程留在后续阶段。
继续添加普通工具时，只注册 Schema 和执行函数，再由 ToolExecutor 统一生成
结果状态和 Evidence，不向 `main.py` 增加专用分支。

### 仍需继续加强

1. 使用正式标注集校准 Router 和 `min_rag_score`，而不是长期依赖默认 `0.5`。
2. 为复杂任务增加真正的并行 PlanStep 调度和依赖关系。
3. 为 retryable error 增加按工具配置的退避策略。
4. 给 Validator 增加完整持久化日志和离线错误分析。
5. 将内部 `[E1]` 映射渲染为标题、文件位置或 URL 形式的来源列表。
6. 长期语义记忆仍留在后续阶段；当前已持久化会话摘要、最近轮次和归档轮次，
   支持按 session ID 续聊。
7. Browser 后续再增加 JavaScript、点击、表单、截图和页面状态。
8. Database 后续按实际业务决定 PostgreSQL/MySQL 连接配置和权限模型。
9. Coding Agent 后续增加 LSP 符号搜索、Windows 受限 Token/容器执行后端和
   按项目配置的自动验收命令。
10. Skills 后续增加输入框 `$skill-name` 补全和可选的浮层选择器。
11. TUI 后续增加流式 Markdown 增量解析、运行中止和会话选择浮层。

## Ruff 格式

项目格式配置位于 `pyproject.toml`，目标 Python 版本为 3.14，行宽为 88。

```powershell
.\.venv\Scripts\ruff.exe format .
.\.venv\Scripts\ruff.exe format --check .
```

---

## 开源 RAG、Agent 与记忆项目研究

本节记录对以下项目主分支和官方文档的链路研究，并据此整理本项目后续的
目标架构：

- [Open Deep Research](https://github.com/langchain-ai/open_deep_research)
- [STORM](https://github.com/stanford-oval/storm)
- [Khoj](https://github.com/khoj-ai/khoj)
- [Onyx](https://github.com/onyx-dot-app/onyx)
- [AnythingLLM](https://github.com/Mintplex-Labs/anything-llm)
- [RAGFlow](https://github.com/infiniflow/ragflow)
- [Mem0](https://github.com/mem0ai/mem0)
- [Letta](https://github.com/letta-ai/letta)

这些项目并不属于同一种系统，主要分为四类：

| 类别 | 项目 | 核心目标 |
|---|---|---|
| 深度研究与报告生成 | Open Deep Research、STORM | 主动规划、反复搜索、生成长报告 |
| RAG 与 Agent 应用 | Khoj、Onyx、AnythingLLM、RAGFlow | 文档检索、工具调用、对话和引用 |
| 独立记忆层 | Mem0 | 从对话提取长期事实，并在后续检索 |
| 有状态 Agent 运行时 | Letta | 管理上下文窗口、记忆、工具和持久状态 |

### 统一观察模型

为了比较这些系统，将完整链路统一拆成以下阶段：

```mermaid
flowchart LR
    A["用户输入"] --> B["会话状态与 Router"]
    B --> C["任务规划与问题拆分"]
    C --> D["RAG 检索与工具调用"]
    D --> E["Evidence 统一登记"]
    E --> F["去重、重排与压缩"]
    F --> G["LLM 生成草稿"]
    G --> H["格式、引用与事实校验"]
    H -->|失败| C
    H -->|通过| I["最终回答"]
    I --> J["会话与长期记忆写回"]
```

各项目覆盖的重点不同：

| 项目 | 主要覆盖阶段 |
|---|---|
| Open Deep Research | 任务规划、并行研究、工具循环、研究压缩、报告生成 |
| STORM | 多视角提问、资料收集、大纲、分章节生成和引用 |
| Khoj | Router、本地与在线检索、工具循环、研究模式和记忆 |
| Onyx | 数据连接、权限索引、混合检索、工具循环和引用映射 |
| AnythingLLM | 工作区索引、普通 RAG、Agent Skills、Flows 和本地部署 |
| RAGFlow | 文档理解、模板切块、混合检索、重排、引用和 Agent Workflow |
| Mem0 | 长期记忆提取、去重、检索与更新 |
| Letta | Agent 状态、上下文窗口、Memory Blocks、文件和归档记忆 |

### Open Deep Research 链路

```text
用户输入
    → 判断是否需要澄清
    → 生成 research brief
    → Supervisor 制订研究计划
    → 并行启动多个 Researcher
    → Researcher 循环调用 Search、MCP 和 Think 工具
    → 网页去重和网页摘要
    → 压缩每个 Researcher 的研究结果
    → Supervisor 判断是否需要继续研究
    → 汇总全部 notes
    → Final Report 模型生成报告
```

主要实现：

- [`deep_researcher.py`](https://github.com/langchain-ai/open_deep_research/blob/main/src/open_deep_research/deep_researcher.py)
- [`utils.py`](https://github.com/langchain-ai/open_deep_research/blob/main/src/open_deep_research/utils.py)

可借鉴的设计：

1. 普通输入先整理为独立的 `research_brief`。
2. Supervisor 负责任务拆分，Researcher 负责执行。
3. 多个互相独立的研究单元并行运行。
4. 每个 Researcher 通过 `LLM → Tool → Result → LLM` 循环继续研究。
5. 原始网页先摘要，研究结果再压缩，降低最终模型的上下文压力。
6. 复杂任务使用专门 Planner，普通问题继续走短链路。

需要补充的部分：

- 当前核心更接近在线深度研究，而不是本地知识库 RAG。
- 多次摘要和压缩后，需要额外保留原始 Evidence 映射。
- Structured Output 主要约束控制结果，不等同于逐断言事实校验。

### STORM 链路

```text
研究主题
    → 生成多个角色和视角
    → 每个角色与 Topic Expert 多轮对话
    → 每轮问题转换为多个搜索查询
    → 搜索并生成带引用的回答
    → 合并全部角色的访谈记录
    → 生成初始大纲
    → 使用访谈资料优化大纲
    → 按章节检索相关资料
    → 并行生成章节
    → 合并、去重和润色文章
```

主要实现：

- [`engine.py`](https://github.com/stanford-oval/storm/blob/main/knowledge_storm/storm_wiki/engine.py)
- [`knowledge_curation.py`](https://github.com/stanford-oval/storm/blob/main/knowledge_storm/storm_wiki/modules/knowledge_curation.py)
- [`outline_generation.py`](https://github.com/stanford-oval/storm/blob/main/knowledge_storm/storm_wiki/modules/outline_generation.py)
- [`article_generation.py`](https://github.com/stanford-oval/storm/blob/main/knowledge_storm/storm_wiki/modules/article_generation.py)

可借鉴的设计：

1. 多视角问题生成，提高复杂主题的检索覆盖率。
2. 先构建资料表，再生成大纲和文章。
3. 先确定文章结构，再为每个章节挑选证据。
4. 章节独立生成，最终统一去重和润色。
5. 保留搜索结果、访谈、大纲、草稿和引用映射等中间产物。

STORM 更适合作为独立的 `report` 工作流，不作为所有用户问题的默认链路。

### Khoj 链路

```text
用户输入
    → 加载 Agent 配置和对话历史
    → 检索相关长期记忆
    → Router 选择一个或多个数据源与工具
    → 普通问答或 Deep Research
    → 调用本地文档、网络、网页、代码、浏览器或 MCP
    → 合并和压缩工具结果
    → 生成回答
    → 从新对话中提取并写入长期记忆
```

主要实现：

- [`helpers.py`](https://github.com/khoj-ai/khoj/blob/master/src/khoj/routers/helpers.py)
- [`api_chat.py`](https://github.com/khoj-ai/khoj/blob/master/src/khoj/routers/api_chat.py)
- [`research.py`](https://github.com/khoj-ai/khoj/blob/master/src/khoj/routers/research.py)
- [`processor/tools`](https://github.com/khoj-ai/khoj/tree/master/src/khoj/processor/tools)

Router 可选择的能力包括 Notes、General、Online、Webpage、Code、Research、
Operator 和 MCP。结构化结果返回后还会继续检查工具是否存在、当前 Agent
是否允许使用以及参数是否合法。

Deep Research 的主要循环为：

```text
LLM 选择下一批工具
    → 校验工具及参数
    → 浏览器类工具顺序执行
    → 其他互不依赖的工具并行执行
    → 分类保存 document、web、code、browser 和 MCP 结果
    → 检查相同工具与参数是否重复调用
    → LLM 继续规划或生成最终总结
```

本项目重点参考：

- 结构化 Router；
- 工具白名单；
- `tool_name + normalized_arguments` 重复调用检测；
- 普通问答与 Deep Research 分级；
- 当前轮工具结果分类保存；
- 用户中断和补充信息的处理方式。

### Onyx 链路

离线索引：

```text
Connector 拉取数据
    → 写入文档元数据和权限
    → 文档解析与切块
    → 可选上下文化摘要和文档摘要
    → 生成 embedding
    → 写入全文、向量、元数据和 ACL
    → 保存同步状态
```

在线检索：

```text
用户查询
    → 构建用户权限和文档过滤条件
    → 生成查询 embedding
    → 关键词与向量混合检索
    → 并行查询内部索引和外部连接器
    → Chunk 去重
    → 分数融合与可选重排
    → 合并邻接 Chunk
    → 转换为统一搜索文档
    → 返回 LLM 工具循环
```

主要实现：

- [`indexing_pipeline.py`](https://github.com/onyx-dot-app/onyx/blob/main/backend/onyx/indexing/indexing_pipeline.py)
- [`pipeline.py`](https://github.com/onyx-dot-app/onyx/blob/main/backend/onyx/context/search/pipeline.py)
- [`search_runner.py`](https://github.com/onyx-dot-app/onyx/blob/main/backend/onyx/context/search/retrieval/search_runner.py)
- [`chat/README.md`](https://github.com/onyx-dot-app/onyx/blob/main/backend/onyx/chat/README.md)
- [`llm_loop.py`](https://github.com/onyx-dot-app/onyx/blob/main/backend/onyx/chat/llm_loop.py)

Onyx 会为搜索结果分配数字型 `document` ID。LLM 只使用这个 ID 引用，
真实标题、URL、权限和 UI 映射由系统保存。这种设计适合演化为本项目的
`Evidence Registry`。

本项目重点参考：

- `Evidence ID → 原始来源` 注册表；
- 检索权限和过滤条件在工具执行前完成；
- Tool Result、LLM Context 和 UI 展示结果分离；
- 当前轮引用映射；
- 长工具结果压缩和上下文裁剪；
- 工具循环的显式状态管理。

### AnythingLLM 链路

文档摄取：

```text
文件、链接或文本
    → Collector 判断文件类型
    → 对应转换器解析
    → 输出标准化 Document
    → 根据 Workspace 切块
    → 生成 embedding
    → 写入 Workspace 对应的向量数据库 namespace
```

普通聊天与 RAG：

```text
用户输入
    → 命令检测
    → Agent 模式检测
    → 模型路由
    → 加载聊天历史
    → 加载 pinned documents
    → 加载当前线程 parsed files
    → Workspace 向量相似度搜索
    → 可选 rerank
    → 历史来源回填上下文
    → 压缩和组装 messages
    → 调用 LLM
    → 返回 sources 并保存聊天记录
```

主要实现：

- [`processSingleFile/index.js`](https://github.com/Mintplex-Labs/anything-llm/blob/master/collector/processSingleFile/index.js)
- [`stream.js`](https://github.com/Mintplex-Labs/anything-llm/blob/master/server/utils/chats/stream.js)
- [`chats/agents.js`](https://github.com/Mintplex-Labs/anything-llm/blob/master/server/utils/chats/agents.js)
- [`vectorDbProviders`](https://github.com/Mintplex-Labs/anything-llm/tree/master/server/utils/vectorDbProviders)

AnythingLLM 区分：

- `chat`：没有检索结果时仍可使用模型通用知识；
- `query`：没有知识库命中时结束本轮知识回答；
- `automatic`：模型支持原生工具时转入 Agent 工具链。

它会把历史来源回填到上下文，但展示的 `sources` 主要保留本轮检索来源。
这种设计有助于连续对话，却不满足本项目计划中的严格当前轮证据隔离。

本项目主要参考工作区、Query 模式、全文与向量 RAG 混合方式，以及本地化
产品体验。

### RAGFlow 链路

文档摄取：

```text
上传或同步文档
    → 对象存储
    → 根据 parser_id 选择解析器
    → DeepDoc/Parser 解析版面、表格、图片和文本
    → 根据模板、分隔符和重叠率切块
    → 提取标题、问题、关键词、摘要和文档结构
    → 批量生成 embedding
    → 写入全文字段、向量和元数据
    → Elasticsearch/Infinity 建立索引
```

在线检索：

```text
问题
    → KB、文档和元数据过滤
    → 构建全文 Query
    → 生成查询 embedding
    → 全文召回与 Dense 向量召回
    → 分数融合
    → 外部 reranker 或本地关键词/向量重排
    → PageRank、标签等额外排名特征
    → similarity threshold
    → 稳定排序和分页
    → 返回 Chunks 与文档聚合
```

主要实现：

- [`task_executor.py`](https://github.com/infiniflow/ragflow/blob/main/rag/svr/task_executor.py)
- [`rag/nlp/search.py`](https://github.com/infiniflow/ragflow/blob/main/rag/nlp/search.py)

可选能力还包括 GraphRAG、RAPTOR、PageIndex、元数据自动过滤、MCP、
Web Search、代码执行、Browser、Memory 和多 Agent Workflow。

本项目重点参考：

- Parser、Chunker、Embedder 和 VectorStore 分层；
- 标准化 Chunk 元数据；
- 关键词和向量多路召回；
- reranker 作为可插拔阶段；
- Retrieval 本身注册为普通工具；
- 检索权重、阈值和过滤条件显式化。

### Mem0 链路

Mem0 是独立记忆层，不负责完整的 RAG 回答和通用工具 Agent。

记忆写入：

```text
对话消息
    → 校验 user_id、agent_id 或 run_id
    → 加载最近消息
    → 检索已有相关记忆
    → 使用 LLM 提取新增事实
    → 批量生成 embedding
    → Hash 去重
    → 写入向量库
    → 提取并关联实体
    → 记录记忆历史
```

记忆检索：

```text
查询
    → 校验 Scope 和 Filter
    → 查询词形归一
    → 提取查询实体
    → Dense 语义检索
    → Keyword/BM25 检索
    → Entity Boost
    → 分数融合和阈值过滤
    → 可选 reranker
    → 返回 MemoryItem
```

主要实现：

- [`mem0/memory/main.py`](https://github.com/mem0ai/mem0/blob/main/mem0/memory/main.py)
- [`graph_memory.py`](https://github.com/mem0ai/mem0/blob/main/mem0/memory/graph_memory.py)

本项目主要参考：

- 按用户、Agent 和运行实例隔离记忆；
- 写入前检索已有记忆；
- 记忆去重、过期和更新策略；
- 语义、关键词和实体多信号检索；
- 记忆提取模型与正常回答模型分离。

记忆内容属于从对话提炼的状态，不与知识库的权威 Evidence 混为一类。

### Letta 链路

```text
用户输入
    → 加载 Agent 状态
    → 加载当前 Conversation 消息
    → 注入常驻 Memory Blocks
    → 注入已打开文件片段
    → 按需搜索 Archival Memory
    → 构建上下文窗口
    → LLM 推理
    → 调用记忆、文件、归档、MCP 或自定义工具
    → 工具结果写回上下文
    → LLM 继续推理或回答
    → 持久化消息、工具调用和 Agent 状态
    → 上下文过长时压缩历史
```

Letta 的上下文层级：

| 层级 | 是否常驻上下文 | 访问方式 | 适合内容 |
|---|---:|---|---|
| Memory Blocks | 是 | 直接读取、记忆工具修改 | 用户信息、Persona、工作状态 |
| Conversation Messages | 部分 | 当前上下文、自动压缩 | 最近对话 |
| Files | 部分 | open、close、grep、semantic search | 较大的只读资料 |
| Archival Memory | 否 | 语义检索工具 | 长期但不必常驻的信息 |
| External RAG | 否 | MCP 或自定义工具 | 大规模外部知识库 |

官方文档：

- [Context hierarchy](https://docs.letta.com/guides/core-concepts/memory/context-hierarchy)
- [Memory blocks](https://docs.letta.com/guides/core-concepts/memory/memory-blocks)
- [Compact Conversation](https://docs.letta.com/api/resources/conversations/subresources/messages/methods/compact)

本项目主要参考：

- 短期上下文、会话消息、常驻记忆和外部知识库分层；
- Memory Block 作为始终在上下文中的状态；
- 文件和长期记忆按需检索；
- 对话历史压缩和滑动窗口；
- Agent 状态与工具调用一起持久化。

## 项目能力横向对比

| 项目 | Router/规划 | 知识库检索 | Web 研究 | 通用工具 | 引用 | 长期记忆 | 主要适用场景 |
|---|---|---|---|---|---|---|---|
| Open Deep Research | Supervisor、多研究单元 | 较弱 | 很强 | Search、MCP | 报告引用 | 基本没有 | 深度调研 |
| STORM | Persona、Outline | 可接 VectorRM | 很强 | 较少 | 较强 | 没有 | 百科、综述和报告 |
| Khoj | 结构化多工具 Router | 强 | 强 | Code、Browser、MCP | 中等偏强 | 强 | 个人知识 Agent |
| Onyx | Agentic Loop | 很强 | 强 | Search、Web、Code | 很强 | 中等 | 企业知识助手 |
| AnythingLLM | chat、query、automatic | 中等 | 中等 | Skills、Flows、MCP | 中等 | Workspace、Global | 本地一体化助手 |
| RAGFlow | Workflow、Agent | 很强 | 强 | MCP、Code、Browser | 很强 | 正在完善 | 复杂文档 RAG |
| Mem0 | 无通用 Router | 只检索记忆 | 无 | 无 | 非核心能力 | 很强 | 独立长期记忆层 |
| Letta | 有状态 Agent Loop | Files、Archive、External RAG | 取决于工具 | 很强 | 非核心能力 | 很强 | 长期运行 Agent |

## 校验能力对比

需要区分三种校验：

### Router 与输出结构校验

- Open Deep Research 使用 Structured Output 控制研究任务和终止状态。
- Khoj 使用 Pydantic、工具白名单和非法选择回退。
- Onyx 使用原生 Tool Calling，并为部分模型提供文本解析回退。
- RAGFlow 使用 Workflow 参数和结构化输出。
- Mem0 对 Scope、Filter 和输入类型进行校验。
- Letta 使用 Tool Rules 和工具参数模型限制执行路径。

### 工具调用与结果校验

- Khoj 检测重复的 `tool_name + arguments`。
- Onyx 把 Tool Result 和循环状态持久化，并限制循环次数。
- AnythingLLM 在 Query 模式下对空检索结果执行明确分支。
- RAGFlow 使用阈值、重排、过滤和任务日志控制检索结果。
- Open Deep Research 将工具错误作为 Tool Message 返回研究循环。

### 最终答案事实校验

上述项目的核心链路大多解决结构、工具、来源和引用编号问题，仍缺少统一的：

```text
拆分最终答案中的事实断言
    → 为每条断言找到当前轮 Evidence
    → 判断 Evidence 是否支持断言
    → 不支持时删除、修改或继续检索
    → 重新生成
    → 再次校验
```

因此，本项目继续保留并增强独立 Validator。确定性格式要求优先使用代码
检查，事实与证据一致性再交给 Validator LLM。

## 研究后确定的目标链路

第二至第四阶段以以下链路为目标。Search、SQLite、File、静态 Browser 和
Python Code 已进入统一执行路径，MCP 继续作为后续扩展：

```mermaid
flowchart TD
    A["用户输入"] --> B["创建 TurnState"]
    S["SessionState：摘要、最近对话、未完成任务、用户约束"] --> C
    B --> C["Input Context Builder"]
    C --> D["Router：chat / rag / tools / research"]

    D -->|"chat"| X["Answer Context Builder"]
    D -->|"rag / tools"| E{"是否复杂任务"}
    D -->|"research"| F["Planner"]

    E -->|"否"| G["Tool Selector：选择一个或多个工具"]
    E -->|"是"| F

    F --> H["生成 PlanStep 和完成条件"]
    G --> H
    H --> I{"Loop Guard：步数、时间、重试和重规划预算"}

    I -->|"允许执行"| JB["Tool Batch Scheduler"]
    I -->|"达到预算"| X

    JB --> JC{"是否包含写入或独占屏障"}
    JC -->|"否"| JD["独立调用：线程安全段并发，否则顺序执行"]
    JC -->|"是"| JE["连续独立段并发，写入与命令逐项执行"]
    JD --> K["RAG / Search / DB / File / Browser / Code / PowerShell"]
    JE --> K
    K --> L["按 tool_call 原顺序写入 TurnState"]
    L --> M["Tool Failure Policy"]

    M -->|"success / partial"| N["Current-turn Evidence Registry"]
    M -->|"retryable error"| I
    M -->|"empty / fatal / repeated"| O{"是否选择其他工具"}
    O -->|"是"| F
    O -->|"否"| X

    N --> P["证据去重、过滤、重排和预算裁剪"]
    P --> X

    X --> Q["构建回答上下文"]
    Q --> R["生成 Draft"]
    R --> T["格式与确定性校验"]

    T -->|"格式问题"| R
    T -->|"通过"| U["事实与引用校验"]

    U -->|"需要补充证据"| V{"仍有重规划预算"}
    V -->|"是"| F
    V -->|"否"| W["基于现有证据收敛回答"]

    U -->|"仅回答内容问题"| R
    U -->|"通过"| Y["最终回答"]
    W --> Y

    Y --> Z["Session Memory Writer"]
    Z --> AA["生成精简 TurnRecord"]
    AA --> AB["更新 SessionState"]
    AB --> AC{"上下文是否超过预算"}
    AC -->|"是"| AD["更新 SessionSummary 并裁剪旧 TurnRecord"]
    AC -->|"否"| AE["等待下一次用户输入"]
    AD --> AE
```

### 目标链路组件来源

| 本项目组件 | 主要参考项目 |
|---|---|
| Router、工具选择和工具白名单 | Khoj |
| 复杂任务 Planner 和并行研究 | Open Deep Research |
| 多视角报告模式 | STORM |
| Tool Loop、Evidence ID 和引用映射 | Onyx |
| 文档解析、混合检索和重排 | RAGFlow |
| Workspace 和 Query 模式 | AnythingLLM |
| 长期事实记忆 | Mem0 |
| 上下文窗口和记忆分层 | Letta |

### 目标统一数据结构

```python
class ToolResult:
    tool_call_id: str
    tool_name: str
    status: str
    data: object
    evidence: tuple["Evidence", ...]
    error_code: str | None
    error_message: str | None
    retryable: bool
    fingerprint: str
    metadata: dict


class Evidence:
    evidence_id: str
    turn_id: str
    tool_call_id: str
    source_type: str
    source_uri: str | None
    title: str | None
    content: str
    score: float | None
    query: str
    citation_required: bool
    metadata: dict


class GroundingDecision:
    action: str  # pass / regenerate / retrieve_more
    grounded: bool
    citations_valid: bool
    issues: tuple[str, ...]
    retry_instruction: str
    suggested_queries: tuple[str, ...]
    claims: tuple["ClaimCheck", ...]
```

Validator 默认只读取：

```python
evidence.turn_id == current_turn_id
```

历史消息用于理解对话，历史工具结果和历史 RAG 结果默认不作为本轮事实证据。
需要引用历史来源时，应在本轮重新检索并注册新的 Evidence。

### 阶段完成情况

| 阶段 | 状态 | 主要内容 |
|---|---|---|
| 第一阶段 | 已完成 | SessionContext、最近对话和 LLM 结构化摘要 |
| 第二阶段 | 已完成 | TurnState、ToolResult、ToolExecutor、Evidence Registry |
| 第三阶段 | 已完成基础版 | 四分类 Router、Coverage Gate、Planner、Loop Guard、失败策略 |
| 第四阶段 | 已完成基础版 | Answer Context、确定性校验、事实引用校验、Session Writer |
| 工具扩展 | 已完成首版 | Search、SQLite、File、静态 Browser、Python Code 与 Coding 工具箱；MCP 留在后续阶段 |
| 工具批次并发 | 已完成受控版 | 连续独立段、有界线程池、写入失败屏障、顺序提交、single-flight、同轮缓存、调用上限和物理失败预算去重 |
| Coding Agent | 已完成增强版 | 并行只读定位、Glob、Grep、Read、Write、Edit、受约束 Command、结构化 PowerShell、Interpreter 和即时语法反馈 |
| Skills | 已完成显式选择版 | 多目录发现、安全 YAML、`/skills` 选择、渐进披露和工具交集 |
| DamnatioX TUI | 已完成全屏版 | 固定 Composer、到底自动跟随、输入队列、模型/effort 浮层、思考显示、流式回答和时间统计 |
| 后续研究模式 | 待实施 | 带依赖边的 PlanStep DAG、STORM 风格报告、多 Researcher |
