Repository navigation
Releases: Rail1bc/astrbot_plugin_testbench
Releases · Rail1bc/astrbot_plugin_testbench
Release list
v1.0.5
🎨 UI / UX (交互与布局)
- 会话面板拖拽改为仅从「≡」手柄发起:面板默认不可拖拽,手柄按下时临时开启、拖放结束(dragend / mouseup)复位——之前
panel.draggable = true会抢占文本选择,复制会话窗口里的对话时鼠标拖动就成了拖拽窗口;页眉不再显示拖拽光标(改由手柄显示 grab 光标),面板头 title 提示同步更新。 - 修复「消息流」切换按钮溢出群发栏:概览列(220px)内「轮次对齐 + 消息流」控制组无处换行时溢出列宽、与「群发消息」标题重合——
.run-overview-head改为允许换行、统计文本加截断、控制组内部也可换行。
🛠 Bug Fixes (修复)
- 修复弹窗常驻「是否放弃修改」确认条(v1.0.2 潜在回归,v1.0.4 修复弹窗打开后暴露):
.modal-actions与.modal-confirm都声明了display: flex,但缺少.类名[hidden] { display: none; }显式覆盖规则(仓库内已有十余处同类规则,如.modal-mask[hidden]/.panel-pending[hidden],唯独弹窗内这两个漏了)——作者样式会覆盖浏览器默认的[hidden]隐藏行为,导致所有弹窗同时显示「是否放弃修改」确认条与取消/确定操作区。补上.modal-actions[hidden]/.modal-confirm[hidden]规则。 - 新增前端 hidden 一致性回归测试(
tests/frontend/hidden_css.test.mjs):静态校验「带 hidden 属性(或被 JS 以.hidden切换)且 CSS 声明了display的类,必须存在[hidden]覆盖规则」,防同类漏网再犯。
v1.0.4
🛠 Bug Fixes (修复)
- 修复全部弹窗无法打开(v1.0.2 回归):
index.html的弹窗操作按钮容器<div class="modal-actions">缺少id="modal-actions",而 v1.0.2(TB-03 dirty 确认条)起modal.js通过$("modal-actions")(getElementById)访问它——恒为null,openModal一执行即抛TypeError: can't access property "hidden", $(...) is null,组/会话配置、删除/重置确认等所有弹窗打开即失败(v1.0.1 的 modal.js 不引用该 id,故为 v1.0.2 引入的回归)。补回缺失的id="modal-actions"。 - 新增前端 id 一致性回归测试(
tests/frontend/page_ids.test.mjs):静态校验页面 JS 中$("…")/getElementById("…")引用的每个 id 均须在index.html中定义、且index.html不得出现重复 id——防 HTML / JS 两侧不同步再次漏网(本次漏改正是此类问题,且此前测试仅覆盖pure.js纯函数)。
v1.0.3
⚙️ Compatibility (兼容性)
- 最低兼容版本修正为 astrbot >=4.26.0:插件 Web API 依赖
astrbot.api.web(PR #8688 的 Quart→FastAPI 迁移引入,首个包含版本为 v4.26.0;4.24.1/4.25.x 均无此模块)——原>=4.24.1声明不实(v4.24.1 的 subscribeSSE 不足以支撑本插件),metadata.yaml 修正为>=4.26.0。
🧹 Chores / Refactoring (重构与工程化)
- 后端测试按域拆分(TB-09):7719 行单文件拆为
tests/fakes.py(28 个公共辅助/Fake 类)+test_runner/test_stores/test_testset/test_assessor/test_api五个测试文件(283 个顶层定义零遗漏归位),导航/分跑/合并成本显著下降。 - CI 只跑上游最新版(TB-05 最终定案):pytest.yml 改为
pip install astrbot(不写死版本,随上游发版自动跟进),安装步骤打印实际版本便于按日志定位上游变更;曾尝试「最低支持版 4.26.0 + latest」双矩阵,但固定旧版本在全新 runner 环境安装/运行不可靠(旧版重依赖解析失败),且与用户实际使用场景(总是跑最新 AstrBot)脱节——砍掉固定版本 leg;framework_internal标记保留作语义标注(最新版全量运行);「跳过数为 0」守卫(TB-29)保留,缺 astrbot 整组跳过时 CI 直接报错。
v1.0.2
🐛 Bug Fixes (修复)
- 持久化写入原子化 + 损坏文件备份(TB-01,数据安全):全部 store 的
_save改为「写临时文件 +os.replace原子替换」,崩溃/断电不再留下半截 JSON;_load解析失败时把损坏文件改名备份(*.corrupt-<ts>)并记告警日志,而非静默从空开始(下一次保存会把「空」写回、用户数据永久丢失)。 - 在途条「完成」条目不再残留(TB-02):
loadHistory/loadStream成功后立即重渲染在途条(events.js 新增renderAllPendingStrips入口),消息流视图同步补写historyRefreshedAt——完成且已刷入历史的条目即时消失。 - 弹窗误关丢表单防护(TB-03):
openModal新增dirty选项(8 处表单弹窗启用),取消/遮罩点击/Esc 对已修改内容先显示内联确认条(不销毁表单 DOM),确认后才关闭;补 Esc 关闭、Tab 焦点圈定、关闭后焦点还原与aria-labelledby。 - 单发/群发失败保留输入(TB-08):入队成功后才清空输入框,网络/后端失败时原文保留可直接重试。
⚙️ Reliability (可靠性)
- API 列表元素级校验(TB-06):
sessions/ids元素须为非空字符串(dict/list 元素此前使dict.fromkeys/set抛 TypeError → 500);conf_id/provider_id/model补字符串校验(非字符串 conf_id 曾可能污染 UCR 路由表);评审重试targets防不可哈希。 - CI 双矩阵锁定 astrbot(TB-05):pytest.yml 改为
astrbot==4.24.1(最低支持版)+4.26.6(已实测版)矩阵,pytest 系锁定;直接依赖内部模块的 3 条用例标framework_internal并在最低版矩阵跳过;新增「跳过数为 0」守卫(TB-29),缺 astrbot 整组跳过时 CI 直接报错。 - 测试 flaky 消除(TB-04):4 处固定
asyncio.sleep(0.05)竞态窗口改为wait_until轮询(路由恢复 ×2、历史重生成 ×2)。
🎨 UI / UX (交互改进)
- 报告生成/批量重试防重(TB-07):同一报告的 LLM 生成与批量评审重试在途时忽略重复点击,按钮置灰 + 「生成中…/重试中…」,完成后恢复。
- 历史刷新不再强制拉回底部(TB-15):向上翻阅时反馈刷新保持阅读位置,仅原在底部/初始加载才滚动。
- 视图切换刷新一致(TB-16)/ 桥接超时可见错误(TB-17)/ 身份搜索防抖(TB-18)/ 报告加载失败重试(TB-19)/ 组会话数量减少提示(TB-20):一批交互细节补齐。
- a11y 补齐(TB-21):tab 按钮
role="tab"/aria-selected、图标按钮aria-label、视图切换按钮文案「切换到 X」消歧义。
🧹 Chores / Refactoring (重构与工程化)
- 在途条清理触发点补全(TB-10):
pending_entries()顺带_prune_runs,无新测试时已完成条目也按时清理。 add_group_sessions总数上限(TB-12)/update_group严格类型校验(TB-13):与 clone_sessions / update_session 同口径。- 死代码与重复实现清理(TB-22/23/24):删除未使用的
clearStream导出与未消费导出;Provider 下拉抽为utils.js providerOptions()共享;重连/防抖/截断魔法数字提为具名常量。 :has()布局规则改修饰类(TB-26):checkbox 标签布局不再依赖老内核 WebView 不支持的:has();清理.ruff_cache/.pytest_cache/__pycache__残留;函数内 stdlib import 提顶。- 文档如实化(TB-11/14/25):CLAUDE.md 依赖声明改为「公共 API 为主 + 唯一内部路径助手 + 3 条 framework_internal 用例」的准确描述,并显式声明插件仓库中文注释约定;评审时机语义(单步失败/中止不评审)写入 README 与 CLAUDE.md 并有锚定测试。
🧪 Testing (测试)
- 新增 10 条测试:损坏文件备份(TB-01)、评审时机跳过(TB-14)、真并行在途与乱序完成(TB-28)、EventBus 慢消费者不阻塞 / StreamStore 损坏行容忍 / SSE 端点 / final_rules 组合兜底(TB-30);后端测试 251 → 259。
v1.0.1
🧹 Chores / Refactoring (重构与工程化)
- 新增插件图标 logo.png:AstrBot 插件管理页自动识别插件根目录的
logo.png并展示。
📝 文档与工程化(Docs & Chores)
- README 细化新手引导:修复「三步开始」流程断链(新建测试组默认 0 会话,须先经 ✎ 编辑设置「会话数量」才能打开会话)、修正「使用流程」中已移除的「添加」按钮描述(新增会话走编辑弹窗「会话数量」);配置项表格补全「会话数量 / 消息类型」,并新增「对比不同提示词 / 配置 / 模型」用法提示——在 AstrBot 框架本体建多个配置档案,测试组内每个会话绑定不同档案,群发同一句话并排对比差异。
- README 开发者章节改为贡献者流程:移除「直接推送到 dev」的维护者流程表述,统一为 fork + 向 dev 提 PR(CI 在 PR 上自动把关);本地测试命令路径改为克隆仓库后的通用形式。
v0.4.5
🐛 Bug Fixes (修复)
- 运行器消息流写入失败不再挂起运行(HIGH):
_await_event的流回填调用包 try/except——stream_store.update_reply/append抛错(磁盘故障等)时记录日志后继续,done/test_done完成判定恒执行,运行不会挂到STALE_RUN_TIMEOUT/TESTSET_STEP_TIMEOUT超时。 - 「+ 新建测试组」改为直接建 0 会话空组、不再弹编辑弹窗:此前创建即弹编辑弹窗,点取消测试组也已被创建(含 1 个会话);现
create_group允许count=0创建空测试组,前端直接建组留在列表、不弹窗,用户按需点 ✎ 编辑补配置与「会话数量」。 - 全 POST handler 非 dict JSON 体不再 500:
api/common.py新增json_dict()统一读取 helper,全部 POST handler(api/ 下 28 处 +history_ops的save_history/regenerate_history2 处,共 30 处)的request.json(default={})调用点替换——数组 / 标量 / null 请求体统一返回 400「请求体必须是 JSON 对象」,不再因.get触发 AttributeError → 500。 - 配置档案嵌套键类型错误不再崩溃:
conf_tool_info对非 dict 的provider_settings/proactive_capability按空对象处理(配置被手改坏时list_confs/list_groups不再 500)。 - 测试集消息清洗容忍非 dict 项:
_normalize_messages对非 dict 消息项直接跳过(直调 store 时不因.get崩溃)。 - 前端事件流订阅建立即失败可重连:
connectEvents主体包 try/catch,subscribeEvents初始 reject 时同样延迟 3s 重连(此前只在断线回调里重连,首次订阅失败事件层本会话报废)。 - 历史 / 消息流加载失败回退缓存:
loadHistory/loadStream的失败分支优先渲染state.historyCache/state.streamCache已有内容,仅无缓存时才显示错误(瞬态失败不再摧毁已渲染好的面板)。 - 群成员变更异步失败有反馈:
removeMember/addMember/saveChatGroupName的 API 失败包 try/catch 并显示错误状态(此前 unhandled rejection + 零反馈)。 - 报告视图加渲染序号守卫:
renderReportView两个 await 之间切换测试集 / 视图时丢弃乱序迟到响应,不再渲染错对象的运行 / 报告。 - 「+ 新建测试集」未保存修改先确认:
openNewTestset有脏编辑时弹 danger 确认(此前createTestset后clearDirty把未保存编辑静默丢弃)。 - segmentLabel 缺 steps 不崩溃:运行记录缺
steps字段时回退「第 N 步」文案。 - 弹窗保存失败不再关闭、丢失表单内容:
modal.js的 ok 回调先执行onOk,失败时弹窗保持打开、#modal-error内联显示错误(此前新建评审 Profile 不合规时弹窗先关、已填内容全部丢失);打开新弹窗前清除上次错误提示。 - 固定规则不再显示评审 Profile 选择器:
.ts-msg-rule-llm声明了display: flex,覆盖[hidden]属性 UA 默认的display: none——导致非 LLM 类型(如「包含」等固定规则)也显示 profile / 上下文下拉;补.ts-msg-rule-llm[hidden] { display: none; }显式隐藏(沿用.groups-card[hidden]等既有修复 pattern)。 - 同根因
display:flex覆盖[hidden]的 3 处遗漏(对抗性审计发现,顺带修复):.ts-report-body(「编辑 / 报告」切换时报告体不隐藏,切回编辑视图后报告内容仍显示在表单下方)、.cg-members(未选群聊时成员编辑区仍占位)、.panel-pending(无在途消息时消息条空占一行)——各补[hidden] { display: none; }。
✨ New Features (新功能)
- 断言组合算子 any / not(testset-redesign v2 收尾①):消息规则支持任意组(至少一条通过)与取反——
rules列表元素 = 叶(机械或 LLM)|{op:"any", rules:[叶...]}(任一子规则通过即组通过)|{op:"not", rule:叶}(取反),顶层隐式 all(全部 entry 通过才整步通过);评估由Assessor._eval_entry递归(机械子叶恒评估、LLM 子叶在组已被决定为通过后短路跳过;每 entry 一条 verdict,组 verdict 的metrics为全部子叶拼接、detail说明「任意(至少一条通过):X/Y 子规则通过」;not 取反子 verdict 的 pass,子 pass None(评审失败)不取反);顶层短路语义不变(机械未过 → 后续 LLM 跳过)。final_rules 不支持组合(保持单叶)。前端规则区新增「+ 任意组」按钮(组行.ts-msg-rule-group,组内子行隐式 all、不嵌套)与叶行「取反」checkbox(.ts-msg-rule-not,机械与 LLM 叶都提供);pure.js 新增buildAnyGroupRule/buildRule的not参数 /collectRules识别kind:"group";store / API 不做规则键白名单,组合节点天然透传。 - 报告按 3 类组织(testset-redesign v2 收尾②):报告详情弹窗改为「统计 / 详情 / LLM 报告」3 tab——统计为纯聚合不展开会话(
metrics_summary指标聚合行 + 新增「断言:通过 X / 失败 Y(共 Z)」data.assertions与「耗时:平均 / 最小 / 最大 / p50 / p95(N 条)」data.durations+ 评审失败数;后端build_assertion_stats只数 pass 非 None 的 verdict、build_duration_stats收集全部 done 步骤 × 会话的数字耗时);详情为完整执行数据(逐步骤×会话×verdict 明细 + 导出原始数据);LLM 报告按测试集配置的report_llm一键生成。 - LLM 生成报告(testset-redesign v2 收尾③):测试集新增报告 LLM 配置
report_llm({provider_id, system_prompt?, model?}——缺省模型用 Provider 当前模型,与评审 profile 一致;编辑视图报告开关下方配置,保存随测试集持久化);报告条目按钮「生成 / 重新生成 LLM 报告」调新端点POST /reports/<report_id>/llm-report(报告完整 JSON 作为 prompt 发给报告 LLM,成功落data.llm_report = {status, text, provider_id, model, generated_at}并持久化,重新生成覆盖);报告详情弹窗 LLM 报告 tab 用新增的markdown 受限子集渲染器(pages/testbench/render_markdown.js:parseMarkdown/parseInline零 DOM 依赖纯函数 +renderMarkdownBlocks(blocks, doc)渲染——文本一律经textContent/createTextNode落(LLM 输出是数据不是代码,绝不拼 innerHTML),链接safeHref仅放行 http(s)/mailto、其余置 "#",防 XSS)。
🔄 Changed (行为变更)
- 评审 Profile 不再单独配模型:
validate_profile移除「model 必填」(省略时评审用 Provider 当前模型,call_reviewer传model=None);表单删除模型输入框,Provider 下拉显示「供应商(当前模型)」,列表模型徽标按 Provider 当前模型解析;保存 / 编辑 profile 时顺带清除旧数据遗留的显式 model。 - 新消息默认 0 条断言:测试集编辑视图新消息默认不再渲染 1 条「无」类型空断言行,按需点「+ 断言」添加。
- 消息框改为 textarea 可纵向拉伸:消息文本从单行
<input type="text">改为<textarea>(全局resize: vertical),长文本可纵向拉大,消息可含换行。 - LLM 规则 slice 上下文可配范围切片:消息级 LLM 规则选「范围切片记录」后新增范围输入(
rule.slice_range,0 基闭区间,格式同最终断言范围「2-4 / 3 / 空=全部」);后端Assessor._slice_entries按范围切片喂给评审 LLM 的记录并钳制边界(越界裁剪 / 倒序空 / 非法回退全部),未配范围时与 record 等效。 - 切片范围支持多段:切片范围输入可写多个段(逗号分隔,如
3-4,10-12),rule.slice_range扩展为 0 基闭区间列表(仍兼容旧版单段 dict 存量数据);Assessor._slice_entries逐段切片拼接(越界裁剪 / 倒序段跳过 / 形状非法回退全部);前端parseSliceRange/sliceRangeToText为多段解析与编辑回填(纯函数层,node:test 覆盖)。 - 状态条消息内容固定高度、过长滚动:
.run-status直接内联当前消息内容(测试集运行进度含完整 stepText),长文本 / 多行消息会把状态条顶高、挤压下方视图;限高(max-height 72px)+ 纵向滚动查看并保留换行(pre-wrap)——常态生效,不限于执行测试集。 {{agent_system_prompt}}占位符弃用,被测 agent 系统提示词改由规则级开关注入:占位符展开依赖评审 Provider 把 system_prompt 真正传给评审 LLM——部分 Provider 忽略 / 改写 system_prompt,内容到不了评审 LLM;改为 LLM 断言规则级「注入提示词」开关(rule.inject_system_prompt,缺省开启,显式 false 才落盘)把被测 agent 的装饰后系统提示词注入评审输入(prompt)开头(【被测 Agent 系统提示词】标签块,Assessor.inject_system_prompt_block)——prompt 是所有 Provider 必传的,对该问题天然免疫;call_reviewer不再接收 / 展开占位符,残留字面量清成空串;verdict 的agent_system_prompt字段保留作信息(评审重试用存储的context_text,已含注入内容,自包含)。- 未捕获到被测 agent 系统提示词时注入块仍存在:开启注入(缺省)时评审输入恒以
【被测 Agent 系统提示词】标签块开头——捕获到内容则注入全文,未捕获 / 为空则显示占位文案「(未捕获到被测 agent 系统提示词)」,报告评审详情可直观确认注入链路状态,不再与未开启注入的表现无异(此前无快照时该块整个消失,排查困难)。 - 注入块改前后闭合标签 + 空系统提示词时回退解析人格:注入块由单侧标签
【被测 Agent 系统提示词】改为前后闭合的【以下是被测 Agent 系统提示词】…【以上是被测 Agent 系统提示词】,长提示词也能清晰区分块边界(沿用中文标签块,避免与注入的 XML 标记冲突);同时on_llm捕获到req.system_prompt为空时(开场对话(begin_dialogs)型人格把身份文本注入req.contexts对话历史而非 system_prompt,这类会话的快照系统提示词恒为空)回退从会话配置档案解析人格(persona_manager.resolve_selected_persona,经会话 umo + 会话级 persona_id + 档案 provider_settings,镜像框架装饰路径),把人格提示词与开场对话补进快照,评审 LLM 仍能看到被测 agent 的人格设定;解析失败 / 无人格回退未捕获占位;回退解析关键决策点打[testbench]前缀 INFO 日志(是否执行 / default_personality / 会话级 persona / 命中人格及内容规模),供排查「未捕获」。 - 人格回退解析抽到 eval/persona.py,评审阶段也回退(不依赖捕获 hook):回退解析实现(
format_persona_snapshot/conversation_persona_id/resolve_agent_system_prompt)从 main.py 抽到共享模块eval/persona.py,on_llm捕获时回退改为薄包装;Assessor在步骤结果无llm_input快照 / 快照系统提示词为空时(捕获 hook 未触发或 begin_dialogs 型会话)评审阶段也调用同一份实现从会话配置档案解析人格补进评审材料——修复「未捕获」不依赖捕获链路,且评审输入恒带被测 agent 人格;评审阶段从对话存储回查会话级 persona_id(conversation_persona_id,防御式,失败回落档案 default_personality),结果按 umo 记忆(同一次运行内多次命中只解析一次);日志改走根astrbotlogger——插件的专用 logger 支持按插件调级,INFO 日志可能被静默过滤,根 logger 与 AstrBot 自身模块记法一致、排查更可靠。
🧪 Tests (测试)
- 后端 +5:运行器流写入失败仍完成、
_normalize_messages非 dict 项、conf_tool_info嵌套错型、_scope_indices边界钳制、非 dict 请求体 400(223 → 228)。 - pure.js 动态测试 +7:buildRule 未知类型回退、信封缺 messages / 版本非 number / 非字符串 text / 畸形 final_rules、ruleFailCount 空 verdicts 回退、segmentLabel 缺 steps(35 → 42 断言组)。
- 前端静态检查 +1:
test_frontend_defensive_fixes防御性改动静态标记(59 → 60)。 - 前端静态检查 +1:
test_frontend_modal_error_keeps_content弹窗 onOk 失败保留表单内容(60 → 61)。 - 后端模型可选随测更新:
test_validate_profile_ok_and_errors/test_call_reviewer_ok_and_statuses/test_plugin_reviewer_crud覆盖省略 model、model=None调用与无 model 创建(228 不变)。 - 后端 +1:
test_assessor_message_rule_slice_range消息规则 slice_range 切片 / 缺省回退 / 边界钳制(228 → 229)。 - pure.js 动态测试 +4:buildRule slice_range 分支(slice 空范围 / 区间 / 单步 / 非 slice 忽略,42 → 46 断言组)。
- pure.js 动态测试 +5:多段切片范围(buildRule slice 多段、parseSliceRange 空 / 多段 / 非法、sliceRangeToText 回填,46 → 51 断言组)。
- 前端静态检查 +1:
test_frontend_message_editor_defaults_and_slice默认 0 断言 / textarea / hidden 修复 / slice 输入标记(61 → 62)。 - 前端静态检查 +1:
test_frontend_run_status_scroll状态条消息限高滚动标记(62 → 63)。 - 后端 +2:
test_inject_system_prompt_block注入块纯函数 +test_assessor_inject_system_prompt_rule_level规则级注入开关(缺省注入 / 显式 false 不注入 / 无 llm_input 快照注入占位块)(229 → 231)。 - 后端 +4:
test_format_persona_snapshot人格快照纯函数、test_resolve_persona_system_prompt_defensive回退解析防御式(无 persona_manager / 解析异常 / 无人格 → 空串)、test_resolve_persona_system_prompt_from_conf从配置档案解析(prompt + 开场对话合入、会话级 persona_id 与 umo 透传)、test_plugin_on_llm_persona_fallback空 system_prompt 时 on_llm 回退补人格(231 → 235)。 - 后端 +1:
test_assessor_persona_fallback评审阶段回退解析人格(结果无 llm_input 快照时从配置档案补上、会话级 persona 回查失败回落档案、同 umo 结果 memo 只解析一次)(235 → 236)。 - 前端静态检查 +1:
test_frontend_llm_rule_inject_system_prompt注入开关静态标记(editor_js 的.ts-msg-rule-inject复选框 / collectRules 透传 / 占位符废弃文案 / css 样式,63 → 64)。 - pure.js 动态测试 +3:buildRule 注入开关分支(缺省与 true → 不带
inject_system_prompt、显式 false → 字段、collectRules 透传 injectSystemPrompt)(51 → 54 断言组)。 - 后端 +15(236 → 251):组合算子 any/not 递归评估(全过 / 部分过 / 全不过 / not 取反 / not 内 LLM / any 内 LLM 短路 / 顶层短路不回归 / 空组与未知形状容错 / 组 verdict 契约)、store 透传组合节点、报告断言统计
build_assertion_stats/ 耗时统计build_duration_stats(error/invalid 与短路跳过不计入、全 done 步骤)、report_llm 存储清洗 / API 校验 / LLM 报告生成端点(成功产物落data.llm_report并持久化、重新生成覆盖、未配置 400 / Provider 缺失 400 / 报告不存在 404 / 数据损坏 400 / 调用异常 400 不落库)。 - pure.js 动态测试 +7:buildRule not 包裹(机械 / LLM 叶)、not=false / 空类型不包裹、buildAnyGroupRule 空子输入 → null、组节点收集、collectRules 识别 kind="group"(组内 not 子叶保留)、空组与无效组内行丢弃(54 → 61 断言组)。
- 新增
tests/frontend/render_markdown.test.mjs(node:test,13 断言组):parseInline 纯文本 / 粗斜体 / 行内代码 / 链接混排、parseMarkdown 标题 / 代码块 / 分隔线 / 无序有序列表 / 表格 / 单行 | 降级段落 / 空行与非法输入容错、renderMarkdownBlocks 块结构 / 表格 thead+tbody / HTML 注入文本按文本渲染(不产生注入元素) / 链接协议白名单(javascript: 置 "#")——node --test总数 61 → 74。 - 前端静态检查 +5(64 → 69):
test_frontend_combo_rule_ui(「+ 任意组」/ 组行 / 取反 checkbox / buildAnyGroupRule / op 节点形状)、test_frontend_report_three_tabs(统计 / 详情 / LLM 报告 3 tab 与断言 / 耗时统计行)、test_frontend_render_markdown_module(模块存在 / 导出纯函数 / 零依赖 / 不拼 innerHTML / safeHref)、test_frontend_report_llm_form(编辑器 report_llm 表单与保存 payload、api.js 封装)、test_frontend_report_llm_button_and_pane(生成按钮按配置显隐、LLM 报告 tab 渲染器接入)。
v0.4.4
🧹 Chores / Refactoring (重构与工程化)
- 巨型文件拆分(Phase 4):
testset_editor.js(1456 行)的报告视图拆到新模块pages/testbench/testset_reports.js(348 行)——createReportView(deps)工厂持有「编辑 / 报告」视图切换状态(viewMode)、最近运行 / 持久化报告列表 / 指标聚合总览 / 详情弹窗 / 导出 / 删除 / 评审重试全部随迁,编辑器只保留#btn-ts-mode切换按钮绑定与renderTestsetEditor末尾按当前视图刷新报告页的入口(reportView.syncViewModeUI()/reportView.isReportMode());getDeps经闭包包装取最新绑定(setDeps会重赋值编辑器闭包变量)。testset_editor.js降到 998 行。配套:前端 ES module 清单(_FRONTEND_MODULES与 CI js-check 循环)加入testset_reports,test_frontend_report_editor_toggle/test_frontend_report_list_actions断言重定向到新模块。
v0.4.3
⚡ Performance (性能优化)
- 身份库 sender_id → is_admin 惰性索引(Phase 3):
IdentityStore新增is_admin_of(sender_id)——按sender_id惰性构建管理员身份索引(create_identity/update_identity/delete_identities写操作后失效、下次查询重建),runner 的_resolve_role改走该 O(1) 查询,不再在每次发送时对身份库全量线性扫描(身份数量增长时避免每次群发都 O(n) 比对)。语义不变:任一身份命中(sender_id精确匹配且is_admin为真)即按管理员处理,未命中 / 旧数据缺is_admin键一律普通成员。
v0.4.2
🧹 Chores / Refactoring (重构与工程化)
- 前端纯函数抽取到零依赖模块
pure.js,新增 node:test 动态测试(Phase 2):把testset_editor.js/testset_run.js的纯逻辑(collectEditorRows/parseScope/parseTestsetEnvelope/buildRule/collectRules/rangesFromFlags、verdict 计数ruleFailCount/ruleReviewFailCount、段文案segmentLabel/segmentSummary与配套常量RULE_VALUE_TYPES/EXPORT_FORMAT/EXPORT_VERSION)抽到pages/testbench/pure.js——不引用 DOM / state / 其它模块,页面模块经import复用同一份实现(防两处漂移),并新增tests/frontend/pure.test.mjs用 Node 内置node:test(零依赖)做行为测试;pytest.yml的 js-check job 追加node --test命令,仓库根新增package.json声明type: module(node 可直接加载页面 ES module,无 npm 依赖)。
v0.4.1
✨ New Features (新功能)
- 持久化写路径去阻塞:全部 store(测试组 / 身份 / 群聊 / 测试集 / 评审 profile / 报告)的同步写方法保持同步签名,API 层与异步编排(测试集运行报告生成)经新增
AsyncWriteMixin.write(store/_base.py)锁内线程化执行——asyncio.to_thread把全量写 JSON 移出事件循环线程(不再阻塞 LLM / 消息处理),实例级asyncio.Lock串行化 read-modify-write + 落盘(防并发写丢更新)。群消息流(StreamStore)改为 JSONL 追加写(streams.jsonl):磁盘只记append/reply两种 op 记录,clear/ 删除会话 / 压缩时才全量重写(reply_status烘焙进消息),行数达阈值(10000)自动压缩——热路径不再反复全量重写整个文件。测试集运行终态广播增加一次报告生成完成后的终态快照:_drive_segments先广播终态(report_id尚为 None),_drivefinally 生成报告后重发终态快照,前端 SSE / 轮询者能拿到含report_id的最终快照。 - 评审 Profile 表单新增
{{metrics}}展开内容实时预览与复制:编辑输出指标时,表单实时显示{{metrics}}占位符展开后的完整内容(逐字段取值要求 + 示例输出,经新接口POST /reviewers/preview由评审运行时的metrics_contract_description直接计算,保证预览与实际展开字节级一致、前端不镜像格式化逻辑);预览与占位符共存——{{metrics}}照常自动展开,也可点「复制预览」把展开内容复制到提示词手动修改后使用(任选其一或同时存在)。复制按钮带剪贴板回退:navigator.clipboard→document.execCommand("copy")→ 选中预览内容提示手动 Ctrl+C(插件页 iframe 沙箱未授予allow-clipboard-write,自动复制可能被拒)。表单同时新增{{agent_system_prompt}}占位符提示(展开为被测 agent 的装饰后系统提示词,未捕获时为空串)。 - LLM 评审材料改为结构化「实际输入 + 输出」:单轮(reply 模式)评审不再只给回复文本——现在包含该轮完整输入与输出,并用中文标签块明确标注身份与分界(
【输入 · user(发送者)】/【输出 · agent(virtual_bot)】,多轮 record / slice 模式每轮带「第 N 步:」前缀、轮间空行分隔)。材料中的输入是实际喂给被测 LLM 的输入而非测试集原始文本:插件经 AstrBot 原生 LLM 阶段 hook(on_llm_request)在调用前快照装饰后的req.prompt与req.extra_user_content_parts(框架 / 插件注入的<system_reminder>、知识库结果、附件标记等),随结果摘要(llm_input)进入评审上下文;未捕获到快照时回退原始文本。快照在 hook 处渲染为纯字符串,不存组件对象引用(随 SSE 事件与报告 JSON 序列化)。同时评审 profile 的system_prompt新增{{agent_system_prompt}}占位符——展开为被测 agent 的装饰后系统提示词(来自同一快照),由用户在评审提示词中自行编排;未捕获时展开为空串(不残留字面量占位符)。verdict 持久化存储agent_system_prompt,报告评审重试(/reports/<id>/reviews/retry)重跑时自动透传,评审材料不包含被测 agent 的 system_prompt。 - 新增主动消息与异步补发检测警告:虚拟会话无法收到插件主动发送的消息(定时任务到点触发的问候 / 话题等),此前这类回复被静默漏掉、测试结果呈「无回复」且无任何提示。现测试台在运行启动时探测 cron 定时任务(AstrBot 公开 API
list_jobs/get_next_run_time):active_agent 任务的payload.session投递目标与虚拟会话 umo 精确匹配、basic 任务 payload 做浅层启发式扫描(深度 2,命中虚拟 umo / 会话 id 才警告),命中项作为运行级警告(含任务名 / 类型 / 表达式 / 投递目标 / 下次运行时间与说明)随运行记录与事件流呈现——手动群发启动前同步探测、测试集运行启动后后台探测,前端在运行状态条(「⚠ N 条主动消息警告」)、结果表格弹窗顶部警告块与面板状态中提示。检测是增强:cron_manager 未初始化 / 枚举失败一律降级为无警告,不破坏测试本身。同时 runner 新增异步补发检测窗口:pipeline 结束后再观察一小段时间(生产装配 1s,构造缺省 0 保持旧行为与测试速度),窗口内 fire-and-forget 补发的回复不计入结果(摘要已冻结),仅在面板状态行标记「pipeline 结束后又有 N 条回复到达(插件异步补发)」——如实告知有回复被漏掉;检测不是捕获,长延时 / 外部触发来源无法覆盖,其计划根源由 cron 探测兜住。 - 评审 Profile 放开为多个实例并把管理入口迁到左侧测试集列表:左侧「测试集」卡片以 tab 拆分「测试集 / 评审 Profile」(镜像身份实体与身份池的列表 + modal 表单管理模式),profile 的创建 / 编辑 / 删除在列表中完成(每条显示 Provider · 模型 · 评审上下文 · 指标数徽标 + 编辑 / 删除);不再限制只能有一个 profile——消息规则 / 最终断言按
profile_id引用,创建第二个不再被 API 拒绝;编辑窗口内的 Profile 摘要区随之移除,消息规则 / 最终断言行内 profile 下拉在 profile 增删改后自动重建(防 stale)。 - 测试集消息模型升级:断言规则由单条
rule扩展为rules规则列表(每条消息可配多条断言,按全部通过判定;旧数据与旧信封单条rule自动迁移),新增命令标记is_command(预期触发框架行为而非 LLM 回复的消息,勾选后随消息持久化);编辑器消息行改为「文本行 + 下方多断言列表」结构(类型下拉 / 断言值 / 删除 + 「+ 断言」添加,min_len/max_len 值须为整数,空值规则保存时静默丢弃并带行号提示)。 - 测试集新增身份配置:可设单一身份(single,整集消息恒用该身份发送,消息级身份下拉随之隐藏)或身份池(pool,消息行身份下拉列出池成员、按成员选择);保存时把被引用身份的完整数据内联快照进测试集(自包含,身份 / 群聊删除后测试集仍可运行),单身份快照含
is_admin(管理员身份发送时event.role自动为"admin")、身份池快照为群聊名 + 成员身份列表;测试集运行记录记录每条消息的解析后发送者与管理员标记。 - 测试集导出 / 导入信封升级到 v2:信封携带身份配置(single →
identity快照;pool →pool身份池),导入复用创建端点、不创建身份 / 群聊记录(内联快照直接可用);解析兼容 v1(单条 rule → rules 列表)与 v2(rules / is_command / identity / pool),版本号高于当前版本拒绝。 - 新增身份管理员配置(is_admin)与发送时自动角色:测试身份实体新增「是否管理员」勾选(新建默认非管理员,旧数据零迁移);发送虚拟消息时按发送身份是否为管理员自动设置
event.role(管理员 →"admin",否则"member")——此前虚拟事件恒为"member",开启computer_use_require_admin(默认开启)的配置下虚拟会话永远无法通过计算机工具的管理员权限门控,现可按身份模拟不同权限身份。管理员身份在身份列表以徽标标注,并带「⚠ 危险」警告提示(管理员可调用需管理员权限的工具、可能执行危险操作),身份表单勾选管理员时即时显示内联警告条;身份表单管理员单选框改为 checkbox 在前、与标签同行显示(不再独占一行),群聊编辑视图成员行同时显示昵称与发送者ID,管理员成员挂「管理员」+「⚠ 危险」徽标。 - 新增工具安全警告:创建 / 编辑测试组与会话级配置档案覆盖时,若所选配置启用了任何可调用的工具(
computer_use_runtime为 local/sandbox、web_search、kb_agentic_mode、proactive_capability.add_cron_tools——缺省即开启,故默认配置本身即命中),弹窗内即时显示内联警告条(不阻塞提交);测试组列表按组与全部会话的有效配置实时计算安全标记(⚠ 工具),配置档案事后内容修改会随列表刷新更新(标记派生、不持久化);GET /confs每个档案新增has_callable_tools布尔。 - 新增群聊虚拟会话支持:测试组 / 会话新增「消息类型」配置(私聊 FriendMessage / 群聊 GroupMessage,默认私聊、旧数据零迁移),群聊消息的 umo 变为
平台:GroupMessage:会话id——只监听GROUP_MESSAGE的插件(如主动回复类插件)现在能被虚拟会话触发;消息类型变更视同 umo 变更,自动清理旧 umo 的路由与对话历史。 - 新增自动@(auto_at)(群聊消息,默认开启):开启时模拟「@机器人 发言」,消息链以 At(机器人自身) 开头、消息文本保持纯文本,唤醒检查直接命中(
is_at_or_wake_command置位);关闭时消息以未唤醒状态进管道,只能被 filter 通过(如 Heartflow)唤醒——用于测试「不 @ 就不回复」的主动回复插件。auto@ 是发送时选项而非组/会话配置:群发栏新增「自动@」勾选框(默认开启,群聊消息生效),测试集每条消息也可单独配置是否@(消息行 @ 勾选框,导入导出信封保留 auto_at 字段、旧文件缺省按开启),旧组/会话配置里的 auto_at 键自动清理。 - 新增测试身份(
name / sender_id / sender_name三元组)与虚拟群聊(名称 + 成员池member_ids)两个跨测试组共享的持久化资源,经 UI 窄条第三个按钮「身份与群聊」视图集中管理;群聊测试会话可绑定一个虚拟群聊,投递消息时自动取成员池首个身份作为默认发送者(优先级:消息级身份 > 绑定群聊默认成员 > 会话/组手动 sender > 默认 testbench)。 - 「身份与群聊」视图交互改型:左侧卡片内以 tab 拆分「身份」/「群聊」两个列表(身份膨胀后群聊列表不被长列表挤走);创建虚拟群聊只填名称(成员多选移出弹窗——成员多时窗口放不下),成员管理移到新增的右侧「群聊编辑」视图——搜索身份池(按名称 / 发送者ID / 昵称实时过滤、已在群内成员排除)点「+ 加入」、成员行可「✕」移除、名称可改;删除群聊后编辑视图回到空态。
- 群聊编辑视图界面优化:群成员列表与搜索结果优先展示昵称(sender_name,无昵称回退发送者ID,悬停显示完整信息)而非裸 ID——成员多时按昵称识别更直观;左侧身份条目可拖拽到右侧群聊编辑视图的成员区快速加入该群(拖入时成员区虚线高亮提示,drop 即加入;未选中群聊 / 身份已在群中给出明确提示而非静默无效)。
- 新增群消息流持久化:每个虚拟会话记录与 LLM 对话历史并行的纯消息流(user 发言含发送者身份与 @ 标记、bot 回复,按时间序,不注入 LLM 上下文),面板页头新增「LLM 历史 ↔ 消息流」切换按钮;重置会话清流、删除会话删流,单会话上限 500 条超出截断最旧。
- 新增唤醒状态 / 无回复原因反馈:no_reply 区分「未唤醒」(
not_woken)与「已唤醒但无回复」(woken_no_reply),结果摘要携带wake字段(woken / at_or_wake / stopped / llm_requested),面板可据此判断消息是否真正唤醒机器人。 - 新增动态身份:群发栏身份选择器可给整批消息指定身份,测试集每条消息也可单独指定身份(消息行新增身份下拉,导入导出信封保留可选 sender 字段,向后兼容旧文件);新增长后端接口:
GET/POST /identities、POST /identities/delete、POST /identities/<id>/update、GET/POST /chat-groups、POST /chat-groups/delete、POST /chat-groups/<id>/update、GET /sessions/<id>/stream、POST /sessions/stream/clear。 - 会话视图历史中的工具调用与工具返回改为结构化气泡:助手消息带
tool_calls时逐个渲染工具调用气泡(summary 即工具名、展开查看美化后的参数 JSON,默认收起防长参数撑开面板),不再以裸「(调用工具…)」占位符挂在思维链下——思维链内出现工具调用时(think 部件与 tool_calls 同消息)工具调用以独立气泡紧随思维链渲染;role: "tool"的返回消息渲染工具返回气泡,头部经tool_call_id关联标注「哪个工具的返回」,正文即返回内容;非 JSON 参数原样显示、空返回显示占位。 - 新增「测试集」视图(UI 窄条第二个按钮):测试集是一组连续 user 消息序列,可对单个 / 多个会话做多轮对话的纵深测试(命令 → 子命令 → 参数确认 → 结果)、提示词/插件改动后的回归(同一序列反复跑)与连发/追问压测。支持 CRUD、每条消息可带回复断言规则(正则 / 包含 / 不包含 / 合法 JSON / 非空 / 字数 / 前后缀),后端以 Python 正则评估、结果随运行返回(✓/✗)。
- 测试集支持批量发送范围(batch_ranges):测试集内按消息勾选「批量」、连续勾选自动合并为一个批量段,段内消息立即连续发出(重叠)、段外消息逐条发送(等上一步全部会话完成);可设多个批量段(每段 ≥1 条),运行发送节奏完全由测试集自身决定、不再在运行时选「逐条 / 批量」模式;侧栏「最近运行」列出历史运行,可点「查看」找回结果(含运行中的继续跟踪)。
- 测试集运行由后端后台任务驱动,与页面生命周期解耦:离开 / 刷新页面不中断后续步骤,返回后经「最近运行」可继续查看进度与结果;运行可随时「取消」(当前步骤完成即止、后续不再发);单步 10 分钟超时安全阀防止一条悬挂消息拖死整个测试集,运行记录超时自动清理。新增 8 个 Web API:
GET/POST /testsets、POST /testsets/delete、POST /testsets/<id>/update、POST /testsets/run、GET /testsets/run/status、POST /testsets/run/abort、GET /testsets/runs。 - 群发不再阻止重叠发送:agent 处理上一条消息时可再次群发(真实「重复追问」场景,与真实平台一致由 AstrBot 原生 pipeline 并发处理)。已打开会话面板底部新增在途消息条,实时显示每条消息「已入队 / 排队等待 LLM / LLM 生成中 / 完成」四个阶段——前三个阶段经 AstrBot 原生 LLM 阶段 hook(
on_waiting_llm_request/on_llm_request)观察,只读不干预 pipeline。 - 平台来源完全移除
virtual_test,默认改用webchat(与 AstrBot WebUI 一致);发送者 id / 昵称默认改为testbench/测试台。 - 群发栏新增实时统计:显示当前打开的会话数量,并标注各会话来源的测试组分布(如「当前会话:8 提示词测试组:5 模型测试组:3」)。
- 面板头部新增「编辑」按钮:以 JSON 编辑器整体查看 / 替换该会话的
{conversations: [...]}结构化对话历史(编辑单条消息、新增或删除对话都在 JSON 中完成),取代原先逐条消息的编辑;气泡保留「重新生成」。按钮文案后由「历史」更名为「编辑」(功能不变)。 - 会话面板页眉改为多行布局:标题与测试组 / 平台 / 配置徽标随内容长度自动换行并撑开页眉,不再溢出截断;「编辑 / 置顶 / 关闭」操作按钮始终固定在第一行右对齐。
- LLM 回复气泡新增思维链折叠显示:带推理内容(
think部件)的回复默认收起,点击「展开思维链」即可查看,再次点击收起;轮次对齐模式下展开 / 收起后自动重排对齐高度。 - 左侧布局重构:最左新增 UI 窄条(方形按钮 ☰「会话列表」/ ✎「测试集」),点击当前视图按钮折叠 / 展开侧栏,点击另一视图按钮切换视图;移除「创建测试组」表单块与独立「测试组列表」块,改为单一列表——列表内含「+ 新建测试组」块(点击即创建默认配置测试组,随后弹出编辑弹窗)+ 测试组块(点击展开组内会话)。
- 新增测试组编辑弹窗:可修改组名、会话数量(保存时若少于目标值自动新增)、平台来源、配置档案、发送者 id 与昵称;组配置变更同步应用到仍继承组配置的会话(新增后端接口
POST /groups/<id>/update,会话已单独覆盖的字段不受影响)。 - 会话可在列表内展开查看配置:逐项显示有效值与「已修改 / 继承组」状态标识,会话头显示「已改 N」汇总徽标;会话配置的修改统一走展开配置中的「编辑配置」弹窗。
- 左侧会话行操作收敛为「打开 / 删除」:移除「配置」按钮,「重置」按钮移至已打开会话的面板页眉(编辑 / 重置 / 置顶 / 关闭)。
- 群发栏移至工作区下方(已打开会话面板在上、群发在右下),轮次对齐滑动条位于面板与群发栏之间。
- 界面重构:右侧工作区视图随左侧列表选择自动切换(不设手动切换按钮)——☰「会话列表」→ 会话视图(已打开会话面板 + 群发栏),✎「测试集」/ 选中测试集条目 → 右侧测试集编辑窗口;测试集列表条目收敛为「有名字的条目」,创建即得到命名条目,消息编辑 / 运行 / 导出 / 删除统一在编辑窗口完成(不再条目内联展开);会话视图顶部新增常显状态条(测试集运行进度 + 取消按钮,两个视图下都常显),已打开会话面板加一层块包裹。
- 群发栏新增测试集执行:
执行测试选择测试集后直接对全部已打开会话运行,进度显示在常显状态条、逐步骤刷新,完成后弹结果表格(批量段步骤带「批量」徽标)。 - 测试集运行目标新增「选择测试组」:可多选测试组,勾选组解析为该组全部会话 id(含未打开的会话)作为目标,运行弹窗只需选目标会话、不再选发送模式。
- 测试集导出 / 导入:编辑窗口可将测试集导出为 JSON 文件(带
format/version信封,为未来「测试集市场」从网络下载兼容预留),可导入已有测试集 JSON 文件(复用创建端点,无新后端接口);导入校验信封格式与版本,非法文件弹窗报错不创建。 - 会话面板页眉新增「⋯」菜单:编辑历史(JSON 编辑器入口,原页眉「编辑」按钮收敛进菜单)、重置历史(清空对话)、复制历史(复制当前会话全部对话历史到剪贴板,跨会话可用,刷新页面后清空)、克隆会话(同测试组内新建 N 个会话,对话历史与当前会话完全一致,可应用于同组配置下多会话对照)、粘贴历史(有复制内容时以剪贴板整体覆盖当前会话历史)、衍生测试组(基于当前会话的历史创建一个全新测试组,组内会话历史均与该会话一致,可命名 / 指定会话数,用于把一次成功调试沉淀为可复用的对照组);新增 2 个后端接口
POST /sessions/clone与POST /sessions/derive(复制与衍生分别按会话 / 按组拷贝原生对话历史)。 - 新增进程内事件总线
EventBus与/eventsSSE 事件流端点:runner / testset_runner 在状态变化点广播全量快照事件(在途pending、会话完成session_done、测试完成test_done、测试集进度testset,快照为发布时刻的拷贝),页面经插件页面subscribeSSE实时订阅,不轮询即可看到在途 / 逐会话 / 测试集进度实时更新;15s 心跳注释行防代理断连。兼容下限提升至astrbot_version: ">=4.24.1"(subscribeSSE 自该版本提供)。 - 测试组「打开全部」按钮改为**「打开全部 / 关闭全部」二态**:组内会话全部打开时按钮变为「关闭全部」,点击一键关闭本组全部已打开会话(只关属于本组的会话,其他组的会话不受影响);任一会话在会话视图中被单独关闭后按钮自动回到「打开全部」,点击只补开尚未打开的会话。
- 左侧列表的「+ 新建测试组」/「+ 新建测试集」按钮移至列表末尾(已有测试组 / 测试集下方),列表为空时紧随空态提示之下——新增入口不再抢占列表首屏,长列表下新建入口始终固定在底部可滚动到。
- 群发栏重构为从左到右三块:第 1 块(窄,仅显示状态)首行左对齐当前会话总数、右对齐「轮次对齐」开关,下方按测试组逐行列出分布(每行「组名:N」,条目多时可上下滚动);第 2 块为群发消息输入框 + 发送按钮;第 3 块为测试集选择 + 执行按钮。原先输入框与测试集选择框横跨整行过长,现收敛为各块内自适应宽度。
- 新增评审层(LLM 断言):测试集从纯机械断言扩展为「机械 + LLM」两层,机械规则全部通过才调 LLM(短路控制成本与不确定性)。新增跨测试集共享的评审 Profile(
name / note / provider_id / model / system_prompt / context(reply|record|slice) / metrics指标声明——类型必须配置声明、不能运行时推断,报告聚合依赖它;system_prompt 支持{{metrics}}占位符自动展开为已收集指标;Provider / 模型为测试集级显式配置,避免用被测模型自评)——评审 Profile 的管理入口在左侧「测试集」卡片的「评审 Profile」tab(列表 + 新建 / 编辑 ...