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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Repository Guidelines

## Project Structure & Module Organization
`src/Undefined/` contains the main runtime package. Core areas include `ai/`, `services/`, `skills/`, `cognitive/`, `memes/`, `knowledge/`, `api/`, `webui/`, `config/`, `mcp/`, and `automations/` (`AutomationService` runtime plus JSON storage); media-facing integrations live in `arxiv/`, `bilibili/`, `github/`, and `attachments/`. `src/Undefined/deploy/` is the containerized one-shot deployment path (`uv run deploy`, templates under `deploy/templates/`) and does not take part in runtime. `tests/` holds the pytest suite.
`src/Undefined/` contains the main runtime package. Core areas include `ai/`, `services/`, `skills/`, `cognitive/`, `memes/`, `knowledge/`, `api/`, `webui/`, `config/`, `mcp/`, and `automations/` (`AutomationService` runtime plus JSON storage); media-facing integrations live in `arxiv/`, `bilibili/`, `github/`, `jm/`, and `attachments/`. `src/Undefined/deploy/` is the containerized one-shot deployment path (`uv run deploy`, templates under `deploy/templates/`) and does not take part in runtime. `tests/` holds the pytest suite.

> Single source of truth for the module-level directory tree: [docs/development.md](docs/development.md). This file, `CLAUDE.md`, and `ARCHITECTURE.md` only keep overviews — update the tree first when the layout changes. `apps/undefined-console/` is the Tauri + Vite management client and `apps/undefined-chat/` is the native-first Tauri + React 19 chat client (both connect to the same Management/Runtime services), while `code/NagaAgent/` remains a git submodule and should be updated deliberately, with upstream syncs kept separate from repo-local changes. Runtime and generated state primarily lives under `data/`, `logs/`, and `dist/`; the root `knowledge/` directory stores knowledge-base data rather than application code. Prefer editing source files and docs over generated outputs unless the task is explicitly about runtime state.

Expand Down
16 changes: 14 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ graph TB
GitHubSender["sender.py<br/>图片卡片发送<br/>• 头像 • 简介 • 统计"]
end

subgraph JmModule["JM 模块 (jm/)"]
JmParser["parser.py<br/>车号解析<br/>• JM+数字 • 禁漫链接 • 分享卡片"]
JmDownloader["downloader.py<br/>整本下载合成<br/>• jmcpy 逐章下载<br/>• 合并为加密 PDF"]
JmSender["sender.py<br/>合并转发发送<br/>• 信息/密码/PDF • 失败回退"]
end

subgraph SecurityLayer["安全防线 (services/)"]
SecurityService["SecurityService<br/>安全服务<br/>• 注入攻击检测<br/>• 速率限制<br/>[security.py]"]
InjectionAgent["InjectionResponseAgent<br/>注入响应生成<br/>[injection_response_agent.py]"]
Expand Down Expand Up @@ -228,8 +234,13 @@ graph TB
GitHubParser -->|"仓库ID"| GitHubClient
GitHubClient -->|"public仓库信息"| GitHubSender
GitHubSender -->|"发送图片卡片"| OneBotClient

MessageHandler -->|"2.7 自动化"| AutomationService

MessageHandler -->|"2.7 非命令自动管线"| JmParser
JmParser -->|"车号"| JmDownloader
JmDownloader -->|"加密 PDF"| JmSender
JmSender -->|"发送合并转发"| OneBotClient

MessageHandler -->|"2.8 自动化"| AutomationService
AutomationService -->|"读写"| AutomationStorage
AutomationStorage -->|"异步读写"| IOUtils

Expand Down Expand Up @@ -850,6 +861,7 @@ description: 从 PDF 文件中提取文本和表格,填写表单。当用户
| **Bilibili** | `bilibili.auto_extract_enabled`, `bilibili.cookie`, `bilibili.prefer_quality` | B站视频自动提取与下载 |
| **arXiv** | `arxiv.auto_extract_enabled`, `arxiv.max_file_size`, `arxiv.auto_extract_max_items` | arXiv 论文自动提取、搜索与 PDF 发送 |
| **GitHub** | `github.auto_extract_enabled`, `github.request_timeout_seconds`, `github.request_retries`, `github.auto_extract_max_items` | GitHub public 仓库自动提取与图片卡片发送 |
| **JM(禁漫)** | `jm.auto_extract_enabled`, `jm.max_file_size`, `jm.max_chapters`, `jm.auto_extract_max_items` | JM 车号自动提取、整本加密 PDF 与合并转发 |
| **思考链** | `*.thinking_enabled` | 思维链支持 |
| **思维链兼容** | `*.thinking_tool_call_compat` | 思维链 + 工具调用兼容 |
| **WebUI** | `webui.url`, `webui.port`, `webui.password` | 配置控制台 |
Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## v3.18.0 JM 漫画自动提取

本版本新增禁漫自动提取管线:消息里出现 `JM` 车号或禁漫链接时,自动获取本子详情、把全部章节合成为一个带密码的 PDF,以「本子信息 / 解密密码 / PDF 文件」三节点合并转发发送(文件只放在转发里,群聊下同时进入群文件列表),并新增与 `arxiv_paper` 同构的 `jm_book` 工具供 AI 按需取详情或附件。功能默认关闭,密码随机生成且不写进历史。

- 新增 `jm` 自动处理管线(`src/Undefined/skills/pipelines/jm/`,`order = 12`)与 `src/Undefined/jm/`(车号解析、jmcpy 客户端设置、整本下载合成、合并转发发送),依赖新增并固定到 `jmcpy>=0.1.3`。
- 触发规则:`JM` 前缀加 5–8 位车号(`JM1114751` / `jm 1114751` / `jm:1114751` / `jm-1114751`,大小写不敏感),以及主机名含 `18comic` 或 `jmcomic` 的链接(`/album/<id>`、`/photo/<id>`、`?id=<id>`),QQ 分享卡片里的链接同样解析,车号与链接混排时按原文出现顺序取(默认只取第一个);分享卡片结构异常(`data` 不是对象、JSON 损坏)只跳过该段,不影响同一条消息里其它段落的检测。前缀必须落在词边界上(`xxjm1234567`、`t.me/jm1234567`、`video_jm1234567.mp4` 都不触发),数字后不跟数字(9 位以上不会被截成 8 位);裸数字不触发,避免群号、时间戳误报。
- 下载与合成:按章节 `order` 顺序逐章下载(`[jm].max_chapters` 可限制),`decode=False` 取服务端原始字节无损落盘,自己解扰后每页只编码一次 JPEG(`[jm].image_quality`,色度 4:4:4)并直接作为 PDF 图像数据;页尺寸统一按 `[jm].pdf_dpi` 换算(页宽 = 像素宽 ÷ DPI × 72),页像素始终不缩放,画质上限由站点源图分辨率决定。不再复用 `jmcpy.imaging.write_pdf`:jmcpy 的下载 API 一章只能产出一个 PDF,而这里要把多个章节合进同一个文件;`jmcpy>=0.1.3` 修掉了追加页退回默认 72 DPI、同份 PDF 内页面尺寸不一致的问题,并把页内 JPEG 色度采样默认值改成 4:4:4。
- 逐页容错:单页解码失败只跳过该页并计入「下载失败 N 页」,其余页照常出 PDF,全部页失败才算空结果;动图(`.gif`)不做分块还原,与 jmcpy 的 `UNDECODED_SUFFIXES` 语义一致。
- 体积语义:`[jm].max_file_size` 先按各章节原始图片累计预判并停止下载,组装时再按**编码后字节**累计复核,超过即提前中止、PDF 不落盘;因此它只是近似内存上限(JPEG 重编码可能比源图更大)。超过上限或没有下到任何页面时只发信息与状态两个节点,不发密码与文件,且信息里不展示 PDF 大小。
- 发送结构固定为三个节点:本子信息(车号、标题、作者、章节数、标签、观看/点赞、页数、大小、简介预览,末行是可直接复制的 `JM<车号>`,不再输出站点链接)、PDF 解密密码(每次随机生成 8 位,字母表去掉 `0/O/1/l/I` 等形近字符)、PDF 文件(本地合成后随转发上传)。密码只出现在转发节点中,写入历史的摘要只说「密码见转发节点」,后续 AI 轮次不会复述密码。
- 文件只放在转发里,不额外发独立文件消息:群聊下 NapCat 会把它作为群文件上传(`isGroupFile`、`busid=102`,元素里带 `fileId` / `fileMd5` / `fileSha1`),节点里的文件可以直接下载,同一个 PDF 因此也会出现在群文件列表里。
- 投递语义:「投递结果未确认」(`delivery_uncertain`)与「文件传输错误」(`file_transfer_error`)不降级重发,直接上抛调用方——这两种情况下转发可能已经送达,换个 action 再发会造成真实重复投递;只有协议端明确拒绝才退化为「信息 + 密码两条普通消息 + 独立文件消息」(此时文件没有别的入口),该路径的密码消息写历史时只记「PDF 解密密码已单独发送」,上传也失败时再补一条不写历史的提示。
- 失败与资源:车号不存在或接口不可用时发送一行 `JM 提取失败:<原因>` 并记录异常类型与堆栈;整本下载跑在模块专用线程池(同时最多 2 本)而不是事件循环默认执行器;任务目录在成功、超限、空结果与下载抛异常四条路径上都会清理;被取消时线程仍在写盘,改为等它跑完再删,不留下残留原图或未加密 PDF。
- 新增 `jm_book` 工具(`src/Undefined/skills/tools/jm_book/`,与 `arxiv_paper` 同构):`output_mode=send`(默认,等价自动提取)、`uid`(只下载并注册**未加密** PDF 附件 UID,不发送消息,供 `file_analysis_agent` 用 `extract_pdf` / `describe_pdf_page` 解析)、`info`(只返回标题/作者/章节/标签/观看点赞/简介与链接,不下载);`callable.json` 把它共享给 `file_analysis_agent`,后者提示词里加了「车号/链接 → 先 `jm_book(output_mode="uid")`」的规则。
- 新增 `[jm]` 配置段:`auto_extract_enabled`(默认 `false`)、`use_proxy`、`auto_extract_group_ids` / `auto_extract_private_ids`(空时跟随全局 access)、`auto_extract_max_items`(默认 1,上限 5)、`max_file_size`、`max_chapters`、`pdf_dpi`、`image_quality`、`download_concurrency`、`request_timeout`、`image_timeout`、`session_dir`(jmcpy 配置目录,可复用已保存的登录态);`[jm].use_proxy` 支持环境变量 `JM_USE_PROXY`。

---

## v3.17.2 侧写有序合并

本版本修复群聊与用户侧写并发更新时的乱序覆盖:同一实体按史官任务入队顺序逐次合并,每次都基于前一次提交后的完整侧写;不同实体继续并发处理,QQ 与绑定的 iLink 私聊也遵循同一用户顺序。
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ bash scripts/install_git_hooks.sh
| `arxiv/` | arXiv 论文解析、元信息获取、PDF 下载与发送 |
| `bilibili/` | B 站链接/BV 解析、视频下载与发送 |
| `github/` | GitHub public 仓库解析、API 获取与图片卡片发送 |
| `jm/` | 禁漫(JM / 18comic)车号解析、整本 PDF 下载合成与加密合并转发 |
| `api/` | Runtime API / Management API 相关服务;路由拆分在 `api/routes/`,包含 `chat`、`cognitive`、`health`、`memes`、`memory`、`naga`、`system`、`tools` |
| `webui/` | aiohttp 管理控制台;路由拆分在 `webui/routes/`,覆盖配置、日志、运行态、表情包与系统管理 |
| `mcp/` | MCP 工具注册、连接与转换 |
Expand All @@ -86,7 +87,7 @@ OneBot WebSocket → onebot/ → handlers/
→ 附件登记 / 访问控制 / 表情包入库
→ SecurityService(注入检测)
→ CommandDispatcher(斜杠指令,命中即结束后续处理)
→ skills/pipelines(Bilibili / arXiv / GitHub 并行自动提取)
→ skills/pipelines(Bilibili / Douyin / arXiv / GitHub / JM 并行自动提取)
→ Automations(pipeline 后接入;consume_ai_loop 时 await 并拦截对应 AI,否则后台执行并立刻放行;发生在 MessageBatcher 之前)
→ MessageBatcher(同 sender 短时合并;拍一拍/buffer 内 @bot 旁路)
→ AICoordinator → QueueManager(按模型隔离, 6 条车道)
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
- **可选音乐工具集**:配置独立部署的 [lxmusic2api](https://github.com/69gg/lxmusic2api) 后,主 AI 可搜索歌曲/歌单、浏览热搜与排行榜、读取歌词/封面/评论、跨平台匹配并交付普通音频附件;完整 Track 通过任务内短引用流转,只暴露面向用户的高层 `music.*` 能力,不暴露下载作业生命周期接口。详见 [使用指南](docs/usage.md#音乐-music) 与 [配置说明](docs/configuration.md#4201-lxmusic2api-音乐服务)。
- **arXiv 论文提取、搜索与分析**:自动检测消息中的 arXiv 链接/标识并发送论文信息与 PDF;`arxiv_paper` 也可只返回 PDF 附件 UID,供 `file_analysis_agent` 做文本提取或指定页视觉分析;`arxiv_search` 负责论文检索。
- **GitHub 仓库卡片**:自动检测 GitHub 仓库链接或 `owner/repo` 仓库 ID,获取 public 仓库信息并发送简洁图片卡片,展示头像、简介、stars、forks、issues、contributors 等概览;API 与头像下载统一遵循 `[github].use_proxy`,头像以内联资源进入离线渲染器。
- **自动处理管线**:Bilibili、arXiv、GitHub 等自动提取统一运行在 `skills/pipelines` 中,斜杠命令优先级更高;命令输入/输出会写入历史,非命令消息会并行检测和处理命中管线,结果通过统一发送层写入历史并登记附件 UID 后再进入 AI 回复。远程大附件超过 `[attachments].remote_download_max_size_mb` 时只登记 URL 引用,避免无界下载和缓存膨胀。
- **禁漫(JM)本子提取**:自动检测 `JM`+车号或禁漫链接,下载全部章节并合成为一个 AES-256 加密 PDF,以「本子信息 / 解密密码 / PDF 文件」三节点合并转发发送(文件只在转发里,群聊下同时进入群文件列表),密码每次随机生成且不写入历史;`jm_book` 工具也可只返回本子信息或未加密 PDF 附件 UID,供 `file_analysis_agent` 解析。默认关闭,`[jm].auto_extract_enabled` 打开。详见 [配置说明](docs/configuration.md#4203-jm-禁漫自动提取)。
- **自动处理管线**:Bilibili、arXiv、GitHub、JM 等自动提取统一运行在 `skills/pipelines` 中,斜杠命令优先级更高;命令输入/输出会写入历史,非命令消息会并行检测和处理命中管线,结果通过统一发送层写入历史并登记附件 UID 后再进入 AI 回复。远程大附件超过 `[attachments].remote_download_max_size_mb` 时只登记 URL 引用,避免无界下载和缓存膨胀。
- **同 sender 短时消息合并**:默认开启。连续发的多条消息会合并到同一轮 AI 调用,AI 一次看到全部意图自行识别"独立请求/修正/打断";告别"画猫→改成狗"的重复触发与回复打架。主提示词按 batcher 的"当前输入批次"语义适配,关闭该功能可能导致连续补充/修正消息与提示词不匹配,需要单独适配。可选投机预发送让用户停顿时 LLM 提前开跑、新消息可在未发出回复前取消,进一步压低响应延迟。详见 [docs/message-batching.md](docs/message-batching.md)。
- **思维链支持**:支持开启思维链,提升复杂逻辑推理能力。
- **高并发架构**:基于 `asyncio` 全异步设计,支持多队列消息处理与工具并发执行,轻松应对高并发场景。
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.17.2",
"version": "3.18.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.17.2"
version = "3.18.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.17.2",
"version": "3.18.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.17.2",
"version": "3.18.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.17.2"
version = "3.18.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.17.2",
"version": "3.18.0",
"identifier": "com.undefined.console",
"build": {
"beforeDevCommand": "npm run dev",
Expand Down
Loading
Loading