diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bec5dbe..82c53ca0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,8 +39,9 @@ jobs: uses: actions/cache@v4 with: path: .mypy_cache - key: ${{ runner.os }}-mypy-${{ hashFiles('**/uv.lock') }} + key: ${{ runner.os }}-mypy-${{ hashFiles('**/uv.lock') }}-${{ hashFiles('src/**/*.py') }} restore-keys: | + ${{ runner.os }}-mypy-${{ hashFiles('**/uv.lock') }}- ${{ runner.os }}-mypy- - name: Run Mypy @@ -66,14 +67,15 @@ jobs: uses: actions/setup-node@v4 with: node-version: "22" + cache: "npm" + cache-dependency-path: apps/undefined-console/package-lock.json - - name: Cache npm and node_modules + - name: Cache node_modules + id: cache-node-modules uses: actions/cache@v4 with: - path: ~/.npm - key: ${{ runner.os }}-undefined-console-npm-${{ hashFiles('apps/undefined-console/package-lock.json', 'apps/undefined-console/package.json', 'apps/undefined-console/biome.json') }} - restore-keys: | - ${{ runner.os }}-undefined-console-npm- + path: apps/undefined-console/node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('apps/undefined-console/package-lock.json') }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable @@ -95,6 +97,7 @@ jobs: patchelf - name: Install app dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' working-directory: apps/undefined-console run: npm ci diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e654c9c..b2481699 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,8 +96,9 @@ jobs: uses: actions/cache@v4 with: path: .mypy_cache - key: ${{ runner.os }}-mypy-${{ hashFiles('**/uv.lock') }} + key: ${{ runner.os }}-mypy-${{ hashFiles('**/uv.lock') }}-${{ hashFiles('src/**/*.py') }} restore-keys: | + ${{ runner.os }}-mypy-${{ hashFiles('**/uv.lock') }}- ${{ runner.os }}-mypy- - name: Run Mypy @@ -132,14 +133,15 @@ jobs: uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} + cache: "npm" + cache-dependency-path: ${{ env.APP_DIR }}/package-lock.json - - name: Cache npm and node_modules + - name: Cache node_modules + id: cache-node-modules uses: actions/cache@v4 with: - path: ~/.npm - key: ${{ runner.os }}-undefined-console-npm-${{ hashFiles('apps/undefined-console/package-lock.json', 'apps/undefined-console/package.json', 'apps/undefined-console/biome.json') }} - restore-keys: | - ${{ runner.os }}-undefined-console-npm- + path: ${{ env.APP_DIR }}/node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('apps/undefined-console/package-lock.json') }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable @@ -161,6 +163,7 @@ jobs: patchelf - name: Install app dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' working-directory: ${{ env.APP_DIR }} run: npm ci @@ -200,14 +203,15 @@ jobs: uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} + cache: "npm" + cache-dependency-path: ${{ env.APP_DIR }}/package-lock.json - - name: Cache npm and node_modules + - name: Cache node_modules + id: cache-node-modules uses: actions/cache@v4 with: - path: ~/.npm - key: ${{ runner.os }}-undefined-console-npm-${{ hashFiles('apps/undefined-console/package-lock.json', 'apps/undefined-console/package.json', 'apps/undefined-console/biome.json') }} - restore-keys: | - ${{ runner.os }}-undefined-console-npm- + path: ${{ env.APP_DIR }}/node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('apps/undefined-console/package-lock.json') }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable @@ -233,6 +237,7 @@ jobs: patchelf - name: Install app dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' working-directory: ${{ env.APP_DIR }} run: npm ci @@ -302,12 +307,28 @@ jobs: if-no-files-found: error build-tauri-android: - name: Build Tauri Android + name: Build Tauri Android (${{ matrix.abi_label }}) runs-on: ubuntu-latest environment: release needs: - verify-python - verify-console + strategy: + fail-fast: false + matrix: + include: + - abi_label: arm64-v8a + tauri_target: aarch64 + rust_target: aarch64-linux-android + - abi_label: armeabi-v7a + tauri_target: armv7 + rust_target: armv7-linux-androideabi + - abi_label: x86 + tauri_target: i686 + rust_target: i686-linux-android + - abi_label: x86_64 + tauri_target: x86_64 + rust_target: x86_64-linux-android steps: - name: Checkout code uses: actions/checkout@v4 @@ -316,24 +337,25 @@ jobs: uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} + cache: "npm" + cache-dependency-path: ${{ env.APP_DIR }}/package-lock.json - - name: Cache npm and node_modules + - name: Cache node_modules + id: cache-node-modules uses: actions/cache@v4 with: - path: ~/.npm - key: ${{ runner.os }}-undefined-console-npm-${{ hashFiles('apps/undefined-console/package-lock.json', 'apps/undefined-console/package.json', 'apps/undefined-console/biome.json') }} - restore-keys: | - ${{ runner.os }}-undefined-console-npm- + path: ${{ env.APP_DIR }}/node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('apps/undefined-console/package-lock.json') }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: - targets: aarch64-linux-android,armv7-linux-androideabi,i686-linux-android,x86_64-linux-android + targets: ${{ matrix.rust_target }} - name: Cache cargo registry and target uses: Swatinem/rust-cache@v2 with: - key: android + key: android-${{ matrix.abi_label }} workspaces: | apps/undefined-console/src-tauri -> target @@ -360,6 +382,7 @@ jobs: ${{ runner.os }}-gradle- - name: Install app dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' working-directory: ${{ env.APP_DIR }} run: npm ci @@ -367,17 +390,147 @@ jobs: working-directory: ${{ env.APP_DIR }} run: npm run tauri:android:init - - name: Build Android APK - # If signing secrets are wired into the generated Android project, replace the - # debug fallback with a release build. The scaffold keeps the expectation explicit - # while still publishing an installable APK on every non-iOS release. + - name: Validate Android signing secrets + env: + ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} + ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + run: | + missing=0 + for name in ANDROID_KEYSTORE_BASE64 ANDROID_KEYSTORE_PASSWORD ANDROID_KEY_ALIAS ANDROID_KEY_PASSWORD; do + if [ -z "${!name}" ]; then + echo "::error title=Missing Android signing secret::${name} is required for release APK signing." + missing=1 + fi + done + if [ "$missing" -ne 0 ]; then + exit 1 + fi + + - name: Configure Android release signing working-directory: ${{ env.APP_DIR }} - run: npm run tauri:android:debug -- --ci --apk + env: + ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} + ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + shell: bash + run: | + KEYSTORE_PATH="$RUNNER_TEMP/undefined-console-release.jks" + KEYSTORE_PROPERTIES_PATH="src-tauri/gen/android/keystore.properties" + APP_GRADLE_PATH=$(find "src-tauri/gen/android" -type f \( -path '*/app/build.gradle.kts' -o -path '*/app/build.gradle' \) | sort | head -n 1) + + if [ -z "$APP_GRADLE_PATH" ]; then + echo "Could not find generated Android app Gradle file" >&2 + exit 1 + fi + + echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$KEYSTORE_PATH" - - name: Collect Android artifact + cat > "$KEYSTORE_PROPERTIES_PATH" <&2 printf 'Matches:\n%s\n' "${matches[*]}" >&2 @@ -396,12 +549,12 @@ jobs: } mkdir -p release-artifacts - copy_single_match "$APP_DIR/src-tauri" '*.apk' "release-artifacts/Undefined-Console-${TAG}-android-universal.apk" + copy_single_match "$APP_DIR/src-tauri" '*.apk' "release-artifacts/Undefined-Console-${TAG}-android-${ABI_LABEL}-release.apk" - name: Upload Android artifact uses: actions/upload-artifact@v4 with: - name: tauri-android + name: tauri-android-${{ matrix.abi_label }} path: release-artifacts/* if-no-files-found: error diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index d0b03286..218699c5 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -86,6 +86,7 @@ graph TB T_Time["get_current_time
获取当前时间"] T_GetPicture["get_picture
获取图片"] T_GetUserInfo["get_user_info
获取用户信息"] + T_ArxivPaper["arxiv_paper
arXiv 论文发送"] T_BilibiliVideo["bilibili_video
B站视频下载发送"] end @@ -102,7 +103,7 @@ graph TB end subgraph IntelligentAgents["智能体 Agents (skills/agents/, 6个)"] - A_Info["info_agent
信息查询助手
(17个工具)
• weather_query
• *hot 热搜
• bilibili_*
• whois"] + A_Info["info_agent
信息查询助手
(18个工具)
• weather_query
• *hot 热搜
• bilibili_*
• arxiv_search
• whois"] A_Web["web_agent
网络搜索助手
(3个工具 + MCP)
• web_search
• crawl_webpage
• Playwright MCP"] A_File["file_analysis_agent
文件分析助手
(14个工具)
• extract_* (PDF/Word/Excel/PPT)
• analyze_code
• analyze_multimodal"] A_Naga["naga_code_analysis_agent
NagaAgent 代码分析
(7个工具)
• read_file / glob
• search_file_content"] @@ -802,6 +803,7 @@ description: 从 PDF 文件中提取文本和表格,填写表单。当用户 | **存储配置** | `token_usage.*` | Token 归档和清理策略 | | **认知记忆** | `cognitive.enabled`, `cognitive.query.*`, `models.embedding.*` | 事件检索、时间衰减加权、侧写与后台史官 | | **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 发送 | | **思考链** | `*.thinking_enabled` | 思维链支持 | | **思维链兼容** | `*.thinking_tool_call_compat` | 思维链 + 工具调用兼容 | | **WebUI** | `webui.url`, `webui.port`, `webui.password` | 配置控制台 | @@ -832,7 +834,7 @@ description: 从 PDF 文件中提取文本和表格,填写表单。当用户 | Agent | 功能定位 | 工具数量 | 核心能力 | |-------|---------|---------|---------| -| **info_agent** | 信息查询助手 | 17个 | 天气查询、热搜榜单、网络检测、B站信息查询等 | +| **info_agent** | 信息查询助手 | 18个 | 天气查询、热搜榜单、网络检测、B站信息查询、arXiv 搜索等 | | **web_agent** | 网络搜索助手 | 3个 + MCP | 网页搜索、爬虫、Playwright MCP | | **file_analysis_agent** | 文件分析助手 | 14个 | PDF/Word/Excel/PPT解析、代码分析、多模态分析 | | **naga_code_analysis_agent** | NagaAgent 代码分析 | 7个 | 代码库浏览、文件搜索、目录遍历 | @@ -841,7 +843,7 @@ description: 从 PDF 文件中提取文本和表格,填写表单。当用户 ### Skills 插件系统 -- **Tools (基础工具)**:原子化的功能单元,如 `send_message`, `get_history`, `bilibili_video`。 +- **Tools (基础工具)**:原子化的功能单元,如 `send_message`, `get_history`, `bilibili_video`, `arxiv_paper`。 - **Toolsets (复合工具集)**:9大类工具集 (group, messages, memory, contacts, group_analysis, notices, render, scheduler, cognitive)。 - **延迟加载 + 热重载**:`handler.py` 仅在首次调用时导入;当 `skills/` 下的 `config.json`/`handler.py` 发生变更时会自动重新加载。 - **Agent 自我介绍自动生成**:启动时按 Agent 代码/配置 hash 生成 `intro.generated.md` 并与 `intro.md` 合并。 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..177724e1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,667 @@ +## v3.2.7 arXiv 工具集与运行时变更感知 + +新增 arXiv 论文搜索与提取工具集,以及运行时 CHANGELOG 查询能力。重构了生图工具支持 OpenAI 兼容接口,引入 grok_search 联网搜索工具,并让 AI 在系统提示词中感知自身模型配置信息。同步修复了多项稳定性问题与 CI 效率优化。 + +- 新增 arXiv 论文搜索 (`arxiv_search`) 与提取 (`arxiv_paper`) 工具,支持按关键词搜索论文、提取摘要与关键信息。 +- 新增运行时 `/changelog` 命令与 changelog 查询工具,支持在对话中查看和检索变更历史。 +- 重构生图工具为双模式分发(星之阁 / OpenAI 兼容接口),新增 `[models.image_gen]` 配置节,支持可配置的生图服务商。 +- 新增 grok_search 联网搜索工具,专用 `[models.grok]` 模型配置,启用后优先级高于 SearXNG。 +- AI 现在能感知自身模型配置信息——在系统提示词中注入当前运行模型的非敏感配置(模型名、认知记忆开关、模型池状态等)。 +- 认知记忆检索复用查询嵌入,减少重复嵌入计算开销。 +- 修复消息工具中 `reply_to` 目标定位不稳定的问题,增强 AI 协调器的队列路由稳定性。 +- 修复 Responses 回放时函数调用 ID 规范化与 replay-only 状态字段过滤问题。 +- 简化 grok_search 为原始提示词直传响应,减少解析链路。 +- 修复 crawl4ai 可用性检测逻辑。 +- 精简 Agent 提示词透传,移除多余包装。 +- 优化 CI 工作流缓存策略(npm + mypy),分离 Android 签名 APK 构建。 +- 改进 WebUI 移动端适配,优化快捷键与长列表展示。 + +--- + +## v3.2.6 Responses 重试与私聊发送修复 + +优化了消息投递系统的可靠性,涵盖 Responses 回放、队列重试及私聊发送链路。主要改进包括发送回退机制、零间隔调度支持,以及 Naga 投递追踪与运行时测试的完善。 + +- 过滤 replay-only 状态字段,防止 Responses 回放结果干扰后续请求。 +- 调整队列重试调度逻辑,支持零间隔立即投递,并细化重试时序。 +- 增加私聊消息发送失败时的临时会话回退机制,降低消息丢失率。 +- 限制 `/lsadmin` 命令的可见性,提升安全性。 +- 为 Naga 增加发送 UUID 幂等性校验、投递追踪及相关测试覆盖。 +- 修复 CI 与运行时测试,并补充 OpenAI reasoning 参数的对齐处理。 + +--- + +## v3.2.5 形象资源与调用暴露整理 + +调整了项目形象资源与部分调用权限配置。优化了外部形象资源的引用方式,并清理了 info_agent 的暴露行为,保持现有功能入口不变。 + +- 更新 README 中的项目形象资源与展示素材。 +- 移除不再需要的 info_agent callable override 配置。 +- 保持既有功能入口的稳定性,减少对使用方式的变更。 + +--- + +## v3.2.4 Naga 回调端口与联动修复 + +适配新版 NagaAgent 接口变化,校准了回调端口与联动流程。重点优化了回调地址解析、端口处理及绑定后的投递逻辑,增强了异常处理与测试覆盖。 + +- 适配新版 NagaAgent 的回调端口配置与请求路径。 +- 修复联动模式下部分绑定状态与回调逻辑不一致的问题。 +- 增强异常处理机制,减少联动过程中的静默失败。 +- 补充 Naga 回调流程相关的测试用例。 + +--- + +## v3.2.3 配置同步与推理参数重构 + +统一了配置同步体验与 AI 推理参数管理,优化了管理端与运行时的读取逻辑。同步更新了 Naga 子模块版本,增强了模板对齐与增量同步功能。 + +- 增强配置同步脚本,支持更精准的模板对齐与增量同步。 +- 重构 AI 推理相关配置项,统一参数表达与读取方式。 +- 更新 NagaAgent 子模块版本,保持联动能力一致性。 +- 规范配置文档与默认值,降低配置迁移成本。 + +--- + +## v3.2.2 IPv6 监听与代理 URL 修复 + +修复了 Runtime API 与 WebUI 在 IPv6 双栈环境下的地址构造问题。统一了 URL 构造逻辑,增强了监听地址、回环地址及代理 URL 在复杂网络环境中的兼容性与稳定性。 + +- 修复 Runtime API 代理 URL 在 IPv6 监听地址下的解析错误。 +- 统一 URL 构造逻辑,防止多入口拼接导致的地址异常。 +- 增强 IPv4/IPv6 双栈监听的兼容性。 +- 提升管理端在复杂网络环境中的连接稳定性。 + +--- + +## v3.2.1 Tool Invoke API 与 Naga Scoped Token + +扩展了 Runtime API 的外部调用能力,新增 Tool Invoke API 并引入 Naga Scoped Token 鉴权机制。明确了接口权限边界,完善了 API 路由与错误处理。 + +- 新增 Tool Invoke API,支持通过运行时接口直接触发工具调用。 +- 引入 Naga Scoped Token 鉴权机制,细化联动权限控制。 +- 完善 API 路由定义、鉴权校验及错误返回格式。 +- 为管理端及外部集成提供更稳定的调用接口。 + +--- + +## v3.2.0 多平台客户端与 Responses 支持增强 + +新增多平台客户端发布链路(Windows/macOS/Linux/Android),并增强了 WebUI 管理体验。运行时新增引用回复支持,优化 Python 解释器与 Responses API 接入,提升了跨平台管理与交互能力。 + +- 建立覆盖 Windows、macOS、Linux 与 Android 的客户端发布流程。 +- 优化 WebUI 界面交互与管理流程,提升远程管理体验。 +- 支持消息引用回复、Python 解释器功能增强及 Responses API 接入。 +- 修复 macOS 与 Android 构建兼容性问题,优化 CI 缓存策略。 +- 统一移动端与桌面端的管理面运行基础。 + +--- + +## v3.1.1 记忆联动与后台调度增强 + +增强了记忆架构的实用性与稳定性。支持跨群记忆联动,优化了后台史官调度(改为轮询周期)及图片分析链路,提升了记忆自动检索的上下文质量。 + +- 增加记忆自动检索加权配置,优化上下文注入效果。 +- 支持跨群记忆联动,扩展认知记忆的共享范围。 +- 将 Historian Job 调整为轮询周期调度,缓解后台任务拥塞。 +- 优化图片分析与 B 站下载链路,减少对主流程的干扰。 +- 提升后台史官任务的稳定性与故障恢复能力。 + +--- + +## v3.1.0 后台史官 Agent Loop + +实现了后台史官的 Agentic Loop,支持持续的记忆整理与长期状态更新。新增侧写维护工具 (read/update profile),优化了记忆改写与回写流程,减少对前台对话的阻塞。 + +- 实现后台史官 Agentic Loop,支持持续处理记忆任务。 +- 新增 read/update profile 工具,完善认知侧写维护链路。 +- 优化后台记忆改写与回写流程,降低前台响应延迟。 +- 为长期记忆与用户画像的持续演进提供基础支持。 + +--- + +## v3.0.3 本地文件 URI 统一 + +统一本地文件发送格式为 `file://` URI,消除了不同入口对文件路径解析的差异,提升了图片与文件消息发送的一致性。 + +- 统一本地文件发送使用 `file://` URI 协议。 +- 消除不同消息入口对文件路径解释的差异。 +- 提升图片和文件消息发送链路的一致性。 + +--- + +## v3.0.2 图片发送链路修复 + +修复了图片发送失败的问题,调整了消息输出链路中的兼容性处理,降低了多模态结果回传的失败率。 + +- 修复图片无法发送的问题。 +- 调整图片消息输出链路中的兼容处理。 +- 降低多模态结果回传时的失败率。 + +--- + +## v3.0.1 WebUI 会话上下文补全 + +补全了 WebUI 会话中的 `request_type` 上下文,改善了 WebUI AI Chat 与运行时上下文的对齐程度,解决了工具调用时的上下文缺失问题。 + +- 为 WebUI 会话 `extra_context` 补充 `request_type` 字段。 +- 改善 WebUI AI Chat 与运行时上下文的对齐程度。 +- 修复管理端对话在工具调用时的上下文缺失问题。 + +--- + +## v3.0.0 新版认知记忆架构与 WebUI 大改进 + +重构了认知记忆架构与 WebUI 管理体验。推出了基于事件、侧写和长期记忆的新版架构,重构了后台史官流程,并显著增强了 WebUI 的可用性与运行态展示。 + +- 推出新版认知记忆架构,优化事件、侧写和长期记忆的组织方式。 +- 重构后台史官相关流程,建立 Agentic Loop 基础。 +- 改进 WebUI 管理体验和运行态展示,增强管理端可用性。 +- 优化记忆注入、检索与改写链路,减少对前台响应的阻塞。 +- 为跨群记忆联动和认知查询能力提供底层支持。 + +--- + +## v2.15.0 知识库与访问控制落地 + +正式引入知识库功能,集成了文本检索、语义检索与重排链路。实现了基于模式的访问控制(黑白名单),并强化了防重复执行机制与斜杠命令识别。 + +- 新增基于文本检索、语义检索和重排的知识库功能。 +- 引入模式化访问控制,支持群聊与私聊黑白名单。 +- 修复带昵称 `@` 片段导致的斜杠命令识别失败问题。 +- 强化防多次执行提示词,降低重复调用工具的概率。 +- 为认知记忆和知识检索联动提供底层能力。 + +--- + +## v2.14.0 工具扩充与重复执行防护 + +扩充了实用工具集,并优化了防重复执行的提示词与决策逻辑。移除了旧版 inflight summary 方案,提升了多工具协作的稳定性与可控性。 + +- 新增更多实用工具,扩展日常查询和执行能力。 +- 重构防重复执行相关提示词与决策逻辑。 +- 移除旧的 inflight summary 方案,简化中间态处理。 +- 优化多工具协作时的稳定性和可控性。 + +--- + +## v2.13.1 私聊多模型池 + +在私聊场景引入多模型池支持,实现了更灵活的模型选择。同时修复了代码交付 Agent 的稳定性问题,优化了上下文切换体验。 + +- 为私聊场景增加多模型池支持和智能模型选择能力。 +- 修复代码交付 Agent 的多个稳定性问题。 +- 改善多模型切换时的上下文和调用体验。 +- 收敛 Agent 协作中的边界处理。 + +--- + +## v2.13.0 并发防重与工具增强 + +引入并发防重复执行机制,解决了并发场景下的工具重复触发问题。升级了时间工具、Bilibili 工具及文本文件投递能力,并收紧了 Agent 互调用权限。 + +- 新增并发防重复执行机制,降低进行中摘要和工具重复触发。 +- 升级 `get_current_time`,增加农历等信息支持。 +- 切换 Bilibili 工具到官方接口并增加 WBI 重试。 +- 新增 `send_text_file` 工具,增强文本文件投递能力。 +- 收紧主工具白名单与 Agent 互调用权限控制。 +- 增强统计功能并修复多项稳定性问题。 + +--- + +## v2.12.11 代码交付 Agent 与互调用 + +正式发布代码交付 Agent,支持代码生成、验证与交付。新增 Agent 互调用能力,支持多 Agent 协作完成复杂任务。 + +- 新增代码交付 Agent,支持生成、验证并交付代码结果。 +- 增加 Agent 互调用能力,支持更复杂的多 Agent 协作。 +- 调整相关提示词与执行链路,提升任务拆分能力。 +- 为编程、交付和复合任务场景提供新的执行入口。 + +--- + +## v2.12.10 工具系统稳定性修复 + +修复了工具调用体系中的兼容性与稳定性问题。重点优化了工具注册、解析和执行链路,确保工具调用的可靠性。 + +- 修复工具系统中的多个兼容性与稳定性问题。 +- 调整工具注册和调用链路,减少异常失败。 +- 改善工具错误处理与输出一致性。 +- 为 Agent 协作与复杂工具链提供稳定基础。 + +--- + +## v2.12.9 Agent 架构与多 Agent 稳定性增强 + +重构了 Agent 架构,梳理了主 AI 与子 Agent 的协作边界。新增好友与群聊查询能力,并修复了多项稳定性问题,提升了多 Agent 协作成功率。 + +- 重构 Agent 架构,明确主 AI 与子 Agent 的协作边界。 +- 新增好友与群聊查询相关能力,扩展联系人可见范围。 +- 修复多项稳定性问题,提升多 Agent 协作成功率。 +- 优化 `end_summary` 和记忆相关逻辑,提升长期上下文质量。 +- 补强部分工具链路的异常处理和容错能力。 + +--- + +## v2.12.8 @ 处理与群成员检索增强 + +优化了群聊中的 @ 处理逻辑与群成员检索功能。增强了复杂消息中的 @ 识别准确性,支持按昵称查找群成员。 + +- 增强 @ 相关处理逻辑,减少复杂消息中的识别偏差。 +- 新增群成员检索工具,支持按昵称查找群成员。 +- 提升消息链路与工具调用之间的衔接稳定性。 +- 为群管理分析和成员操作能力提供支持。 + +--- + +## v2.12.7 已知问题快速修补 + +修复了若干关键 Bug,重点解决了部分异常输入导致的失败问题,确保了前一版本新增功能的稳定性。 + +- 修复三个关键 Bug,降低常见故障触发率。 +- 调整相关边界处理,减少异常输入导致的失败。 +- 巩固前一版本新增功能的实际可用性。 + +--- + +## v2.12.6 Bilibili 视频解析发送 + +新增 Bilibili 视频解析、下载与发送功能,并补充了群管理分析工具集。打通了从视频内容识别到发送的完整链路。 + +- 新增 Bilibili 视频解析、下载与发送功能。 +- 增加群管理分析工具集,补充群聊观察能力。 +- 打通视频内容从识别到发送的完整链路。 +- 扩展多媒体工具和群分析工具的能力边界。 + +--- + +## v2.12.5 Anthropic Skills 与 Naga 工具更新 + +集成 Anthropic Skills 支持,允许以 `SKILL.md` 形式注入能力。更新了 NagaAgent 子模块及相关工具,增强了外部知识注入与联动的一致性。 + +- 新增 Anthropic Skills 支持,兼容 `SKILL.md` 形式的能力注入。 +- 更新 NagaAgent 子模块及相关工具,改善联动一致性。 +- 整理 AGENTS 文档和子模块说明,减少维护歧义。 +- 优化提示词与对接流程,提升多来源能力接入体验。 + +--- + +## v2.12.4 提示词回退与拒答修复 + +回退主提示词至更稳定的版本,降低了降智、拒绝回复及不稳定输出的概率。修复了提示词标签缺失问题,提供了更精简的 NagaAgent 提示词变体。 + +- 回退主提示词到更稳定的旧版本思路,降低异常行为概率。 +- 基于回退方案提供更精简的 NagaAgent 提示词变体。 +- 修复提示词中缺失标签的问题,避免格式错误影响模型理解。 +- 缓解因提示词变形引发的降智、拒绝回复和不稳定输出问题。 + +--- + +## v2.12.3 消息目标自动推断 + +优化了消息发送的目标推断逻辑,减少了手动填写目标参数的需求。修复了仅提供目标类型时 `send_message` 的失败问题,提升了群聊与私聊的目标解析准确性。 + +- 增加消息发送目标推断逻辑,简化参数填写。 +- 修复仅提供目标类型时 `send_message` 可能直接失败的问题。 +- 调整消息工具 Handler,提升群聊和私聊的目标解析稳定性。 +- 同步更新版本号与依赖锁文件。 + +--- + +## v2.12.2 WebUI 安全与自更新增强 + +增强了 WebUI 的安全性与自更新能力。引入强制初始密码修改流程与基于 Git 的自更新机制,改善了长期运行实例的维护体验。 + +- 增加强制修改初始密码流程,降低默认凭据风险。 +- 引入基于 Git 的自更新能力,改善维护与升级体验。 +- 改进 WebUI 路由、模板和前端交互,补齐安全提示与引导。 +- 调整主进程启动和配置读取细节,配合更新流程落地。 +- 重构 `self_update` 相关实现,为后续维护操作提供基础。 + +--- + +## v2.12.1 NagaAgent 模式开关 + +引入 NagaAgent 模式开关,支持显式控制联动能力的启用。优化了相关提示词资源与工具装配逻辑,使模式切换更加清晰直观。 + +- 添加 NagaAgent 模式开关,显式控制联动能力启用状态。 +- 新增或拆分 NagaAgent 专用提示词资源,减少与主提示词耦合。 +- 调整 AI 客户端与工具装配逻辑,使模式切换更清晰。 +- 更新配置示例和 WebUI 读取逻辑,确保管理端可配置该能力。 +- 优化联动模式下的默认 Prompt 表达。 + +--- + +## v2.12.0 配置增强与命令系统重构 + +升级了配置系统与命令体系。增强了运行参数配置与热重载支持,重构了命令注册表以支持插件化。同时调整了核心组件实现以适配新架构。 + +- 增强配置系统,补充更多运行参数,优化默认体验。 +- 新增配置热重载支持,使配置改动在运行中即时生效。 +- 重构命令系统与注册表,推动斜杠命令插件化。 +- 调整 AI、队列、上下文和安全服务的实现,配合新架构升级。 +- 更新 NagaAgent 子模块,为后续联动能力提供支持。 +- 修复关闭思考时仍发送思考参数的问题,并补充启动模式说明。 + +--- + +## v2.11.2 严格供应商兼容修复 + +优化了工具命名与兼容逻辑,适配了对函数调用约束更严格的供应商。调整了 AI 客户端与 Agent Handler,降低了因命名或适配差异导致的调用失败率。 + +- 重写工具名称生成与兼容逻辑,适配严格的函数调用约束。 +- 修复部分供应商因工具名不合法而拒绝请求的问题。 +- 更新 AI 客户端与 LLM 层处理路径,统一命名规则。 +- 调整多个 Agent 的 Handler 与 Prompt,提升适配兼容性。 +- 更新配置示例和 WebUI 相关读取逻辑,保持前后端一致。 + +--- + +## v2.11.1 WebUI 自举与访问控制补强 + +完善了 WebUI 的自举启动流程与访问控制功能。新增群聊/私聊白名单模式,支持限制消息收发范围。增加了 Agent/Tool 调用播报功能,提升了运行时可观察性。 + +- 修复缺失 `config.toml` 时的启动与引导流程,支持配置自举。 +- 补强 Wheel 资源打包与跨平台文件锁,提升开箱可用性。 +- 新增群聊与私聊 Allowlist 模式,支持限制消息范围。 +- 增加 Agent/Tool 调用播报和彩蛋模式,提升可观察性。 +- 改进 WebUI 日志筛选、配置解析报错与构建细节。 + +--- + +## v2.11.0 WebUI 与 TOML 配置中枢 + +推出了 WebUI 管理界面与 `config.toml` 统一配置中心。实现了可视化配置编辑、日志查看与 Bot 控制,支持配置热重载与校验。 + +- 新增 `Undefined-webui` 入口,提供登录、配置编辑、日志查看和 Bot 控制。 +- 引入 `config.toml` 优先的配置加载与热重载机制。 +- 重构 WebUI 前后端结构,补齐模板、静态资源与国际化支持。 +- 废弃 `.env.example`,强化 TOML 配置使用方式。 +- 调整运行时组件以适配新配置对象,并提升 Python 版本要求至 3.11。 + +--- + +## v2.10.1 `/stats` 并发错配修复 + +修复了 `/stats` 命令在高并发场景下的分析结果错配问题。增加了 Matplotlib 缺失时的兜底处理,提升了统计功能的稳定性。 + +- 修复 `/stats` 并发执行时分析结果错配问题。 +- 改善统计分析结果与请求上下文的绑定关系。 +- 增加 Matplotlib 缺失或异常时的兜底处理。 +- 提升统计命令在高并发场景下的稳定性。 +- 补强统计链路的异常处理与可恢复性。 + +--- + +## v2.10.0 架构整理与 CoT 兼容增强 + +重构了系统架构,优化了配置管理与工具调用稳定性。增强了 DeepSeek CoT 等推理模型的兼容性,初步构建了 AI 统计分析能力。 + +- 重构系统架构,梳理核心模块边界。 +- 优化配置管理结构,降低维护复杂度。 +- 增强 DeepSeek CoT 兼容性,改善推理类模型接入体验。 +- 提升工具调用稳定性,减少异常调用失败。 +- 补强 AI 统计分析能力,为 `/stats` 功能提供基础。 + +--- + +## v2.9.0 OpenAI SDK 驱动的 AI 运行时 + +基于 OpenAI SDK 重构了 LLM 请求层,模块化了 AI 运行时。增强了多供应商接口兼容性,并引入了更完整的 Token 归档与安全处理链路。 + +- 使用 OpenAI SDK 重构统一的 LLM 请求层。 +- 模块化 AI 运行时,明确模型调用与执行边界。 +- 增强不同供应商接口的兼容性。 +- 引入更完整的 Token 归档与统计基础。 +- 加强安全处理链路,为功能扩展提供支持。 + +--- + +## v2.8.3 系统提示词优化 + +优化了系统提示词结构与表达方式,提升了模型对任务意图的理解一致性。降低了跑偏与冗余输出的概率,增强了对话稳定性。 + +- 优化系统提示词结构与表达方式。 +- 改善模型对任务意图的理解一致性。 +- 降低部分场景下的跑偏和冗余输出。 +- 提升整体对话稳定性与回复可用性。 +- 延续架构调整后的行为校正。 + +--- + +## v2.8.2 定时任务上下文修复 + +修复了定时任务执行时的上下文缺失问题,实现了运行时动态注入与持久化。提升了定时任务重启后的恢复能力与执行稳定性。 + +- 修复定时任务执行时上下文缺失的问题。 +- 为调度任务补充上下文持久化能力。 +- 增加运行时动态注入,改善任务恢复后的可执行性。 +- 提升定时任务重启后继续执行的稳定性。 +- 修正调度器相关的边界行为。 + +--- + +## v2.8.1 导入路径修复与结构清理 + +批量替换相对导入为绝对导入,解决了模块间导入不稳定的问题。清理了代码结构,并补充了文件分析 Agent 的相关文档。 + +- 将相对导入批量替换为绝对导入,消除路径歧义。 +- 修复重构后模块间导入不稳定的问题。 +- 提升代码结构清晰度和可维护性。 +- 补充文件分析 Agent 的图片分析能力说明。 +- 降低 Skills 目录拆分的维护成本。 + +--- + +## v2.8.0 Skills 架构重写 + +重写了 Skills 加载架构,引入统一注册表模型。支持工具与 Agent 的懒加载、热重载及私有 MCP 接入,并自动生成 Agent 说明文档。 + +- 重写 Skills 加载架构,引入统一注册表逻辑。 +- 支持工具与 Agent 的懒加载和热重载。 +- 增加工具调用超时控制,改善运行时稳定性。 +- 支持 Agent 级独立 `mcp.json`,实现私有 MCP 工具接入。 +- 自动生成 Agent `intro.md`,提升能力描述一致性。 + +--- + +## v2.7.0 并发安全与异步 IO 重构 + +重构了并发基础设施,统一了异步安全文件操作与请求上下文隔离。修复了核心并发竞态条件,将阻塞型 IO 移出主事件循环,提升了高并发场景下的稳定性。 + +- 重构 IO 层,统一为异步安全文件操作。 +- 引入基于 `contextvars` 的请求上下文隔离。 +- 修复核心并发竞态条件,增强数据访问安全性。 +- 将阻塞型 IO 移出主事件循环,降低死锁风险。 +- 为高并发工具与 Agent 调度提供稳定基础。 + +--- + +## v2.6.0 非阻塞调度循环与联系人能力 + +将 AI 请求调度改为基于模型的非阻塞循环,显著提升了并发处理能力。新增 QQ 用户与群组管理工具集,扩展了联系人与成员信息查询能力。 + +- 新增 QQ 用户与群组管理工具集,扩展联系人查询能力。 +- 重构成员信息查询链路,统一工具组织方式。 +- 将队列调度改为基于模型的非阻塞循环,减少串行阻塞。 +- 提升高并发场景下的请求吞吐与调度稳定性。 +- 同步更新版本与配套文档说明。 + +--- + +## v2.5.1 Python 解释器工具接入 + +接入 Python 解释器工具,基于 Docker 提供隔离执行环境。支持在运行时安全执行 Python 代码,为代码交付与分析能力提供基础。 + +- 新增 Python 解释器工具。 +- 基于 Docker 提供隔离执行环境,提升安全性。 +- 支持在运行时执行 Python 代码并返回结果。 +- 为代码执行类能力提供独立工具入口。 + +--- + +## v2.5.0 AI 请求层重构与 `/stats` 上线 + +重构了 AI 请求层,理顺了调用与统计链路。上线 `/stats` 可视化统计命令,支持 Token 用量统计与图表展示。 + +- 重构 AI 请求层,理顺调用与统计链路。 +- 新增 Token 用量统计能力。 +- 上线 `/stats` 可视化统计与分析入口。 +- 为用量观测补充图表和聚合展示基础。 +- 改进 CI 中 Ruff 和 MyPy 的缓存配置。 + +--- + +## v2.4.0 核心架构解耦与记忆增强 + +模块化解耦了主 AI、安全检查与命令系统。增强了记忆系统与 OneBot 群组管理能力,优化了群聊上下文处理与日志系统。 + +- 重构核心架构,实现模块化解耦。 +- 增强记忆系统与 OneBot 群组管理相关能力。 +- 优化群聊上下文处理,改善运行时状态组织。 +- 增强日志系统,提供更丰富的观测信息与彩色输出。 +- 新增基于 `uv` 的自动化代码质量检查工作流。 +- 优化 GitHub Actions 缓存策略,降低 CI 成本。 + +--- + +## v2.3.0 MCP 接入与多工具调度 + +正式接入 MCP (Model Context Protocol),支持通过标准配置连接外部工具。定时任务新增多工具执行支持,允许串行或并行运行。 + +- 新增 MCP 支持,可通过标准 JSON 配置外部工具连接。 +- 基于 `fastmcp` 驱动 MCP 接入,提升扩展规范性。 +- 定时任务新增多工具执行,支持串行与并行模式。 +- 补充 Prompt 文档与 Agent 说明,明确工具执行模式。 + +--- + +## v2.2.6 非 URL 文件输入支持 + +`download_file` 工具新增对本地文件路径的支持,优化了目标解析逻辑。允许非 URL 文件直接进入下载与分析流程,提升了本地资源使用的便利性。 + +- `download_file` 工具新增对本地文件路径的支持。 +- 优化非 URL 文件的目标解析逻辑。 +- 移除文件分析前必须转换为网络地址的限制。 +- 提升本地资源接入文件工具链时的可用性。 + +--- + +## v2.2.5 文件消息类型补全处理 + +补全了对文件、视频、录音等消息类型的处理链路。修复了缺失类型时的兼容性问题,降低了多媒体消息解析失败率。 + +- 补充对文件消息的完整处理链路。 +- 修复缺失 `file`、`video`、`record`、`audio` 等消息类型时的兼容问题。 +- 降低多媒体消息进入主流程时的解析失败率。 +- 打通文件下载与分析的输入前置。 + +--- + +## v2.2.4 Toolsets 分层与安全回复优化 + +引入 `toolsets` 分层结构,按分类暴露工具前缀。重构 Skills 加载逻辑,新增工具加载统计日志。优化安全拦截回复提示词,减少无效输出。 + +- 引入 `toolsets` 工具层级,降低工具命名歧义。 +- 重构 Skills 加载逻辑,解耦依赖并统一发现流程。 +- 新增工具加载统计日志,提升技能注册可见性。 +- 将部分渲染与调度能力迁入新的工具集结构。 +- 优化注入防护回复提示词,采用更自然的风格。 +- 缩短安全拦截回复长度,减少干扰。 + +--- + +## v2.2.3 调度指令精度与发布检查增强 + +优化了 `scheduler_agent` 的 Prompt 与文档,提升定时调用意图识别准确度。在发布流程中集成 Lint 检查,提前拦截风格与静态错误。 + +- 优化 `scheduler_agent` 的 Prompt 和 Intro,提升意图对齐。 +- 为发布流程补充 Lint 集成,提前拦截代码问题。 +- 新增 `ci` 依赖组,统一 CI 环境下的质量检查入口。 +- 升级 Ruff 版本并同步版本号。 + +--- + +## v2.2.2 放宽 Python 版本要求 + +将 Python 版本要求放宽至 `>=3.10`,降低了部署与试用门槛,减少了因解释器版本不符导致的安装失败。 + +- 将 Python 版本支持范围扩展到 `>=3.10`。 +- 降低用户部署和试用的环境门槛。 +- 减少因解释器版本不符导致的安装失败。 +- 同步更新版本声明与发布配置。 + +--- + +## v2.2.1 README 资源兼容性修复 + +修复了 README 中本地图片路径在外部平台(如 PyPI)下的显示问题,统一使用 GitHub Raw URL 以保持显示一致性。 + +- 将 README 中的图片引用改为 GitHub Raw URL。 +- 提升 README 在 GitHub、PyPI 等平台中的显示一致性。 +- 解决相对路径图片在非仓库目录下失效的问题。 +- 保持文档结构不变,修复资源访问方式。 + +--- + +## v2.2.0 PyPI 发布与包名调整 + +正式面向 PyPI 发布,包名调整为 `Undefined-bot`。新增自动发布流程,并保留原有 CLI 启动方式,降低迁移成本。 + +- 新增基于 Trusted Publishing 的 PyPI 自动发布流程。 +- 将 PyPI 包名调整为 `Undefined-bot`。 +- 保持 CLI 启动命令不变,兼容既有使用方式。 +- 补充 PyPI 安装说明和发布文档。 +- 完善安装路径,支持源码与安装包分发。 + +--- + +## v2.1.1 AI 请求兼容性修复 + +修复了 OpenAI 请求链路中的兼容性问题,增强了日志与错误处理。优化了 Release 流程中的注释提取与说明生成逻辑。 + +- 修复工具响应未正确写回会话历史导致的 API 兼容性问题。 +- 增强 AI 请求日志与错误处理,便于定位失败原因。 +- 修复 Agent 调用链中可能触发的 HTTP 400 错误。 +- 调整 Release 注释提取逻辑,区分标题与正文。 +- 优化自动发布说明生成,提升文档质量。 + +--- + +## v2.1.0 日志可观测性与持久化增强 + +大幅增强了系统级日志的可观测性,完善了 AI 调用、工具执行与消息流转的记录。实现了定时任务与摘要结果的本地持久化,并建立了 GitHub Release 自动化工作流。 + +- 增强 AI 调用、工具执行和消息流转日志,提升排障能力。 +- 为定时任务增加本地持久化存储,降低数据丢失风险。 +- 为 AI 对话结束摘要增加持久化能力。 +- 为所有 Agent 补充 `get_current_time` 工具,增强时间感知。 +- 统一 Agent 介绍文档,清理过时工具。 +- 新增 GitHub Release 自动化工作流与变更日志生成。 + +--- + +## v2.0.0 Skills 架构与 CLI 入口 + +将原有工具体系重构为 Skills 架构,区分基础工具与智能 Agent。新增 CLI 启动入口与定时任务能力,独立了队列管理服务。 + +- 重构工具体系为 Skills 架构,引入注册表机制。 +- 增加 CLI 启动入口,支持更便捷的运行方式。 +- 引入并行工具执行能力,提升效率。 +- 新增基于 Crontab 的定时任务能力及 `scheduler_agent`。 +- 拆分队列管理为独立的 `QueueManager` 服务。 +- 新增群成员信息查询工具,修复 OneBot 初始化问题。 + +--- + +## v1.0.0 初始发布与基础能力落地 + +首个公开版本,基于 `asyncio` 与 `aiohttp` 构建了异步机器人架构。接入 OneBot V11,集成了 AI 对话、网页抓取、多模态分析与基础记忆模块。 + +- 完成基于 `asyncio` 和 `aiohttp` 的异步机器人架构。 +- 接入 OneBot V11,支持群聊与私聊消息处理。 +- 集成 AI 对话、网页抓取、多模态分析和图像渲染能力。 +- 提供消息读取、文件读取、联网抓取和图片发送等基础工具。 +- 引入基础记忆、FAQ 与限流模块。 + +--- diff --git a/README.md b/README.md index 12be7a70..33b75cf1 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ - **多模型池**:支持配置多个 AI 模型,可轮询、随机选择或用户指定;支持多模型并发比较,选择最佳结果继续对话。详见 [多模型功能文档](docs/multi-model.md)。 - **本地知识库**:将纯文本文件向量化存入 ChromaDB,AI 可通过关键词搜索或语义搜索查询领域知识;支持增量嵌入与自动扫描。详见 [知识库文档](docs/knowledge.md)。 - **访问控制(群/私聊)**:支持 `access.mode` 三种模式(`off` / `blacklist` / `allowlist`)和群/私聊黑白名单;可按策略限制收发范围,避免误触发与误投递。详见 [docs/access-control.md](docs/access-control.md)。 +- **版本变更可查询**:仓库根目录维护 `CHANGELOG.md`,并提供 `/changelog` 命令在运行时查看最近版本和单版本摘要。 - **并行工具执行**:无论是主 AI 还是子 Agent,均支持 `asyncio` 并发工具调用,大幅提升多任务处理速度(如同时读取多个文件或搜索多个关键词)。 - **智能 Agent 矩阵**:内置多个专业 Agent,分工协作处理复杂任务。 - **callable.json 共享机制**:通过简单的配置文件(`callable.json`)即可让 Agent 互相调用、将 `skills/tools/` 或 `skills/toolsets/` 下的工具按白名单暴露给 Agent,支持细粒度访问控制,实现复杂的多 Agent 协作场景。 @@ -57,6 +58,7 @@ - **Agent 私有 MCP**:可为单个 agent 提供独立 MCP 配置,按调用即时加载并释放,工具仅对该 agent 可见。 - **Anthropic Skills**:支持 Anthropic Agent Skills(SKILL.md 格式),遵循 agentskills.io 开放标准,提供领域知识注入能力。 - **Bilibili 视频提取**:自动检测消息中的 B 站视频链接/BV 号/小程序分享,下载 1080p 视频并通过 QQ 发送;同时提供 AI 工具调用入口。 +- **arXiv 论文提取与搜索**:自动检测消息中的 arXiv 链接/标识并发送论文信息与 PDF;同时提供 `arxiv_paper` 发送工具和 `arxiv_search` 检索工具。 - **思维链支持**:支持开启思维链,提升复杂逻辑推理能力。 - **高并发架构**:基于 `asyncio` 全异步设计,支持多队列消息处理与工具并发执行,轻松应对高并发场景。 - **异步安全 I/O**:统一 IO 层通过线程池 + 跨平台文件锁(Linux/macOS `flock`,Windows `msvcrt`)+ 原子写入(`os.replace`)保证并发写入不损坏、且不阻塞主事件循环。 @@ -75,6 +77,7 @@ Undefined 的功能极为丰富,为了让本页面不过于臃肿,我们将 - 🧭 **[Management API 与远程管理](docs/management-api.md)**:WebUI / App 共用的管理接口、认证、配置/日志/Bot 控制与引导探针说明。 - 🛠️ **[配置与热更新说明](docs/configuration.md)**:从模型切换到 MCP 库挂载,全方位掌握 `config.toml` 的高阶配置。 - 💡 **[交互与使用手册](docs/usage.md)**:包含实用的对话示例、多模态解析用法,以及群管家必备的管理员`/指令`。 +- 📝 **[版本变更记录](CHANGELOG.md)**:查看按版本整理的更新摘要,也可在运行时使用 `/changelog` 查询。 - 🛡️ **[访问控制说明](docs/access-control.md)**:教你如何精准配置黑白名单,让机器人的使用范围分毫不差。 - 🧠 **[认知记忆系统详解](docs/cognitive-memory.md)**:黑科技解密——“无阻塞后台史官”是如何将对话内化为向量记忆与用户侧写的。 - 📚 **[本地知识库接入方案](docs/knowledge.md)**:为 AI 挂载本地文本资产,轻松拥抱企业/个人专属 QA。 diff --git a/apps/undefined-console/README.md b/apps/undefined-console/README.md index 771a3a19..17c27db2 100644 --- a/apps/undefined-console/README.md +++ b/apps/undefined-console/README.md @@ -44,4 +44,42 @@ This scaffold intentionally keeps the frontend shell lightweight. It is suitable ## Android notes -The release workflow expects the Android SDK and Java 17. If signing secrets are configured, the workflow should be upgraded to emit a signed release APK/AAB. The current scaffold always emits an installable APK artifact and makes signing expectations explicit in the CI comments. +The release workflow expects the Android SDK, Java 17, and Android signing secrets. It emits signed release APK artifacts per ABI. + +## Android release signing + +The Android application identifier is `com.undefined.console`. + +The release workflow now expects these GitHub Actions secrets in the `release` environment: + +- `ANDROID_KEYSTORE_BASE64` +- `ANDROID_KEYSTORE_PASSWORD` +- `ANDROID_KEY_ALIAS` +- `ANDROID_KEY_PASSWORD` + +Generate a keystore locally, for example: + +```bash +keytool -genkeypair \ + -v \ + -keystore undefined-console-release.jks \ + -alias undefined-console \ + -keyalg RSA \ + -keysize 4096 \ + -validity 3650 +``` + +Encode it for GitHub Secrets: + +```bash +base64 -w 0 undefined-console-release.jks +``` + +Then store the resulting single-line Base64 string in `ANDROID_KEYSTORE_BASE64`, and put the matching passwords and alias into the other three secrets. + +During the release workflow, CI will: + +1. Decode the keystore into the runner temp directory. +2. Write `src-tauri/gen/android/keystore.properties`. +3. Patch the generated Android Gradle app module to attach the release signing config. +4. Build signed release APKs, one per ABI. diff --git a/apps/undefined-console/package-lock.json b/apps/undefined-console/package-lock.json index 354f65fc..6001addb 100644 --- a/apps/undefined-console/package-lock.json +++ b/apps/undefined-console/package-lock.json @@ -1,12 +1,12 @@ { "name": "undefined-console", - "version": "3.2.6", + "version": "3.2.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "undefined-console", - "version": "3.2.6", + "version": "3.2.7", "dependencies": { "@tauri-apps/api": "^2.3.0", "@tauri-apps/plugin-http": "^2.3.0" diff --git a/apps/undefined-console/package.json b/apps/undefined-console/package.json index 93a0d14f..6060cbe3 100644 --- a/apps/undefined-console/package.json +++ b/apps/undefined-console/package.json @@ -1,7 +1,7 @@ { "name": "undefined-console", "private": true, - "version": "3.2.6", + "version": "3.2.7", "type": "module", "scripts": { "tauri": "tauri", diff --git a/apps/undefined-console/src-tauri/Cargo.lock b/apps/undefined-console/src-tauri/Cargo.lock index 96d4a38c..d16730ab 100644 --- a/apps/undefined-console/src-tauri/Cargo.lock +++ b/apps/undefined-console/src-tauri/Cargo.lock @@ -4063,7 +4063,7 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "undefined_console" -version = "3.2.6" +version = "3.2.7" dependencies = [ "serde", "serde_json", diff --git a/apps/undefined-console/src-tauri/Cargo.toml b/apps/undefined-console/src-tauri/Cargo.toml index 569160ff..2df37efc 100644 --- a/apps/undefined-console/src-tauri/Cargo.toml +++ b/apps/undefined-console/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "undefined_console" -version = "3.2.6" +version = "3.2.7" description = "Undefined cross-platform management console" authors = ["Undefined contributors"] license = "MIT" diff --git a/apps/undefined-console/src-tauri/tauri.conf.json b/apps/undefined-console/src-tauri/tauri.conf.json index 3a7d5386..f29fd6dc 100644 --- a/apps/undefined-console/src-tauri/tauri.conf.json +++ b/apps/undefined-console/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Undefined Console", - "version": "3.2.6", + "version": "3.2.7", "identifier": "com.undefined.console", "build": { "beforeDevCommand": "npm run dev", diff --git a/apps/undefined-console/src/main.ts b/apps/undefined-console/src/main.ts index 07c643d9..165015f0 100644 --- a/apps/undefined-console/src/main.ts +++ b/apps/undefined-console/src/main.ts @@ -35,13 +35,9 @@ const PREFERENCE_STORAGE_KEY = "undefined.console.preferences"; const messages = { zh: { brand: "Undefined Console", - subtitle: "保存连接、测试端点,然后直接进入真正的 WebUI。", lang_toggle: "English", theme_light: "浅色", theme_dark: "深色", - hero_title: "连接后直接打开远程 WebUI", - hero_copy: - "Tauri 只负责保存连接与做基础探测;真正的管理界面直接使用现有 WebUI,因此样式和功能与浏览器版保持一致。", button_open: "打开 WebUI", button_test: "测试连接", button_seed: "填入本地示例", @@ -53,7 +49,6 @@ const messages = { saved_profiles: "已保存连接", saved_profiles_copy: "连接配置保存在当前设备本地。", editor_title: "连接编辑器", - editor_copy: "填写同一个 IP/域名,再分别填写 Management 与 Runtime 端口。", display_name: "显示名称", host: "IP / 域名", host_placeholder: "例如:192.168.2.1 或 example.com", @@ -63,8 +58,6 @@ const messages = { password_placeholder: "填写后打开 WebUI 时会自动尝试登录", notes: "备注", notes_placeholder: "例如:本机、预发布、Android 备用连接", - launcher_hint: - "Tauri 只负责连接管理;真正的后台功能与样式都以 WebUI 为准。", empty_profiles: "还没有保存的连接。", empty_probes: "点击“测试连接”后,这里会显示探针结果。", profile_default_name: "本地管理入口", @@ -98,13 +91,9 @@ const messages = { }, en: { brand: "Undefined Console", - subtitle: "Save connections, test endpoints, then open the real WebUI.", lang_toggle: "中文", theme_light: "Light", theme_dark: "Dark", - hero_title: "Open the real remote WebUI after choosing a connection", - hero_copy: - "Tauri only stores connections and runs basic probes. The actual management interface uses the existing WebUI so the look and features stay aligned with the browser version.", button_open: "Open WebUI", button_test: "Test connection", button_seed: "Seed local", @@ -116,8 +105,6 @@ const messages = { saved_profiles: "Saved profiles", saved_profiles_copy: "Profiles are stored locally on this device.", editor_title: "Profile editor", - editor_copy: - "Use one host/IP field, then provide dedicated Management and Runtime ports.", display_name: "Display name", host: "Host / IP", host_placeholder: "For example: 192.168.2.1 or example.com", @@ -127,8 +114,6 @@ const messages = { password_placeholder: "If filled, WebUI will try to sign in automatically", notes: "Notes", notes_placeholder: "For example: local, staging, Android fallback", - launcher_hint: - "Tauri only manages connections; the real console UI and features stay in WebUI.", empty_profiles: "No saved profiles yet.", empty_probes: "Probe results will appear here after you click test connection.", @@ -625,7 +610,6 @@ function render(): void {
${t("brand")}
-

${t("subtitle")}

`; } - function renderBootstrapProbe(data) { - const el = get("managementBootstrapProbe"); - if (!el) return; - if (!data || data.error) { - el.innerHTML = `
${escapeHtml(data?.error || "--")}
`; - return; - } - - const configExists = !!data.config_exists; - const configValid = - data.config_valid === undefined ? null : !!data.config_valid; - const usingDefaultPassword = !!data.using_default_password; - const runtimeEnabled = !!data.runtime_enabled; - const runtimeReachable = - data.runtime_reachable === undefined - ? null - : !!data.runtime_reachable; - const authMode = - data.auth_mode || (state.authAccessToken ? "token" : "cookie"); - const advice = Array.isArray(data.advice) ? data.advice : []; - - const configStatus = configExists ? "ok" : "error"; - const validationStatus = - configValid === null ? "skipped" : configValid ? "ok" : "error"; - const authStatus = usingDefaultPassword ? "error" : "ok"; - const runtimeStatus = - runtimeReachable === null - ? runtimeEnabled - ? "skipped" - : "error" - : runtimeReachable - ? "ok" - : runtimeEnabled - ? "error" - : "skipped"; - - let html = `
${t("probes.section_bootstrap")}
`; - html += `
`; - html += probeItem( - t("probes.bootstrap_config"), - probeStatusBadge(configStatus), - ); - html += probeItem( - t("probes.bootstrap_validation"), - probeStatusBadge(validationStatus), - ); - html += probeItem( - t("probes.bootstrap_auth"), - `${probeStatusBadge(authStatus)} ${escapeHtml(String(authMode))}`, - ); - html += probeItem( - t("probes.bootstrap_runtime"), - probeStatusBadge(runtimeStatus), - ); - html += `
`; - - const summary = []; - if (configExists) summary.push(t("probes.bootstrap_config_exists")); - if (!configExists) summary.push(t("probes.bootstrap_config_missing")); - if (configValid === false && data.validation_error) - summary.push(String(data.validation_error)); - if (usingDefaultPassword) summary.push(t("auth.change_required")); - if (runtimeEnabled && runtimeReachable === false) - summary.push(t("probes.bootstrap_runtime_pending")); - if (!summary.length) summary.push(t("probes.bootstrap_ready")); - - html += `
${summary - .concat(advice) - .map( - (item) => - `
${escapeHtml(item)}
`, - ) - .join("")}
`; - html += `
`; - el.innerHTML = html; - } - - function buildBootstrapFallback(meta, errorMessage = "") { - return { - config_exists: !!state.configExists, - config_valid: null, - using_default_password: !!state.usingDefaultPassword, - auth_mode: state.authAccessToken ? "token" : "cookie", - runtime_enabled: !!(meta && meta.enabled), - runtime_reachable: false, - validation_error: "", - advice: errorMessage ? [String(errorMessage)] : [], - }; - } - function setProbeUnavailable(message) { const msg = String(message || RUNTIME_DISABLED_ERROR); renderInternalProbe({ error: msg }); @@ -917,23 +826,6 @@ renderExternalProbe(data); } - async function fetchBootstrapProbe() { - try { - const data = await fetchJsonOrThrow([ - "/api/v1/management/probes/bootstrap", - "/api/v1/management/probes/capabilities", - ]); - renderBootstrapProbe(data); - } catch (error) { - const meta = await fetchRuntimeMeta().catch(() => ({ - enabled: false, - })); - renderBootstrapProbe( - buildBootstrapFallback(meta, error.message || error), - ); - } - } - async function searchMemory() { if (!(await ensureRuntimeEnabled())) { setMemoryUnavailable(t("runtime.disabled")); @@ -1245,17 +1137,14 @@ async function refreshProbes() { try { - await fetchBootstrapProbe(); if (!(await ensureRuntimeEnabled())) { setProbeUnavailable(t("runtime.disabled")); runtimeState.probesLoaded = true; - runtimeState.bootstrapLoaded = true; return; } await Promise.all([fetchInternalProbe(), fetchExternalProbe()]); runtimeState.probesLoaded = true; - runtimeState.bootstrapLoaded = true; } catch (error) { showToast( `${t("runtime.failed")}: ${appendRuntimeApiHint(error.message || error)}`, diff --git a/src/Undefined/webui/static/js/state.js b/src/Undefined/webui/static/js/state.js index e5b04c0c..2b1561b3 100644 --- a/src/Undefined/webui/static/js/state.js +++ b/src/Undefined/webui/static/js/state.js @@ -178,6 +178,9 @@ const state = { capabilities: null, tab: (initialState && initialState.initial_tab) || "overview", view: initialView || "landing", + mobileDrawerOpen: false, + configMobileActionsOpen: false, + logsMobileActionsOpen: false, config: {}, comments: {}, configCollapsed: {}, diff --git a/src/Undefined/webui/templates/index.html b/src/Undefined/webui/templates/index.html index d2752cb7..d5c47a5d 100644 --- a/src/Undefined/webui/templates/index.html +++ b/src/Undefined/webui/templates/index.html @@ -182,26 +182,60 @@

设置新密码