Files
mnote/design/07-ai/process/7-61-yuxi-reference-middleware-extensions-dashboard-v1.md
T

24 KiB
Raw Blame History

7-61 [process] Yuxi reference: middleware tool composition, extensions entry, knowledge settings UI, and local dashboard v1

创建时间:2026-06-13

当前状态:PROCESS

Owner07-ai / 03-rust-web / Hermes tools / Page AI settings / Knowledge RAG UI / Dashboard

上位设计:design/07-ai/done/7-57-yuxi-reference-ai-run-config-knowledge-facade-v1.md

本稿是 7-57 的补充,覆盖 7-57 未涉及的 Yuxi 参考领域。

参考代码:

  • reference-code/Yuxi/backend/package/yuxi/agents/middlewares/(中间件分层组合)
  • reference-code/Yuxi/backend/package/yuxi/agents/base.pyAgent 基类 + checkpointer
  • reference-code/Yuxi/web/src/views/ExtensionsView.vue(扩展统一入口)
  • reference-code/Yuxi/web/src/views/DataBaseInfoView.vue(知识库详情页)
  • reference-code/Yuxi/web/src/views/DashboardView.vueDashboard 可观测性)
  • reference-code/Yuxi/web/src/composables/useAgentStreamHandler.js(流式事件状态机)
  • reference-code/Yuxi/backend/package/yuxi/agents/backends/sandbox/paths.py(虚拟路径安全)

上位依据:

  • ARCHITECTURE.md
  • CURRENT_ARCHITECTURE.md
  • design/07-ai/done/7-50-lightrag-knowledge-rag-provider-v1.md
  • design/07-ai/done/7-57-yuxi-reference-ai-run-config-knowledge-facade-v1.md
  • design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md
  • design/03-rust-web/reference/3-23-sidebar-local-folder-resource-runtime-followup-v1.md
  • design/10-review/done/16-mnote-web-runtime-module-maintainability-checklist-v1.md

1. 第一结论

Yuxi 有六个工程模式值得 MNote 借鉴,但不适合整体搬移:

  1. 中间件分层工具组合Hermes tool manifest 当前是扁平 Vec,每次新增能力(knowledge base、skills、MCP、filesystem、subagent、summary)都在同一个 manifest 函数中线性追加。Yuxi 的 middleware 模式把每种能力作为独立层,按需组合。
  2. 扩展管理统一入口:当前 MNote 的 Skills/MCP/Knowledge Base/Tools 入口分散在 settings、Page AI settings、侧边栏等不同位置。Yuxi 的 ExtensionsView 用 tab 统一管理所有扩展。
  3. 知识库详情设置页:当前 LightRAG settings 较薄,只有 source directory 和 basic status。Yuxi 的 DataBaseInfoView 提供了文件管理、检索配置、图谱配置、评估等完整详情页。
  4. 流式事件状态机规范化:当前 Hermes SSE/WS 事件处理分散在多个 consumersidebar runtime、document adapter、Page AI sidebar)。Yuxi 的 handleStreamChunk 是单一状态机,覆盖 init→loading→stream_event→finished/interrupted/error 全生命周期。
  5. 本地 Dashboard:当前 MNote 没有本地可观测性面板。Yuxi 的 Dashboard 提供了 agent run 调用量、token 消耗、知识库检索次数、工具调用频率等可视化。
  6. 虚拟路径安全:当前 WorkspacePath 校验较松散。Yuxi 的 sandbox paths 有 validate_thread_id + relative_to 防穿越、虚拟路径前缀隔离、按 thread/user 分层。

这些都属于 MNote 现有主线的 enhancer,不改变底层(Hermes ACP / Reasonix / LightRAG / Rust SSR),不引入新存储或新 agent 框架。

2. 非目标

  • 不引入 LangGraph / DeepAgents 作为 agent runtime。
  • 不复制 Yuxi 的 Milvus / Neo4j / Postgres 存储体系。
  • 不把 Vue/Ant Design 前端模式迁入 Rust SSR / browser runtime。
  • 不改变 LightRAG 作为唯一知识库 provider 的定位。
  • 不新增定时轮询刷新。
  • 不改变 local-first 普通 Markdown 编辑主路径。
  • 不改变 7-57 已完成的 run journal / agent descriptor / knowledge facade 成果。

3. 六个借鉴领域详析

3.1 中间件分层工具组合

Yuxi 模式

class ChatbotAgent(BaseAgent):
    async def get_graph(self, context=None, **kwargs):
        middlewares = [
            create_agent_filesystem_middleware(...),   # 文件系统
            save_attachments_to_fs,                    # 附件落地
            KnowledgeBaseMiddleware(),                 # 知识库检索
            SkillsMiddleware(),                        # Skills 注入
            create_subagent_task_middleware(context),  # 子智能体
            summary_middleware,                        # 上下文压缩
            TodoListMiddleware(...),                   # 任务列表
            PatchToolCallsMiddleware(),                # 工具调用修复
            ModelRetryMiddleware(max_retries=2),       # 模型重试
        ]
        return create_agent(model=..., tools=..., middleware=middlewares, ...)

每个中间件是独立类/函数,按声明顺序构成 agent 的能力栈。新增能力只需新增一个 middleware,不改动 agent 核心流程。

MNote 当前状态

manifest.rs 中 Hermes tool manifest 是扁平 Vec<Value>,约 30+ 个工具在一个函数中线性追加。新增 knowledge_rag、skills、context、block、onlyoffice 等工具时,每次都在同一个 manifest 函数末尾追加,没有按能力域分组。

pub fn manifest() -> Value {
    let tools = annotate_tools_with_capabilities(vec![
        skill_read_tool(),
        context_snapshot_tool(),
        // ... 30+ tools
        available_tool("mnote.artifact.create_summary", ...),
    ]);
    // ...
}

借鉴方向

不是引入 Python 式 class middleware,而是把 Rust manifest 按能力域拆成独立 registry 模块,每个模块自声明工具和能力:

hermes_tools/
  manifest.rs          → 顶层装配,组合各 registry
  registry/
    context_registry.rs    → context.* 工具组
    doc_registry.rs        → mnote.doc.* 工具组
    block_registry.rs      → mnote.block.* 工具组
    page_registry.rs       → mnote.page.* 工具组
    knowledge_rag_registry.rs → mnote.knowledge_rag.* 工具组
    skill_registry.rs      → mnote.skill.* 工具组
    mindmap_registry.rs    → mindmap.* 工具组
    onlyoffice_registry.rs → onlyoffice.* 工具组
    artifact_registry.rs   → mnote.artifact.* 工具组

每个 registry 暴露 pub fn tools() -> Vec<Value>pub fn capabilities() -> Vec<&'static str>。manifest 只负责装配和 capability annotation。Agent descriptor 可以按 capability 选择性包含工具组。

3.2 扩展管理统一入口

Yuxi 模式

ExtensionsView.vue 用一个 tab 组件统一管理四种扩展:

智能体扩展
  ├── 知识库(管理员可见)
  ├── 工具(管理员可见)
  ├── MCP(管理员可见)
  └── Skills(所有用户可见)

每种扩展是独立子组件,通过 tab 切换懒加载。URL query 参数持久化当前 tab,刷新后不丢失。

MNote 当前状态

  • Skills 入口:Page AI settings → Skills 子面板
  • Knowledge base 入口:settings → 资料库 settings
  • MCPHermes MCP 配置在 Hermes workspace settings
  • Tools:无独立管理入口,Hermes tool manifest 是编译期静态

这四个入口分散在不同 settings surface,用户需要记住去哪找。

借鉴方向

在 settings 页面增加"扩展"tab(或在现有 settings IA 中统一),按权限分组:

设置
  ├── 通用
  ├── 外观
  ├── 编辑器
  ├── 扩展 ← 新增
  │   ├── 知识库(LightRAG 资料库管理)
  │   ├── Skills(已安装 + 可用)
  │   ├── MCP 服务器
  │   └── Agent 工具状态(只读能力清单)
  ├── AIHermes / Reasonix 配置)
  └── 关于

第一阶段不要求完整 CRUD,先做只读能力清单 + 已安装 Skills/MCP 状态展示 + 知识库详情入口。URL hash 持久化当前 tab。

3.3 知识库详情设置页

Yuxi 模式

DataBaseInfoView.vue 是知识库详情页,子 tab 包括:

  • 文件管理:文件夹树、上传、解析状态跟踪(pending/processing/done/error)、批量删除、文件预览
  • 检索测试:输入 query → 展示检索结果 + 相似度分数 + 来源文件
  • 检索配置:向量/BM25/混合检索模式选择、TopK、相似度阈值、BM25 权重
  • 图谱配置:实体抽取 schema、关系类型约束
  • 评估:检索质量评估、问答对测试
  • 设置:名称、描述、嵌入模型、分块策略、共享配置

MNote 当前状态

LightRAG settings 较薄,只有:

  • source directory 配置
  • ingest 触发按钮
  • 基本状态灯(indexed / pending
  • OCR 开关

借鉴方向

在不改变 LightRAG provider 的前提下,增强 knowledge base settings UI

  1. 文件管理面板:展示已 ingest 文件列表、解析状态(parsing/chunking/indexing/done/error)、文件类型图标、最后更新时间
  2. 检索测试面板:输入 query → 直接调 /api/knowledge-rag/search → 展示 top-K 结果 + citation preview + 来源文件 + 相关度
  3. 检索参数配置search modelocal/global/hybrid/naive/mix)、top_k、相似度阈值(expose LightRAG QueryParam 可配置项)
  4. Ingest 状态跟踪:LightRAG 后台完成状态通过现有 status bridge/backoff 同步到 UI,展示每个文件的 stage 和 error

不新增:

  • 分块策略 UI(由 LightRAG 管)
  • 图谱 schema 编辑(由 LightRAG 管)
  • 嵌入模型切换(由 LightRAG 管)

3.4 流式事件状态机规范化

Yuxi 模式

useAgentStreamHandler.jshandleStreamChunk 是一个规范的状态机:

┌─────────────────────────────────────────────┐
│                  stream start                │
└─────────────────┬───────────────────────────┘
                  │
     ┌────────────▼────────────┐
     │  init                   │ ← 建立 request_id 绑定
     │  → replyLoadingVisible  │
     └────────────┬────────────┘
                  │
     ┌────────────▼────────────┐
     │  loading                │ ← message_delta / tool_call_delta
     │  → push msgChunks       │
     └────────────┬────────────┘
                  │
     ┌────────────▼────────────┐
     │  stream_event           │ ← tool-started / tool-finished
     │  → 关联 tool_call_id    │    agent_state (todos/uploads)
     └────────────┬────────────┘
                  │
     ┌────────────▼────────────┐
     │  finished / interrupted  │ ← terminal
     │  / error / approval      │
     └──────────────────────────┘

关键设计点:

  • 每种 status 有明确的过渡规则
  • stream_event 中的 tool-finished 通过 tool_call_id 关联到对应 AI 消息
  • agent_state 事件同步 todos/uploads 等运行时状态
  • 中断(approval/interrupted)有独立的恢复路径

MNote 当前状态

Hermes SSE/WS 事件处理分散在多个 consumer:

  • sidebar-page-ai-runtime.js 处理 Page AI 面板的流式回复
  • document-editor-adapter-runtime.js 处理编辑器内的 agent 交互
  • 每个 consumer 有自己的事件解析和状态管理

借鉴方向

不是引入 Vue composable,而是在 browser runtime 中抽出一个共享的 AgentStreamEventRouter

// rust/crates/mnote-web/browser/agent-stream-event-router.js

const EVENT_STATES = {
  INIT: 'init',
  LOADING: 'loading',
  STREAM_EVENT: 'stream_event',
  FINISHED: 'finished',
  INTERRUPTED: 'interrupted',
  ERROR: 'error',
  APPROVAL_REQUIRED: 'approval_required',
};

function createAgentStreamRouter({ onDelta, onToolCall, onToolResult, onAgentState, onTerminal }) {
  return function routeEvent(event) {
    switch (event.status) {
      case EVENT_STATES.INIT:
        // 建立 request_id ↔ message 绑定
        break;
      case EVENT_STATES.LOADING:
        // 判断 message_delta / tool_call_delta → onDelta / onToolCall
        break;
      case EVENT_STATES.STREAM_EVENT:
        // tool-started / tool-finished → onToolResult
        // agent_state → onAgentState
        break;
      case EVENT_STATES.FINISHED:
      case EVENT_STATES.INTERRUPTED:
      case EVENT_STATES.ERROR:
        onTerminal(event);
        break;
      case EVENT_STATES.APPROVAL_REQUIRED:
        // 中断等待用户确认
        break;
    }
  };
}

Page AI sidebar runtime 和 document editor adapter 都消费同一个 router,各自提供自己的 onDelta/onToolCall/onTerminal 回调。

3.5 本地 Dashboard

Yuxi 模式

Dashboard 包含:

  • 调用统计:按时间线的 agent run 次数、成功/失败率
  • 用户活跃度DAU/MAU、会话时长
  • AI 智能体分析:各 agent 调用量排行
  • 工具调用监控:各 tool 被调用次数、耗时
  • 知识库使用情况:检索次数、文件数、chunk 数

MNote 当前状态:无 Dashboard。

借鉴方向

为 local-first 场景做最小 Dashboard

  1. Agent Run 统计(基于 7-57 run journal):最近 N 天 run 次数、平均耗时、成功/失败/中断分布
  2. Token 消耗(基于 run journal 中的 token usage):按 agent、按日期维度
  3. 知识库状态(基于 LightRAG status bridge):已索引文件数、总 chunk 数、最近 ingest 时间
  4. Skills/MCP 健康:已安装 skill 数、MCP 连接状态

数据源优先级:

  • Agent run 统计:SQLite control-plane agent_runs 表(7-57 已建)
  • Token 消耗:从 run journal 中提取
  • 知识库状态:LightRAG /status API + MNote status bridge
  • Skills/MCPHermes workspace 配置 + Rust manifest

不新增:

  • 多用户统计(local-first 不需要)
  • 实时推送更新(10 分钟 TTL + 手动刷新即可)
  • 独立的时序数据库

3.6 虚拟路径安全加固

Yuxi 模式

沙盒路径的关键安全设计:

# 1. ID 安全校验
_SAFE_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$")

def validate_thread_id(thread_id: str) -> str:
    if not _SAFE_ID_RE.match(value):
        raise ValueError("thread_id contains invalid characters")

# 2. 虚拟路径前缀隔离
def get_virtual_path_prefix() -> str:
    return "/" + VIRTUAL_PATH_PREFIX.strip("/")  # /sandbox-v1

# 3. 路径穿越防护
def resolve_virtual_path(thread_id, virtual_path, *, uid):
    # 必须从虚拟前缀开始
    # 用 relative_to 校验不穿越 base_dir

# 4. 按 thread/user 分层
# workspace/ → 用户级共享
# uploads/   → 线程级
# outputs/   → 线程级

MNote 当前状态

WorkspacePath 主要通过 allowed_roots 做目录白名单校验,但没有:

  • 线程级隔离(同一用户的多个 agent run 共享同一文件系统视图)
  • 虚拟路径前缀(agent 直接看到宿主机真实路径)
  • 正则 ID 校验

借鉴方向

不是引入 Yuxi 的 Python sandbox,而是在 Rust WorkspacePath / AiAccessScope 中加固:

  1. Agent 可见路径使用虚拟前缀agent 通过 mnote://workspace/mnote://uploads/ 等虚拟路径引用文件,MNote 在 tool 边界做映射
  2. Run 级临时目录隔离:每个 agent run 有独立 mnote://runs/{run_id}/outputs/,不污染 workspace
  3. 路径穿越防护:所有 agent 发来的路径必须在 allowed roots 内,且经过 canonicalize + starts_with 双重校验
  4. Attachments 目录agent 上传/生成的附件落 mnote://attachments/{run_id}/,与 workspace 文件明确分开

第一阶段只加固现有 AiAccessScope + allowed_roots,不改变 agent 现有文件操作语义。

4. 执行优先级

批次 内容 优先级 预计影响面
Batch A Hermes tool registry 模块化拆分 manifest.rs 重构,不改变 API
Batch B 扩展管理 settings 入口 + 能力清单 settings UI,不改变后端
Batch C LightRAG 知识库详情页(文件管理 + 检索测试 + 检索参数) knowledge-rag settings UI + 少量 API
Batch D AgentStreamEventRouter 抽共享 browser runtime 重构,不改变 API
Batch E 本地 Dashboard 最小版 新页面 + SQLite 查询
Batch F WorkspacePath 虚拟路径安全加固 AiAccessScope 增强,agent tool 适配

5. Checklist

Batch AHermes tool registry 模块化拆分

  • A1. 在 hermes_tools/ 下创建 registry/ 子目录
  • A2. 把 manifest.rs 中工具按能力域拆到独立 registry 模块
    • A2a. context_registry.rscontext_snapshotcontext_read_current_pagecontext_resolve_target
    • A2b. doc_registry.rsdoc_fetchdoc_finddoc_markdown_editdoc_apply_block_opsdoc_plan_update
    • A2c. block_registry.rsblock_fetchblock_replaceblock_insert_afterblock_deleteblock_move_after
    • A2d. page_registry.rspage_getpage_savepage_update_titlepage_update_options
    • A2e. knowledge_rag_registry.rsknowledge_rag_statusknowledge_rag_queryknowledge_rag_section_contextknowledge_rag_open_reference
    • A2f. skill_registry.rsskill_readskill_*
    • A2g. mindmap_registry.rsmindmap_fetchmindmap_apply_opsmindmap_create_from_outline
    • A2h. onlyoffice_registry.rs:所有 onlyoffice_* 工具
    • A2i. artifact_registry.rsartifact_* 工具
  • A3. 每个 registry 暴露 pub fn tools() -> Vec<Value> + pub fn capability_names() -> &[&str]
  • A4. manifest.rs 改为装配层:收集各 registry 的 tools + 统一 capability annotation
  • A5. cargo test -p mnote-web hermes_tool_manifest --lib 通过
  • A6. Agent descriptor smoke 验证 manifest 返回的工具列表与拆分前一致(scripts/task557-page-ai-agent-descriptor-smoke.js

Batch B:扩展管理 settings 入口

  • B1. 在 settings 页面增加"扩展"tab,路由 /settings?tab=extensions
  • B2. 扩展 tab 包含子面板:知识库、Skills、MCP、Agent 工具
  • B3. 知识库子面板:展示 LightRAG 当前状态 + 已索引文件数 + "管理"按钮 → 跳转知识库详情
  • B4. Skills 子面板:展示已安装 skill 列表(名称、版本、状态、来源)
  • B5. MCP 子面板:展示已配置 MCP 服务器列表(名称、URL、连接状态)
  • B6. Agent 工具子面板:从 /api/page-ai/agent-descriptors 读取能力清单,只读展示
  • B7. URL query 参数持久化当前子 tab(&ext=knowledge|skills|mcp|tools
  • B8. 登录态浏览器验证:settings → 扩展 tab,切换子面板,刷新后 tab 不丢失

Batch CLightRAG 知识库详情页

  • C1. 新增知识库详情页路由 /knowledge-base
  • C2. 文件管理面板
    • C2a. 展示已 ingest 文件列表(文件名、类型图标、大小、状态灯、最后更新时间)
    • C2b. 状态灯映射:pending/parsing/chunking/indexing/done/error,每 30s 有界刷新(来自 status bridge
    • C2c. 文件删除按钮(调 mnote.knowledge_rag.delete 或 LightRAG API
    • C2d. 手动 re-index 按钮(单文件)
  • C3. 检索测试面板
    • C3a. 输入框 + 搜索按钮 → 调 /api/knowledge-rag/search
    • C3b. 结果列表:citation preview + 来源文件 + 相关度分数
    • C3c. 点击结果 → open_reference 打开对应资源
  • C4. 检索参数配置面板
    • C4a. search mode 下拉:local/global/hybrid/naive/mix
    • C4b. top_k 数字输入(1-100
    • C4c. 相似度阈值滑块(0.0-1.0
    • C4d. 保存到 user_ui_preferencesSQLite control-plane
  • C5. Ingest 源目录管理:展示当前 source roots + 添加/移除(只改 MNote source registry,不动 LightRAG 配置)
  • C6. 登录态浏览器验证:知识库详情页三个面板切换、检索测试真实返回结果、参数保存后刷新不丢失

Batch DAgentStreamEventRouter 抽共享

  • D1. 在 rust/crates/mnote-web/browser/ 创建 agent-stream-event-router.js
  • D2. 定义标准事件类型 enuminit/loading/stream_event/finished/interrupted/error/approval_required
  • D3. 实现 createAgentStreamRouter({ onDelta, onToolCall, onToolResult, onAgentState, onTerminal }) 工厂函数
  • D4. sidebar-page-ai-runtime.js 改为消费 AgentStreamEventRouter
  • D5. document-editor-adapter-runtime.js 改为消费 AgentStreamEventRouter(如涉及编辑器内 agent 交互)
  • D6. 浏览器 smoke 回归:Page AI 对话、tool call 展示、中断恢复、finished 状态均正常
  • D7. scripts/task*-page-ai-*.js 相关 smoke 通过

Batch E:本地 Dashboard 最小版

  • E1. 新增 /dashboard 路由 + 页面壳
  • E2. Agent Run 统计卡片
    • E2a. 后端:GET /api/dashboard/agent-run-stats?days=7 → 返回 run 总数、成功/失败/中断分布、按 agent 分组
    • E2b. 前端:卡片 + 简易柱状图(按天分布)
  • E3. Token 消耗卡片
    • E3a. 后端:从 agent_runs 表提取 token usage 汇总(总 token、按 agent 分组)
    • E3b. 前端:数值卡片(本周消耗 / 总计)
  • E4. 知识库状态卡片
    • E4a. 后端:代理 LightRAG /status + MNote status bridge,返回文件数、chunk 数、最近 ingest 时间
    • E4b. 前端:数值卡片 + 状态灯
  • E5. Skills/MCP 健康卡片
    • E5a. 后端:从 Hermes workspace 配置 + Rust manifest 汇总
    • E5b. 前端:列表 + 状态灯
  • E6. 所有卡片使用 10 分钟 TTL + 手动刷新按钮,不做实时推送
  • E7. 登录态浏览器验证:Dashboard 页面展示各卡片数据

Batch FWorkspacePath 虚拟路径安全加固

  • F1. 在 AiAccessScope 中增加 run_id 字段
  • F2. 实现 AgentVirtualPath 类型:mnote://workspace/mnote://outputs/{run_id}/mnote://uploads/{run_id}/
  • F3. 在 Hermes tool 边界做虚拟路径 ↔ 真实路径映射(resolve_agent_path / to_agent_virtual_path
  • F4. 路径穿越防护:canonicalize + starts_with(allowed_root) 双重校验
  • F5. Run 级临时目录:每个 agent run 开始时创建 mnote://outputs/{run_id}/run 结束时清理
  • F6. Agent tool smoke 验证:agent 只能访问 allowed roots 内文件,路径穿越被拒绝

6. 与现有设计的关系

现有设计 本稿关系
7-57 Batch A (run journal) 本稿 Batch E (Dashboard) 消费 run journal 做统计
7-57 Batch B (agent descriptor) 本稿 Batch B 的工具清单面板消费 descriptor
7-50 (LightRAG provider) 本稿 Batch C 是其 UI 增强
7-18 (agent file editing) 本稿 Batch F 加固其 AiAccessScope
3-23 (sidebar local folder runtime) 本稿 Batch B/C 在 settings 中增加入口
7-38 (Page AI sidebar owner split) 本稿 Batch D 是 sidebar runtime 的事件路由重构

7. 风险

  • Batch A 重构 manifest:如果工具名或 capability annotation 在拆分中漂移,会导致 agent descriptor 不一致。必须用 smoke 对比拆分前后的 manifest JSON。
  • Batch C 检索参数LightRAG QueryParam 的字段可能随版本变化。MNote 透传用户配置时应做字段白名单,未知字段忽略。
  • Batch D 事件路由重构:如果 browser runtime 中的事件格式在不同 consumer 间有细微差异(例如 Page AI 用 message_ideditor 用 msg_id),统一 router 时需要兼容映射。
  • Batch E DashboardSQLite agent_runs 表可能膨胀。后续需要 TTL 清理策略,当前阶段保留最近 30 天。
  • Batch F 虚拟路径agent 端(Hermes / Reasonix)需要能处理 mnote:// 前缀,或 MNote 在 tool 边界双向映射。第一阶段先只映射,不要求 agent 原生理解虚拟路径。

8. 验证基线

  • cargo test -p mnote-web --lib 全绿
  • scripts/task557-page-ai-agent-descriptor-smoke.js 通过
  • scripts/task529-knowledge-rag-citation-resource-tab-smoke.js 通过
  • scripts/task530-knowledge-rag-page-ai-final-answer-smoke.js 通过
  • 新增 smokescripts/task561-extensions-settings-smoke.jsBatch B+C
  • 新增 smokescripts/task561-dashboard-smoke.jsBatch E
  • 登录态浏览器验证:settings 扩展 tab、知识库详情页、Dashboard 页面均可正常访问