Commit Graph

252 Commits

Author SHA1 Message Date
sinohqb
f433ebb970 feat(campaigns): dual-axis periodic report (time trend + capability)
Add generate_campaign_report: a pure aggregator over a campaign's child Runs
producing a time-trend axis (Runs bucketed by service-window position) and a
capability-summary axis (grouped by scenario), each carrying pass_rate /
availability / latency. pass_rate keeps the single-Run case-level meaning and
counts execution failures as 0.0 (ADR-0002); time_scale only places Runs into
window-time buckets and never alters any figure. Engine summary now records
avg_latency_ms to feed the latency axis.

Expose GET /api/campaigns/{id}/report (structured) and .../report/markdown
(reusing the existing Markdown export path). Adds "可用性/Availability" to the
domain glossary.
2026-07-30 13:55:32 +08:00
sinohqb
8910fd17e0 feat(campaigns): durable scheduler loop with restart recovery and cancel
Add a thin async loop (run_campaign_loop) that ticks on real wall-clock time,
maps elapsed×time_scale to a window offset via the pure decide_schedule, spawns
due child Runs, and marks the campaign COMPLETED at window end. All authority
lives in the DB (started_at, spawned_indices, status), so the app lifespan can
resume every RUNNING campaign on startup without double-spawning and stop all
loops gracefully on shutdown. A failing plan entry is skipped and recorded
rather than wedging the campaign.

Creating a campaign now starts its loop; POST /api/campaigns/{id}/cancel stops
further spawning (completed child Runs are kept); GET /api/campaigns/{id}
reports live progress (window offset, spawned/completed Run counts).
2026-07-30 13:33:10 +08:00
sinohqb
c6b102a9b5 feat(campaigns): add scheduling decision and child-Run spawning
Add the pure scheduling seam (campaign_scheduler.decide_schedule) that, given a
static plan and window-clock offset, decides which plan entries are due and
whether the window ended — mirroring judgement.combine_case_outcome, with
time_scale confined to the clock mapping so it never touches judgement/report.

The campaign_runner shell maps injected elapsed time to a window offset, spawns
due child Runs through the existing EvalEngine.run(existing_run=...) path with
campaign_id + RunTrigger.CAMPAIGN, and persists spawned-entry indices per entry
for idempotent, restart-recoverable progress. No auto loop yet (ticket 03).
2026-07-30 12:06:31 +08:00
sinohqb
e4404f1fa2 feat(campaigns): add Campaign persistence and create/query API
Introduce the 评估活动 (Campaign) aggregate above Run: a single-target,
service-cycle window driving a static plan. Adds Campaign/CampaignPlanEntry
models, CampaignDB table, nullable eval_runs.campaign_id, CampaignRepository,
Alembic migration, and POST/GET /api/campaigns with validation.

Ticket 01 of v0.6; no scheduling or child-run spawning yet (ADR-0003 v1).
2026-07-30 11:56:19 +08:00
sinohqb
af7e7bf110 docs(v0.6): add Campaign spec and 5 tracer-bullet tickets
Some checks failed
CI / test (push) Failing after 46s
.scratch/v0.6/spec.md:评估活动 v1(静态地基)规格——单对象、可配服务
周期窗口、耐久调度、双主轴周期报告、time_scale 时间倍速。5 张 tracer-
bullet 票(持久化/API → 调度决策+派生 → 耐久回路+恢复 → 双轴报告 →
前端页),依赖边 ①→②→③、②→④、①③④→⑤。
2026-07-30 11:45:13 +08:00
sinohqb
fe2a3f7579 docs(domain): add Campaign glossary terms and phasing ADR
Some checks failed
CI / test (push) Failing after 40s
领域建模拷问产出:CONTEXT.md 新增「周期评估」章节(评估活动 / 服务周期
窗口 / 活动计划);ADR-0003 记录活动分期(v1 静态地基、v2 自适应回路)
与「OpenClaw 进调度热回路」的取舍。
2026-07-30 11:12:57 +08:00
sinohqb
1345daddd2 feat(engine): make poll_reply timeout configurable via env
Some checks failed
CI / test (push) Failing after 45s
被评数字员工响应普遍逼近 30s 硬编码轮询超时,越线的轮次被记为无回复
(run 427b14bb round 2 实测 31.4s 超时)。新增
AGENTEVAL_POLL_REPLY_TIMEOUT(默认 30s),engine 未显式传入
timeout_config 时从 settings 取值,慢目标可放宽。
2026-07-30 09:58:08 +08:00
sinohqb
5db0ede4f4 refactor(judgement): converge case-pass decision into one deep module
Some checks failed
CI / test (push) Failing after 50s
「用例是否通过」此前散落 8 处且互相矛盾:engine 权威判定焊死在持久化里
不可单测;report 聚合/compare/markdown 各自从规则结果反推,规则还不一致
(markdown 用 all([]) 把故障用例误渲染成 )。

- 新增纯函数 evaluation/judgement.combine_case_outcome(RuleOutcome/
  CaseOutcome),判定组合脱离通道与 DB 可单测(判定矩阵 14 例)
- engine 调用它一次,逐用例权威结果写入 summary.case_outcomes(JSON,
  零迁移);report/compare/markdown 只读权威值,老 run fallback 反推
- 故障用例判 False(ADR-0002):修正 markdown 的  bug 与 compare 的
  None;顺带修 engine 连通用例无回复也算通过的 bug
- pass_rate 口径改为用例级(CONTEXT.md 词条),规则级保留在
  passed_rules/total_rules;CLI 对比标签同步更正
- 修 RunRepository.update 漏拷 scenario_version/triggered_by 的字段漂移
2026-07-29 19:45:02 +08:00
sinohqb
f1aa61edd0 chore: sync package-lock version to 0.5.0-dev
Some checks failed
CI / test (push) Failing after 41s
2026-07-29 15:43:29 +08:00
sinohqb
25b4c98dc8 docs(release): v0.5「准」发布说明与里程碑收尾
Some checks failed
CI / test (push) Has been cancelled
版本升至 0.5.0-dev;新增 release-notes-v0.5.md(判定语义 + 场景版本化
+ 领域文档基线);AGENT.md/AGENTS.md 更新里程碑路线图、判定语义速查与
CONTEXT.md/ADR 指引。
2026-07-29 15:43:15 +08:00
sinohqb
cbab55843b fix(reports): export via authed axios blob download instead of window.open
Some checks failed
CI / test (push) Failing after 2m50s
启用登录鉴权后,导出 HTML/MD/JSON 用 window.open 直连 API 无法携带
X-Auth-Token,服务端返回 401 导致导出失效。改为经 axios 拉取 blob
(拦截器自动附加凭据)后触发浏览器下载。
2026-07-29 15:35:34 +08:00
sinohqb
5dd3c4ff1c style(dashboard): redesign stat cards with fixed-height compact layout
Some checks failed
CI / test (push) Failing after 44s
累计执行卡片的“/ 今日 N”后缀按数值字号渲染导致换行、卡片高度不一。
StatCard 改为紧凑三行固定高度布局(标题/数值/副行),今日次数移到
副行小字显示,六张卡片高度一致。
2026-07-29 15:26:38 +08:00
sinohqb
d23b321225 fix(runs): mark orphaned running/pending runs failed on startup
Some checks failed
CI / test (push) Failing after 59s
评测任务是进程内 asyncio 任务,服务重启会中断执行且状态永远停在
running。启动时将遗留的 running/pending 运行标记为 failed(summary
写入 interrupted 错误),清理为尽力而为,不阻断启动。另将仪表盘最近
评测记录的触发方式与版本号标签位置对调。
2026-07-29 14:48:14 +08:00
sinohqb
fbac28bc7e feat(frontend): always show trigger source labels (手动/AI 助手/CLI)
Some checks failed
CI / test (push) Failing after 49s
运行列表、报告页运行下拉、仪表盘最近评测行不再隐藏手动标签;
报告头与对比 A/B 卡片新增"触发方式"(报告 payload 补 triggered_by)。
2026-07-29 14:34:32 +08:00
sinohqb
8e3cf82fcc feat(frontend): surface scenario version across dropdowns and views
Some checks failed
CI / test (push) Failing after 43s
场景启动下拉、报告页运行下拉(A/B)、场景筛选(版本范围 v1/v2)、
仪表盘最近评测行、场景预览与编辑弹窗标题统一带上考纲版本标识。
2026-07-29 14:20:09 +08:00
sinohqb
770d260750 feat(report): compare requires same scenario version (ticket 05)
Some checks failed
CI / test (push) Failing after 39s
对比报告可比性收紧为同场景同考纲版本(ADR-0001):跨版本 API 返回 400
(detail 含双方版本号),报告生成层抛 ValueError;前端对比候选按
同场景 + 同版本过滤,A 变更后自动清空不可比的 B。文档"尚未实现"标注移除。
2026-07-29 11:21:52 +08:00
sinohqb
0a47260237 feat(run): snapshot scenario version at run creation (ticket 04)
运行创建时快照场景考纲版本,三种触发来源(手动/AI 助手/CLI)一致;
迁移回填存量运行为其场景当前版本,孤儿运行回填 1。运行列表、
报告头与对比卡片展示 v{n} 版本标签。
2026-07-29 10:59:44 +08:00
sinohqb
43e05ee38d feat(scenario): system-maintained syllabus version (ticket 03)
场景新增整型 version(迁移回填 1,batch mode)。仅考纲字段
(cases / model_bindings / llm_config)变更时升版,元数据编辑不升版,
API 传入的 version 被忽略(ADR-0001)。前端场景列表展示版本标签。
2026-07-29 10:42:35 +08:00
sinohqb
8a526599ab feat(report): annotate connectivity cases and add judged pass rate (ticket 02)
报告层推导连通用例标记(无判定结果 + 每轮有回复 + 无用例级错误),
summary 新增 connectivity_cases 与 judged_pass_rate(无判定型用例时为 null)。
对比报告同步标注且连通用例按引擎口径计通过;总通过率口径不变(ADR-0002)。
2026-07-29 10:32:56 +08:00
sinohqb
5dd1bc8535 feat(engine): expectations now additive with explicit rules (ticket 01)
期望始终派生隐式判定并与显式规则叠加执行:rule_logic 只组合显式规则,
期望是叠加其上的硬约束,任一不满足即用例不通过。隐式判定以 EvalResult
同构落库,reason 前缀 [期望] 标明来源。连通用例(无规则无期望)行为不变。
2026-07-29 10:24:01 +08:00
sinohqb
2dcf415940 docs(v0.5): add spec and tracer-bullet tickets for judgement semantics & scenario versioning
Some checks failed
CI / test (push) Failing after 53s
范围:期望与规则叠加生效、连通用例报告标注、场景版本化(ADR-0001/0002 约束)。
工单 01-05 按依赖序编号,01/02/03 可并行,03→04→05 线性链。
2026-07-29 10:16:37 +08:00
sinohqb
e33922c3fe docs(domain): add domain glossary CONTEXT.md and first ADRs
Some checks failed
CI / test (push) Failing after 51s
拷问会话产出:14 条核心术语定义(评测对象/场景/用例/轮次/通过率/模型能力·用途等),
以及两项决策记录——场景版本化的可比性语义(ADR-0001)、通过率含执行失败的口径(ADR-0002)。
2026-07-28 21:46:56 +08:00
sinohqb
c2bc56effd fix(deploy): use npmmirror registry in volcengine-102 Dockerfile
Some checks failed
CI / test (push) Failing after 57s
npm ci hangs on volcengine-102 because package-lock resolved URLs
point to registry.npmjs.org (GFW-blocked). Force npmmirror before ci.
2026-07-28 19:54:24 +08:00
sinohqb
595409487b docs(release): v0.4「联」发布说明与里程碑收尾
Some checks failed
CI / test (push) Failing after 38s
- 新增 release-notes-v0.4.md(事故排查 + 功能总结 + v0.5 候选方向)
- AGENT.md 里程碑表更新至 v0.4 + 鉴权配置说明
- README / plan-v0.4 状态同步
2026-07-28 17:41:20 +08:00
sinohqb
9c564b575e feat(frontend): v0.4 login page, dashboard rebuild, reports UX, keep-alive refresh
- 登录页 + App 鉴权门 + X-Auth-Token 拦截器 + 菜单头部退出按钮
- 仪表盘重构:6 指标卡 / 趋势图 + 场景表现 / 最近记录 + 快捷操作 + 来源分布
- Reports 页重做:场景筛选、富选项下拉、allowClear、一键重置、同场景对比约束
- useOnTabActive:标签页激活自动刷新(根治 AI 助手评测记录"消失")
- ModelConfigs 12 列合并为 6 列;来源 Tag;chunk 告警阈值修正并记录原因
2026-07-28 17:41:08 +08:00
sinohqb
739d586aec feat(backend): v0.4 triggered_by tracking, login gate, compare guard, dashboard stats
- EvalRun.triggered_by 全链路(manual/ai_assistant/cli)+ 迁移 b7d4e6f81c22
- 标准 agenteval-run SKILL.md 纳入版本管理,deploy 脚本同步 + API Key 注入
- 简单登录:AGENTEVAL_ADMIN_PASSWORD + HMAC 会话 token,require_auth 双凭据
- 对比报告限同场景(400)+ 空 results 误判修复
- /api/stats/dashboard 扩展聚合;/api/runs 返回场景/对象名
- 测试 218 → 232
2026-07-28 17:40:54 +08:00
sinohqb
92f98c3af7 docs(release): add v0.3 release notes and minimal CI baseline
Some checks failed
CI / test (push) Failing after 2m59s
- 补齐 release-notes-v0.3.md,更新 AGENT.md 里程碑表与 README 至 v0.3 现状
- 新增 scripts/ci-check.sh(版本一致性 + ruff + pytest + tsc)
- 新增 .gitea/workflows/ci.yml 与本地 pre-push hook 约定
2026-07-27 16:51:45 +08:00
sinohqb
f1eb123dd1 fix: use GATEWAY_MODE=local for openclaw-eval 2026-07-20 17:26:00 +08:00
sinohqb
26a36f5bdb fix: add OPENCLAW_ALLOW_UNCONFIGURED env var 2026-07-20 17:24:43 +08:00
sinohqb
baba638fd5 fix: use private registry for openclaw image 2026-07-20 17:21:52 +08:00
sinohqb
d0831684ec fix(deploy): stamp head instead of upgrade to avoid duplicate column 2026-07-20 15:53:15 +08:00
sinohqb
d970a9c06a fix(deploy): init_db before alembic to create base tables 2026-07-20 15:50:29 +08:00
sinohqb
c6700e9c89 fix(deploy): remove COPY data/scenarios (gitignored), use mkdir instead 2026-07-20 15:37:41 +08:00
sinohqb
5b1c88065b feat(deploy): add volcengine-102 production deployment
Multi-stage Dockerfile (Node frontend build + Python runtime),
docker-compose with agenteval (port 8002) and openclaw-eval containers.
2026-07-20 15:33:44 +08:00
sinohqb
affbf60945 feat(models): add model capability metadata 2026-07-17 21:41:32 +08:00
sinohqb
b3c6c1fa7a docs: add repository agent guidelines 2026-07-17 21:18:09 +08:00
sinohqb
cc79d3a625 feat(models): support mainstream model protocols 2026-07-17 20:58:27 +08:00
sinohqb
457dfed252 fix(frontend): refresh scenario model references 2026-07-17 20:34:45 +08:00
sinohqb
470ff5875f feat(models): add centralized model configuration 2026-07-17 20:02:43 +08:00
sinohqb
9293f9e842 feat(files): improve category and location layout 2026-07-17 18:13:43 +08:00
sinohqb
d7514f4e65 refactor(files): harden storage and split frontend
Add transactional file storage workflows, typed API contracts, recursive category handling, frontend component separation, and Files API coverage.
2026-07-17 17:41:19 +08:00
sinohqb
867d4e3ff1 fix(engine): dynamic 生成失败原因持久化到 run.summary.case_errors
## 背景
用户反馈动态问诊评测「执行不下去」。诊断发现:dynamic 用例的 LLM 消息
生成 API 调用失败(0.2s 瞬间 failed,凭证/参数问题),引擎正确地标记
case 失败——但失败的具体原因(如 401 详情)只 emit 到 WebSocket,从不
写入 run.summary。导致 run 记录只有 total_rules:0 failed,DB/报告查不到
任何原因,用户和排查者都无从下手。

## 修复
- EvalEngine 新增 self._case_errors 收集致命的 case 级错误
- _generate_messages 的 8 个失败点统一走 _fail() helper:既 emit 到
  WebSocket,也记录到 _case_errors(含 case_id + stage + 具体 error)
- run() 汇总时把 _case_errors 写入 summary["case_errors"]
- 新增测试:dynamic 生成失败时 summary.case_errors 必须含原因(补上
  之前 KNOWN-2 记录的 _generate_messages 测试盲区)

## 注
这不是导致失败的 bug(失败源于外部 API 凭证/参数),而是让失败「可诊断」
的可用性修复。用户需自查 llm_config 的 api_key 是否有效/model 是否被
该端点接受。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 16:29:51 +08:00
sinohqb
c4962ddadf fix(llm_score): 修复多轮用例 question 提取错位导致普遍打 0 分
## 现象
多轮/动态用例的 llm_score 规则几乎全部返回 0.0/10 失败,即便被测对象
回复质量很高(实测 400+ 字的专业医疗回复也是 0 分)。

## 根因
evaluate() 里 question 提取逻辑错误:
    if len(dialog) >= 2:
        question_text = extract_reply_text(dialog[-2].reply)  # BUG
dialog[-2].reply 是「上一轮智能体的回复」,被误当成「用户问题」。于是评分
LLM 收到的问答对是:
  - "用户问题" = 上一轮 AI 回复
  - "智能体回复" = 当前轮 AI 回复
两段都是 AI 说的话、互不相关,评分 LLM 判定牛头不对马嘴 → 打 0 分。

单轮用例因 len(dialog)<2 走 sent_message 提取(正确),故不受影响;
问题只在多轮/dynamic 用例爆发。

## 修复
- question 始终取当前轮 last_turn.sent_message(用户实际发送的问题),
  移除错误的 dialog[-2].reply 分支
- reason 增加评分 LLM 自己的理由(parsed["reason"]),便于未来诊断
- 新增回归测试:多轮场景验证 question 来自 last sent_message 而非 prev reply

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 16:15:07 +08:00
sinohqb
f765bee7a1 fix(frontend): 修复 vendor-charts 循环 chunk 导致的运行时崩溃
## 问题
线上打开首页报错:
vendor-charts-Z9UiCjXy.js: Uncaught ReferenceError:
Cannot access 'd' before initialization

## 根因
T4 bundle 优化把 @ant-design/charts 单独拆为 vendor-charts chunk,但它的深层
@antv/* 依赖图与 vendor chunk 交叉引用,形成 Circular chunk(构建时已有警告
"vendor-charts -> vendor -> vendor-charts",当时被忽略)。循环 chunk 导致
ES module 求值顺序错乱 → TDZ 错误。

尝试把 @antv 也并入 vendor-charts 仍循环(charts 生态还依赖 lodash/d3 等
公共库,与 vendor 交叉)。

## 修复
移除 vendor-charts 单独拆分,让 @ant-design/charts + @antv 回到 vendor 主 chunk,
消除跨 chunk 循环。保留 vendor-monaco / vendor-antd(构建证明无循环)。
charts 在 Home 首页(默认路由)即需加载,单独拆分的懒加载收益本就微乎其微;
真正的懒加载收益来自 App.tsx 的页面级 React.lazy(保留)。

构建验证:无 Circular chunk 警告,无 vendor-charts chunk。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 16:04:09 +08:00
sinohqb
69100c3f40 fix(deploy): --skip-build 模式自动重启容器 + commit 校验降级
## 问题
v0.4 用 --skip-build 部署时踩到两个坑:
1. compose up -d 对无配置变更的容器是 no-op,不重启,导致 volume 挂载的
   backend 新代码不被 uvicorn 加载(这次靠手动 docker compose restart 才生效)
2. /api/health 的 commit 来自镜像 build-arg,--skip-build 不重建镜像 → commit
   校验必然失败触发 die,部署脚本非 0 退出

## 修复
- restart 阶段:SKIP_BUILD=1 时追加 docker compose restart agenteval,
  强制重载 volume 挂载的后端代码
- commit 校验:SKIP_BUILD=1 时降级为 warn(镜像未重建是预期的,代码已
  rsync+restart 生效),仅 full build 模式才 die

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 15:53:30 +08:00
sinohqb
12c1732617 v0.4-t3t4: OpenClaw 通道 + 前端 bundle 优化
## T3: OpenClaw 直连通道
- channels/openclaw.py: OpenClawChannel
  - send: POST /api/v1/chat/completions
  - poll_reply: GET /api/v1/chat/completions/{msg_id}
  - health_check: GET /api/health
  - 默认从 settings 读取 upstream/auth_token,channel_config 可覆盖
- channels/factory.py: 注册 ChannelType.OPENCLAW → OpenClawChannel
- Targets.tsx: 通道类型下拉新增「HTTP 通用」和「OpenClaw」选项
- 8 个 OpenClawChannel 单元测试(发送/轮询/超时/健康检查/默认配置)

## T4: 前端 Bundle 优化
- App.tsx: 7 个页面改为 React.lazy 懒加载 + Suspense fallback(Spin)
- vite.config.ts: 精细化 manualChunks
  - vendor-antd / vendor-monaco / vendor-charts 独立拆分
  - 主 index 68KB → 7KB,页面按需加载
  - 无循环依赖警告

## 测试
- 178/178 全绿,覆盖率维持 77%

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 15:37:14 +08:00
sinohqb
e0b69fa2b9 v0.4-t1t2: 测试覆盖率 62%→77% + UTC 时区根本修复
## T1: P0 测试补全(+67 个测试)
- test_utils_llm.py: extract_reply_text / extract_content_from_llm_response / parse_json_from_llm_text 各边界
- test_file_repository.py: 分类 CRUD / 树形结构 / 级联删除 / 文件创建/查询/删除/物理文件清理
- test_report.py: generate_report / generate_compare_report / render_markdown / render_json
- test_llm_score.py: OpenAI 格式 / Anthropic content-block 格式 / JSON 回退解析 / 异常降级

## T2: P1 测试补全(+28 个测试)
- test_scenarios.py: 模板列表/字段完整性/规则类型有效性 + YAML/JSON 加载/校验
- test_webhook.py: 未配置不发送 / 正确 payload / secret header / 异常静默忽略
- test_reports_api.py: GET /reports/{id} / /html / /json / /markdown / /compare 集成测试

## UTC 时区根本修复
- storage/db.py: 新增 iso_utc() 函数,确保所有 datetime 序列化输出带 Z 后缀
- runs.py / files.py / report.py: 6 处 .isoformat() → iso_utc()
- 前端 toDate() 兜底仍保留(向下兼容),但后端不再输出无时区时间戳

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 14:19:16 +08:00
sinohqb
17aeba80dd v0.3-s4: 场景模板库 + WS 自动重连 + PageWrapper 复用
## 场景模板库(S4-1)
- scenarios/templates.py: 6 个内置模板
  - 单轮问答基础 / 多轮对话 / 动态 LLM 生成 / 安全合规检测 / JSON 接口校验 / 加权评分
  - 每个模板附带对应规则配置(含 v0.3 新规则)
- routers/scenarios.py: GET /api/scenarios/templates + GET /api/scenarios/templates/{id}
- api.ts: scenariosApi.listTemplates() / getTemplate()
- Scenarios.tsx: 「从模板新建」按钮 + 卡片式模板选择弹窗
  - 选择后预填名称/描述/标签/cases JSON/llm_config,直接进入编辑 Drawer

## WebSocket 自动重连(S4-2)
- useRunSession.ts: connectWs() 函数 + 指数退避重连
  - 异常断开(非 1000/clean)时自动重试,最多 5 次
  - 延迟:1s → 2s → 4s → 8s → 16s(上限 30s)
  - 超出重试次数后降级 REST 获取最终状态
  - reconnectTimerRef 在组件卸载时清理,无内存泄漏

## PageWrapper 复用(S4-3)
- PageWrapper.tsx: 升级 inline 模式匹配全高页面的 padding 页头样式
- Home / Targets / Scenarios: 用 PageWrapper inline+fullHeight 替换重复内联页头
- Home.tsx: 去掉 unused `colors` import

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 12:05:18 +08:00
sinohqb
349200e51f v0.3-s3: Webhook + OpenClaw HTTP Skill + Markdown/对比报告
## Webhook 通知(S3-1)
- settings.py: 增加 AGENTEVAL_WEBHOOK_URL / AGENTEVAL_WEBHOOK_SECRET
- utils/webhook.py: send_run_webhook(),非阻断,任何异常仅 warning log
- runs.py: run 完成后自动触发 webhook(payload 含 run_id/status/summary/report_url)
- .env.example: 新增 webhook 配置示例

## OpenClaw Skill HTTP 改造(S3-2)
- plugins/openclaw/agenteval_skill.py: 完全重写
  - 改用 HTTP API(POST /api/runs + GET /api/runs/{id} 轮询 + GET /api/reports/{id})
  - 移除 subprocess + CLI 依赖
  - 轮询等待至 completed/failed,支持配置 poll_interval / timeout
  - 返回结构化中文摘要(summary_text),直接可用于 OpenClaw 对话展示

## Markdown 报告导出(S3-3)
- report.py: render_markdown_report() — 完整的 Markdown 表格 + 对话展示
- save_report: 支持 fmt="markdown",输出 .md 文件
- reports.py: GET /api/reports/{run_id}/markdown,Content-Disposition 附件下载
- api.ts: reportsApi.markdownUrl()
- Reports.tsx: 「导出 MD」按钮

## 对比报告(S3-4)
- report.py: generate_compare_report(run_id_1, run_id_2)
  - run_a / run_b 汇总 + delta(pass_rate / passed_cases / passed_rules)
  - case-level diff,标记 changed 用例
- reports.py: GET /api/reports/compare?run1=&run2=
- api.ts: reportsApi.compare()
- Reports.tsx: 完整对比视图
  - Segmented 切换「单次报告」/「对比报告」
  - 双 Select(报告 A vs B)+ 对比按钮
  - 汇总 delta card(pass_rate 变化 + 变化用例数徽章)
  - 用例对比表(通过/失败/改善↑/退步↓)+ 展开规则明细

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 11:44:54 +08:00
sinohqb
c7f1dca49d v0.3-s2: 3 个新规则 + 组合逻辑 + 33 个测试
## 新规则(共 6 种,增加 3 种)

### semantic_similarity
- 调用 OpenAI 兼容 embedding API(asyncio.gather 并发两路请求)
- 余弦相似度与 reference 比对,min_score 可配置(默认 0.7)
- API 异常时明确返回失败原因,不隐藏错误

### json_schema
- 验证回复是否为合法 JSON(支持 markdown 代码块剥离)
- required_keys / forbidden_keys / key_types 三维校验
- dot-path 支持嵌套字段("data.id")
- strict_json=false 模式非阻断校验

### safety
- 双层检测:关键词黑名单(零延迟)+ 可选 moderation API
- API 不可用时自动降级黑名单,不中止评测
- 支持自定义 flagged_categories

## 规则组合逻辑(rule_logic + rule_pass_threshold)

- models.py: EvalRuleConfig 增加 weight 字段;Case 增加 rule_logic / rule_pass_threshold
- models.py: 新增 RuleLogic 枚举(all / any / weighted)
- engine._save_rule_results: 按 rule_logic 决定 case 通过/失败
  - ALL:全部通过才通过(原有行为,向下兼容)
  - ANY:至少一条通过即通过
  - WEIGHTED:加权平均分 >= rule_pass_threshold

## 测试(43 → 76,新增 33)
- test_s2_rules_and_logic.py:3 个新规则的 pass/fail/边界/API 降级 + 5 个组合逻辑集成测试

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-17 11:23:22 +08:00