CLAUDE.md · git:20260823.355fad9 · 2026-08-23 · sha256 323997fd5c3c212b

CLAUDE.md git:20260823.355fad9A

Immutable. This exact content never changes and is served at /api/v1/blob/323997fd5c3c212b.

# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## 项目概述

Undefined 是基于 Python asyncio 的高性能 QQ 机器人平台,通过 OneBot V11 协议(NapCat/Lagrange.Core)与 QQ 通信,搭载认知记忆架构、自研 Skills 系统、本地知识库、全局表情包库,以及 Management-first WebUI / Desktop / Android 管理端。

## 开发命令

```bash
# 依赖安装 / 初始化
uv sync
uv run playwright install       # 页面截图等能力依赖的浏览器运行时

# 启动
uv run Undefined-webui          # 启动 Management-first WebUI(推荐入口)
uv run Undefined                # 直接启动 Bot

# WebUI 自动启动 Bot
# 配置 [webui].autostart_bot = true 后,运行 uv run Undefined-webui 会自动拉起 bot 进程
# 默认为 false,保持传统手动启动行为
# 注意:该配置仅在 WebUI 启动时生效,运行时修改需重启 WebUI

# 代码质量(提交前必须全部通过)
uv run ruff format .
uv run ruff check .
uv run mypy .                   # strict=true
uv run pytest tests/
uv run pytest tests/test_xxx.py
uv run pytest tests/test_xxx.py::test_func -v
uv build --wheel                # 校验打包与资源包含

# 前端 / 桌面端(仅改动 apps/undefined-console/ 或 apps/undefined-chat/ 或 webui/static/js/ 时需要)
cd apps/undefined-console && npm ci && npm run check
cd apps/undefined-console && npm run dev
cd apps/undefined-console && npm run tauri:dev

cd apps/undefined-chat && npm ci && npm run check
cd apps/undefined-chat && npm run tauri:dev

# Git hooks 安装
bash scripts/install_git_hooks.sh
# pre-commit 自动执行:ruff format --check + ruff check + mypy
# 含 JS/Tauri 改动时额外执行:Biome + TypeScript + cargo fmt/check
```

## 代码规范

- **类型注释**:所有 Python 代码必须有完整类型注释,mypy strict 模式
- **异步 IO**:磁盘读写必须走 `utils/io.py`(`asyncio.to_thread` + 跨平台文件锁 + 原子写入),禁止在事件循环中直接阻塞 IO
- **Python 版本**:`>=3.11, <3.14`(推荐 3.12)
- **测试**:pytest + pytest-asyncio,`asyncio_mode = "auto"`
- **前端格式化**:`src/Undefined/webui/static/js/` 由根目录 `biome.json` 管理;`apps/undefined-console/` 和 `apps/undefined-chat/` 走 Biome + TypeScript + Cargo 检查
- **版本号同步**:发布版本时优先使用 `uv run python scripts/bump_version.py <version>`,统一同步 Python 包、console、chat 与 Tauri 版本号
- **Git hooks**:优先通过 `scripts/install_git_hooks.sh` 安装,不要手动维护 `core.hooksPath`

## 架构分层

核心源码位于 `src/Undefined/`,主要模块如下:

| 目录 / 文件 | 职责 |
|---|---|
| `ai/` | AI 运行时核心:`client.py`(主入口)、`llm.py`(模型请求)、`prompts.py`(Prompt 构建)、`tooling.py`(工具管理)、`multimodal.py`(多模态)、`model_selector.py`(模型选择)、`summaries.py`(短期总结) |
| `services/` | 运行服务:`ai_coordinator.py`(协调器+队列投递)、`queue_manager.py`(车站-列车队列)、`message_batcher.py`(同 sender 短时合并)、`command.py`(命令分发)、`model_pool.py`(多模型池)、`security.py`(安全防护) |
| `skills/` | 热重载技能系统:`tools/`(原子工具)、`toolsets/`(按域分组工具)、`agents/`(智能体)、`commands/`(斜杠指令)、`anthropic_skills/`(SKILL.md 知识注入) |
| `cognitive/` | 认知记忆:`service.py`(入口)、`vector_store.py`(ChromaDB)、`historian.py`(后台史官异步改写+侧写合并)、`job_queue.py`、`profile_storage.py` |
| `memes/` | 表情包库:两阶段 AI 管线、异步处理队列、SQLite 元数据、ChromaDB 向量检索 |
| `knowledge/` | 本地知识库:文本切分、嵌入、重排、ChromaDB 存储与运行时检索 |
| `arxiv/` | arXiv 论文解析、元信息获取、PDF 下载与发送 |
| `bilibili/` | B 站链接/BV 解析、视频下载与发送 |
| `github/` | GitHub public 仓库解析、API 获取与图片卡片发送 |
| `api/` | Runtime API / Management API 相关服务;路由拆分在 `api/routes/`,包含 `chat`、`cognitive`、`health`、`memes`、`memory`、`naga`、`system`、`tools` |
| `webui/` | aiohttp 管理控制台;路由拆分在 `webui/routes/`,覆盖配置、日志、运行态、表情包与系统管理 |
| `mcp/` | MCP 工具注册、连接与转换 |
| `automations/` | 条件驱动的轻量工作流:`AutomationService` 运行时、start 匹配、@ 消费、DAG / 分支 / 循环、旧定时任务迁移 |
| `config/` | 配置系统:`loader.py`(TOML 解析+类型化)、`models.py`(数据模型)、`hot_reload.py`(热更新) |
| `attachments.py` | 富媒体/附件注册、作用域隔离、`<attachment uid="..."/>` 统一标签(`<pic>` 向后兼容)渲染 |
| `utils/` | `io.py`(异步 IO)、`history.py`(消息历史)、`paths.py`、`logging.py`、`sender.py` 等通用能力 |

### 消息处理流程

```text
OneBot WebSocket → onebot.py → handlers.py
  → 附件登记 / 访问控制 / 表情包入库
  → SecurityService(注入检测)
  → CommandDispatcher(斜杠指令,命中即结束后续处理)
  → skills/pipelines(Bilibili / arXiv / GitHub 并行自动提取)
  → Automations(pipeline 后接入;consume_ai_loop 时 await 并拦截对应 AI,否则后台执行并立刻放行;发生在 MessageBatcher 之前)
  → MessageBatcher(同 sender 短时合并;拍一拍/buffer 内 @bot 旁路)
  → AICoordinator → QueueManager(按模型隔离, 4 级优先级)
  → AIClient → LLM API / Skills / MCP

Management / Runtime 请求 → webui/app.py 或 api/app.py → routes/*
  → 配置、日志、记忆、工具调用、AI Chat 等能力
```

### 多模型池分工

- `ai/model_selector.py` — 纯选择逻辑(策略 / 偏好 / compare 状态),无 IO 副作用
- `services/model_pool.py` — 私聊交互服务,持有 ai/config/sender,处理 `/compare`、`选X`、`select_chat_config`
- `services/ai_coordinator.py` — 持有 `ModelPoolService`(`self.model_pool`),私聊队列投递时通过它选模型
- `handlers.py` — 私聊消息只调 `await self.ai_coordinator.model_pool.handle_private_message(user_id, text)`,不直接感知选择细节
- `skills/agents/runner.py` — Agent 直接调用 `ai_client.model_selector.select_agent_config(...)`,无 `hasattr`
- 默认关闭:`models.pool_enabled = false`;群聊不参与多模型,始终走主模型

### Skills 系统

- **热重载**:自动扫描 `skills/` 下 `config.json` / `handler.py` 变更并重载
- **自动处理管线**:`skills/pipelines/<name>/` 使用 `config.json + handler.py`,在斜杠命令之后、AI 自动回复之前并行检测/处理;命令输入和命令输出要写入历史,管线输出通过 `MessageSender` 自动写历史并登记本地媒体/文件附件 UID。
- **Skills handler 不引用 `skills/` 外的本地模块**,依赖通过 context 注入
- **Agent 标准结构**:`config.json` + `handler.py` + `prompt.md` + `intro.md` + `mcp.json`(可选) + `anthropic_skills/`(可选)
- **共享授权**:通过 `callable.json` 将工具或 Agent 白名单暴露给其他 Agent
- **Anthropic Skills**:支持 SKILL.md 目录结构与渐进式披露

#### 关键工具说明

- `group.get_member_info`:支持 `brief` 参数(默认 false)。当 `brief=true` 时只返回当前昵称(群名片优先,否则 QQ 昵称),便于快速称呼用户。
- `group.get_avatar`:接受 `user_id` 与可选 `size`(40/100/140/640),下载 QQ 头像并注册为附件,返回 `<attachment uid="..."/>` 标签。
- 统一附件标签:推荐使用 `<attachment uid="..."/>`,系统根据 UID 前缀(`pic_`/`file_`)自动区分图片与文件。旧 `<pic uid="..."/>` 语法向后兼容。
- 远程附件默认按 `[attachments].remote_download_max_size_mb` 限制下载缓存;超过上限或配置为 `0` 时只登记 URL 引用(`source_ref`),避免大文件造成磁盘和延迟压力。

### 队列模型

车站-列车模型(QueueManager):按模型隔离队列组,4 级优先级(超管 > 私聊 > @提及 > 普通群聊),普通队列自动修剪保留最新 2 条,非阻塞按节奏发车(默认 1Hz)。

### 同 sender 短时消息合并(MessageBatcher)

同一 sender 在 `[message_batcher].window_seconds` 内连续发送的多条消息会合并到同一轮 AI 调用,AI 一次性看到全部 `<message>` 块自行识别“独立请求/修正/打断”。拍一拍永远旁路立即处理;群聊已有 buffer 时新到的 @bot 也单独立即处理;首条 @bot 进入 buffer 时整批走 mention 队列。可选开启投机预发送 `pre_send_seconds < window_seconds`:静默到该阈值先把 batch 提前发给 LLM 抢时间,新消息在 inflight 未发出任何消息时可取消该调用。`enabled=false` 行为退化回旧版。详见 [docs/message-batching.md](docs/message-batching.md)。

### 存储与数据

- `data/history/` — 消息历史(`group_*.json` / `private_*.json`,默认 10000 条,可通过 `[history]` 调整,0 = 无限)
- `data/cognitive/` — ChromaDB 向量库 + `profiles/` 侧写 + `queues/` 任务队列
- `data/memes/` — 表情包库(`blobs/` 原图、`previews/` 预览图、`memes.sqlite3` 元数据、`chromadb/` 向量检索)
- `data/cache/` — 附件、下载、渲染与 WebUI 文件缓存
- `data/attachment_registry.json` — 附件注册表
- `data/memory.json` — 置顶备忘录(500 条上限)
- `data/end_summaries.json` — 短期总结存储
- `data/automations.json` — 自动化工作流存储。启动时若无此文件但存在旧 `scheduled_tasks.json`,则读取并转为新格式写入,不删除旧文件、不双写
- `data/faq/` — FAQ 存储
- `data/token_usage.jsonl` — Token 统计(自动 gzip 归档;流式调用可含可选 `ttft_seconds` / `tokens_per_second`)
- `knowledge/` — 本地知识库数据目录(`texts/`、`intro.md`、`chroma/` 等)
- `res/prompts/` — 系统提示词模板

## 提示词约定

系统提示词(`res/prompts/undefined.xml`)包含用户识别规则:
- 以 QQ 号(`sender_id`)为用户唯一标识,昵称可能随时变动
- 称呼用户时使用当前最新昵称,不确定时可调用 `group.get_member_info(brief=true)` 查询
- 认知记忆(`end.observations`)只写值得日后检索的写实实质事实(宁缺毋滥);必须含稳定实体标识,用户观察格式如:“QQ号12345678(昵称张三)做了某事”

## 配置系统

- 主配置:`config.toml`(从 `config.toml.example` 复制)
- 配置热更新:`config.reload()` 触发回调
- MCP 配置:`config/mcp.json`(全局)或 `agents/<name>/mcp.json`(Agent 私有)
- 脚本 `scripts/sync_config_template.py` 可将新配置项同步到已有 `config.toml`

## 运维脚本

- `scripts/install_git_hooks.sh` — 安装 Git hooks(设置 `.githooks`)
- `scripts/sync_config_template.py` — 同步配置模板新增项(支持 `--dry-run`)
- `scripts/reembed_cognitive.py` — 更换嵌入模型后重建认知向量库(支持 `--events-only` / `--profiles-only` / `--batch-size` / `--dry-run`)
- `scripts/bump_version.py` — 同步更新 Python / console / Tauri 版本号,并可选择连同 lock 文件一起更新

## 跨平台控制台

`apps/undefined-console/` 是基于 Tauri v2 + TypeScript + Vite 的管理客户端,支持 Windows / macOS / Linux / Android,连接同一套 Management API 与 Runtime API。

`apps/undefined-chat/` 是原生优先的 WebChat 客户端,基于 Tauri v2 + React,直接连接 Runtime API,面向长期挂起、桌面/移动端聊天使用场景。采用莫兰迪橙色系(Morandi Orange)设计,与 WebUI 保持视觉一致性。它移植 WebUI webchat 的核心聊天功能,并在事件流(SSE 优先 + JSON fallback 双通道)、桌面快捷键、图片查看(缩放/旋转/全屏)、安全存储(系统 keyring / Android Keystore)等方面做了原生增强;HTML 采用 sanitize 内联渲染 + 独立预览窗口隔离运行的双层策略。详见 [docs/undefined-chat.md](docs/undefined-chat.md)。