Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -850,20 +850,25 @@ description: 从 PDF 文件中提取文本和表格,填写表单。当用户
| **思考链** | `*.thinking_enabled` | 思维链支持 |
| **思维链兼容** | `*.thinking_tool_call_compat` | 思维链 + 工具调用兼容 |
| **WebUI** | `webui.url`, `webui.port`, `webui.password` | 配置控制台 |
| **微信 iLink** | `weixin.enabled`, `weixin.state_dir`, `weixin.*_seconds` | 微信私聊帐号生命周期、重试与本地状态 |

## 十、架构详解

### 8层架构分层

1. **外部实体层**:用户、管理员、OneBot 协议端 (NapCat/Lagrange.Core)、大模型 API 服务商
2. **核心入口层**:main.py 启动入口、配置管理器 (config/loader.py + parsers/ + load_sections/)、热更新应用器 (config/hot_reload.py)、OneBotClient (onebot/ + onebot.py shim)、RequestContext (context.py)、Runtime API Server (api/app.py → api/routes/ 路由子模块,含 naga/ 子包)
3. **消息处理层**:MessageHandler (`handlers/`)、SecurityService (security.py)、CommandDispatcher (services/command.py + commands/ mixins)、MessageBatcher (services/message_batcher/)、AICoordinator (services/coordinator/ + ai_coordinator.py 门面)、QueueManager (queue_manager.py)、自动处理管线 (skills/pipelines/)、Bilibili/arXiv/GitHub 解析与发送模块
2. **核心入口层**:main.py 启动入口、配置管理器 (config/loader.py + parsers/ + load_sections/)、热更新应用器 (config/hot_reload.py)、OneBotClient (onebot/ + onebot.py shim)、WeixinService (`weixin/` + `weixin-ilink-client`)、RequestContext (context.py)、Runtime API Server (api/app.py → api/routes/ 路由子模块,含 naga/ 子包)
3. **消息处理层**:MessageHandler (`handlers/`)、统一 DeliveryAddress 路由 (`utils/message_targets.py`)、SecurityService (security.py)、CommandDispatcher (services/command.py + commands/ mixins)、MessageBatcher (services/message_batcher/)、AICoordinator (services/coordinator/ + ai_coordinator.py 门面)、QueueManager (queue_manager.py)、自动处理管线 (skills/pipelines/)、Bilibili/arXiv/GitHub 解析与发送模块
自动提取由 `PipelineRegistry` 并行检测、并行处理全部命中的管线;发送结果写入历史后继续进入 AI 自动回复。
4. **AI 核心能力层**:AIClient (ai/client/ + client.py shim)、PromptBuilder (ai/prompts/ + prompts.py shim)、ModelRequester (ai/llm/ + llm.py shim)、ToolManager (tooling.py)、MultimodalAnalyzer (ai/multimodal/ + multimodal.py shim)、SummaryService (summaries.py)、TokenCounter (tokens.py)
5. **存储与上下文层**:MessageHistoryManager (utils/history.py, 10000条限制)、MemoryStorage (memory.py, 置顶备忘录, 500条上限)、EndSummaryStorage、CognitiveService + JobQueue + HistorianWorker + VectorStore + ProfileStorage、MemeService + MemeWorker + MemeStore + MemeVectorStore (表情包库)、FAQStorage、ScheduledTaskStorage、TokenUsageStorage (自动归档)
6. **技能系统层**:ToolRegistry (registry.py)、AgentRegistry、7个 Agents、11类 Toolsets
7. **异步 IO 层**:统一 IO 工具 (utils/io.py),包含 write_json、read_json、append_line、跨平台文件锁 (flock/msvcrt)
8. **数据持久化层**:历史数据目录、FAQ 目录、Token 归档目录、记忆文件、总结文件、定时任务文件
8. **数据持久化层**:历史数据目录、FAQ 目录、Token 归档目录、记忆文件、总结文件、定时任务文件、微信绑定/游标/隔离/审计状态

### 微信 iLink 路由边界

微信接入由主进程独立管理,不依赖 OneBot 是否在线。`WeixinService` 先校验帐号与 peer,再把已绑定来源映射为逻辑 QQ 私聊交给 `MessageHandler`;未知来源在写历史或调用 AI 之前进入隔离存储。`DeliveryAddress` 将逻辑身份与物理通道分离:`qq:<id>` 和 `wechat:<id>` 可共享同一个用户历史、认知记忆与权限,但发送器、消息合并 scope 和 transport 元数据保持通道隔离。定时任务同样持久化规范 `address`,旧 `target_type + target_id` 在加载时转换为 `group:` 或 `qq:` 地址。

### "车站-列车" 队列模型

Expand Down Expand Up @@ -909,6 +914,6 @@ description: 从 PDF 文件中提取文本和表格,填写表单。当用户

---

**架构图版本**: v3.4.1
**更新日期**: 2026-05-10
**架构图版本**: v3.8.1
**更新日期**: 2026-07-14
**基于代码版本**: 最新 main 分支
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## v3.9.0 微信 iLink 私聊接入与统一消息路由

本版本将 Undefined 的实时会话能力从 QQ 扩展到微信,并围绕“逻辑身份与物理通道分离”重整私聊投递模型。微信用户可以复用既有 QQ 身份下的权限、历史、认知记忆和模型偏好,同时让回复、定时任务与媒体始终返回消息实际到达的通道;配套的登录管理、安全隔离和消息语义也形成了可完整使用的微信私聊链路。

- 微信私聊成为一等会话通道。Undefined 可直接管理 ClawBot / iLink 扫码登录和消息收发,无需 OneBot 在线或安装 OpenClaw 微信插件;文本、Markdown、图片、文件、视频、语音转写、输入状态及长消息均纳入现有对话流程。底层协议能力由独立的 MIT SDK `weixin-ilink-client` 承载,主项目继续负责身份、历史、权限和业务编排。
- 统一跨通道身份与投递。微信帐号可绑定逻辑 QQ 号,并通过规范化地址区分 QQ 私聊、微信私聊与群聊;模型选择、命令、自动管线、表情包、附件、消息合并和定时任务共享同一套身份能力,但始终按照当前物理路由发送,避免 QQ 与微信之间串线。原有目标参数继续兼容,并在与规范地址并用时校验一致性。
- 补齐完整消息语义。微信入站内容保留 Markdown 和 `<`、`>`、`&` 等字符的字面含义,混合文本与媒体在全量预检后按原始顺序发送,本地媒体路径不会泄露到正文;Bot 可通过统一工具把音频附件显式发送为 QQ 或微信原生语音,同时保留 WAV 等普通文件附件的下载语义;引用消息支持接收、历史恢复和同路由原生回复。微信转发会优先通过 SDK 的有界并发上传与保序 `item_list` 多项目消息投递,并在上游明确拒绝时回退逐段发送,附件登记及历史记录继续遵循现有消息体系的边界。
- 提供可运营的帐号管理与安全边界。WebUI 新增微信入口和完整的扫码绑定流程,Runtime / Management API 覆盖登录、刷新、验证码、启停、改绑、解绑、隔离与审计;一对一绑定、特权身份二次确认、未知来源隔离、敏感状态保护、二维码生命周期管理和异常退避恢复共同保证长期运行。同步补齐双语配置说明、架构与使用文档以及相关回归测试。
- 优化长期运行后的统计命令。`/stats` 按请求时间范围流式扫描 Token 记录,并通过归档时间边界跳过无关文件;图表在线程中串行渲染到请求独立目录,私聊优先整组投递,失败时保留纯文本摘要,避免大历史阻塞事件循环、缓存相互覆盖或媒体上传失败后完全无响应。

---

## v3.8.1 可配置长图渲染与浏览器运行时回退

本版本为 AI 渲染工具新增适合长内容发送的长图布局,可精确控制成图宽度与内边距;同时完善 Playwright 浏览器选择,在缺少内置浏览器时可使用已配置或系统安装的 Chrome / Chromium 完成渲染。
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<td width="100%" valign="top">
<div align="center">
<h1>Undefined</h1>
<em>QQ bot platform with cognitive memory architecture and multi-agent Skills, via OneBot V11.</em>
<em>QQ and WeChat bot platform with cognitive memory architecture and multi-agent Skills.</em>
<br/><br/>
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/Python-3.11--3.13-blue.svg" alt="Python"></a>
<a href="https://docs.astral.sh/uv/"><img src="https://img.shields.io/badge/uv-auto%20python%20manager-6a5acd.svg" alt="uv"></a>
Expand All @@ -15,7 +15,7 @@
</div>
<h3>项目简介</h3>
<p>
<strong>Undefined</strong> 是一个基于 Python 异步架构的高性能 QQ 机器人平台,搭载<strong>认知记忆架构</strong>,采用自研 <strong>Skills</strong> 系统,内置多个智能 Agent,支持代码分析、网络搜索、娱乐互动等多模态能力,并提供 <strong>WebUI</strong> 在线管理,以及可连接同一管理服务的 <strong>跨平台 App</strong>。
<strong>Undefined</strong> 是一个基于 Python 异步架构的高性能机器人平台,以 OneBot V11 接入 QQ,并可通过微信 ClawBot/iLink 接入微信私聊。项目搭载<strong>认知记忆架构</strong>,采用自研 <strong>Skills</strong> 系统,内置多个智能 Agent,支持代码分析、网络搜索、娱乐互动等多模态能力,并提供 <strong>WebUI</strong> 在线管理,以及可连接同一管理服务的 <strong>跨平台 App</strong>。
</p>
</td>
</tr>
Expand Down Expand Up @@ -67,6 +67,7 @@ Console 和 Chat 都需要连接到已经运行的 Undefined 服务。首次部
- **置顶备忘录**(`memory.*`):AI 自身的置顶提醒(自我约束、待办事项),每轮固定注入,支持增删改查
详见 [认知记忆文档](docs/cognitive-memory.md)。
- **Management-first WebUI**:继续保留 `uv run Undefined-webui` 一键入口;即使 `config.toml` 缺失或未配完,也能先进入管理态补配置、看日志、校验并启动 Bot。
- **微信 ClawBot/iLink 私聊**:可将一个微信帐号映射为逻辑 QQ 身份,共享权限、私聊历史、认知记忆和模型偏好,同时用 `wechat:<QQ号>` 保持物理回复路由隔离;支持 Markdown、图片、文件、视频、原生语音、同一物理会话内的引用收发,以及保序多项目消息模拟的转发投递,并带二维码管理、媒体上传重试、未知来源隔离、高权限身份二次确认和审计。无需安装 OpenClaw 或微信插件;发送原生语音需要系统提供 FFmpeg。详见 [微信 iLink 接入](docs/wechat-ilink.md)。
- **远程管理 + 多端客户端**:浏览器版 WebUI、跨平台 Console(管理客户端)和原生优先 Undefined Chat(聊天客户端)共享同一套 Management / Runtime 服务,支持远程管理,并覆盖 `Windows / macOS / Linux / Android` 发布链路。
- **Undefined Console**:基于 Tauri v2 的管理客户端,完整管理功能
- **Undefined Chat**:基于 Tauri v2 + React 19 的原生优先聊天客户端,采用莫兰迪橙色系设计,移植 WebUI webchat 的核心聊天能力并做原生增强:中英双语运行时切换(i18n)、平台抽象层(按真实平台区分桌面/移动布局)、桌面快捷键、系统凭据存储、HTML 正文 sanitize 内联渲染 + 独立预览窗口隔离运行、Android(非 iOS)横屏/平板适配。iOS 暂不作为发布平台
Expand Down Expand Up @@ -121,6 +122,7 @@ Undefined 的功能极为丰富,为了让本页面不过于臃肿,我们将
- 🔄 **[多模型并发竞技](docs/multi-model.md)**:配置多个异构模型,让它们并行运算、同台 PK,从中择优响应。
- ⌨️ **[命令系统与斜杠指令](docs/slash-commands.md)**:查阅所有斜杠指令(`/*`)的详细用法,并学习如何轻松扩展你自己的指令系统。
- 🌐 **[Runtime API 与 OpenAPI](docs/openapi.md)**:主进程 Runtime API、鉴权、探针、记忆/侧写查询和运行态集成说明。
- 💬 **[微信 ClawBot / iLink 接入](docs/wechat-ilink.md)**:逻辑 QQ 身份映射、`wechat:<QQ号>` 路由、扫码管理、隔离与媒体能力说明。
- 💬 **[Undefined Chat](docs/undefined-chat.md)**:原生优先 WebChat 客户端说明——莫兰迪橙色系设计、功能对等表、平台差异(桌面快捷键/独立窗口、Android 生命周期)、Runtime 真源、SSE/JSON fallback、安全存储、附件上传和 HTML 预览隔离。
- 🏗️ **[构建指南](docs/build.md)**:Python 包、WebUI、跨平台 App、Android 与 Release 工作流的构建说明。
- 🔧 **[运维脚本](scripts/README.md)**:嵌入模型更换后的向量库重嵌入等维护工具。
Expand Down
4 changes: 2 additions & 2 deletions apps/undefined-chat/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-chat/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "undefined-chat",
"private": true,
"version": "3.8.1",
"version": "3.9.0",
"type": "module",
"scripts": {
"tauri": "tauri",
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-chat/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-chat/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "undefined_chat"
version = "3.8.1"
version = "3.9.0"
description = "Undefined native chat client"
authors = ["Undefined contributors"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-chat/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Undefined Chat",
"version": "3.8.1",
"version": "3.9.0",
"identifier": "com.undefined.chat",
"build": {
"beforeDevCommand": "npm run dev",
Expand Down
4 changes: 2 additions & 2 deletions apps/undefined-console/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-console/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "undefined-console",
"private": true,
"version": "3.8.1",
"version": "3.9.0",
"type": "module",
"scripts": {
"tauri": "tauri",
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-console/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/undefined-console/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "undefined_console"
version = "3.8.1"
version = "3.9.0"
description = "Undefined cross-platform management console"
authors = ["Undefined contributors"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion apps/undefined-console/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Undefined Console",
"version": "3.8.1",
"version": "3.9.0",
"identifier": "com.undefined.console",
"build": {
"beforeDevCommand": "npm run dev",
Expand Down
56 changes: 56 additions & 0 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,62 @@ autostart_bot = false
# en: Check GitHub Releases for updates in the background whenever WebUI is opened.
check_updates = true

# zh: 微信 ClawBot/iLink 私聊接入。凭据与游标仅写入 state_dir,不写入本配置。
# zh: 关闭时不会创建网络连接;二维码登录只能从管理界面显式发起。
# en: WeChat ClawBot/iLink private-chat integration. Credentials and cursors are
# en: stored under state_dir and never in this configuration file.
# en: No network connection is created when disabled; QR-code login can only be
# en: started explicitly from the management interface.
[weixin]
# zh: 是否启用微信 iLink 接入。关闭时不建立网络连接。
# en: Enable the WeChat iLink integration. No network connection is made when disabled.
enabled = false
# zh: 敏感凭据、游标、绑定、隔离记录和审计记录的存储目录。
# en: Directory for sensitive credentials, cursors, bindings, quarantined peers, and audit records.
state_dir = "data/weixin"
# zh: 单次消息长轮询的超时时间(秒)。
# en: Timeout for each message long-poll request, in seconds.
long_poll_timeout_seconds = 35.0
# zh: 上游提示 token 失效后暂停重试的时间(秒)。
# en: Pause before retrying after the upstream reports a stale token, in seconds.
stale_token_pause_seconds = 3600.0
# zh: 普通请求失败后的重试间隔(秒)。
# en: Retry delay after an ordinary request failure, in seconds.
retry_delay_seconds = 2.0
# zh: 连续失败达到阈值后的退避时间(秒)。
# en: Backoff duration after consecutive failures reach the threshold, in seconds.
failure_backoff_seconds = 30.0
# zh: 进入长退避的连续失败次数阈值。
# en: Consecutive failure threshold for entering the longer backoff.
failures_before_backoff = 3
# zh: 单个入站或出站媒体文件的大小上限(MB)。
# en: Maximum size of one inbound or outbound media file, in MB.
media_max_size_mb = 100
# zh: 单个媒体上传请求遇到临时网络或服务端错误时的最大尝试次数(1-10)。
# en: Maximum attempts for one media upload after transient network or server failures (1-10).
media_upload_attempts = 3
# zh: 单条多项目消息并发上传媒体的上限(1-8)。
# en: Maximum concurrent media uploads for one multi-item message (1-8).
media_upload_concurrency = 3
# zh: 是否优先用 iLink 多项目消息模拟微信合并转发;上游明确拒绝时自动回退为逐段发送。
# en: Prefer iLink multi-item messages for WeChat forward emulation; fall back to sequential sends on explicit rejection.
multi_item_messages_enabled = true
# zh: 单次 iLink 多项目消息最多包含的项目数(1-20);超出时保持顺序分批。
# en: Maximum items in one iLink multi-item message (1-20); larger forwards are split in order.
multi_item_max_items = 10
# zh: 二维码登录会话的有效期(秒)。
# en: Lifetime of a QR-code login session, in seconds.
login_session_ttl_seconds = 300.0
# zh: 绑定管理员或超级管理员身份时,二次确认 token 的有效期(秒)。
# en: Lifetime of a confirmation token when binding an admin or superadmin identity, in seconds.
privileged_confirmation_ttl_seconds = 300.0
# zh: 最多保留的未知来源隔离记录数。
# en: Maximum number of quarantined unknown-peer records to retain.
pending_max_records = 100
# zh: 最多保留的帐号管理审计记录数。
# en: Maximum number of account-management audit records to retain.
audit_max_records = 1000

# zh: 主进程 Runtime API(供 WebUI/外部系统读取探针、记忆检索、AI Chat 使用)。
# en: Runtime API in the main process (for WebUI/external integrations: probes, memory queries, AI chat).
[api]
Expand Down
4 changes: 3 additions & 1 deletion docs/access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ superadmin_bypass_allowlist = true

因此,配置可统一约束“收消息”和“发消息”。

微信 iLink 私聊按其绑定的逻辑 QQ 号参与 `allowed_private_ids` / `blocked_private_ids` 判定。绑定不会绕过名单;若逻辑 QQ 是 superadmin,则继续遵循本页两个 superadmin 绕过开关。未知微信来源会在访问控制和消息处理之前隔离,详见 [微信 iLink 接入](wechat-ilink.md)。

## 与 Naga 会话策略的关系

全局 `[access]` 控制机器人整体能否收发消息。Naga 另有独立的会话策略(`[naga].mode` + 群/私聊名单),用于在 Naga 总闸打开后,按群/私聊决定是否启用 NagaAgent 提示词/工具与外部网关(`/naga`、绑定、回调投递)。模式名与本节相同(`off` / `blacklist` / `allowlist`),但 **Naga 的 allowlist 空名单为 fail closed(拒绝全部)**,与本节「空名单不限制」不同;详见 [configuration.md §4.27](configuration.md)。
全局 `[access]` 控制机器人整体能否收发消息。Naga 另有独立的会话策略(`[naga].mode` + 群/私聊名单),用于在 Naga 总闸打开后,按群/私聊决定是否启用 NagaAgent 提示词/工具与外部网关(`/naga`、绑定、回调投递)。模式名与本节相同(`off` / `blacklist` / `allowlist`),但 **Naga 的 allowlist 空名单为 fail closed(拒绝全部)**,与本节「空名单不限制」不同;详见 [configuration.md §4.28](configuration.md)。
Loading
Loading