feat(sight): add conversation grader#1349
Conversation
Add a rule-based conversation evaluation pipeline with stable input hashing, SQLite persistence, and manual API endpoints. This keeps the MVP deterministic over captured GenAI and interruption evidence so repeated evaluations can reuse completed runs. LLM and agent graders remain reserved extension points. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
Add dashboard controls for fetching, running, and displaying persisted conversation evaluations with evidence deeplinks into ATIF. The UI keeps evaluation manual so users decide when to grade a snapshot, while still surfacing saved verdicts in conversation rows. Pending snapshots require explicit force evaluation from the panel. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
Drain idle in-flight HTTP states and persist them as pending GenAI calls when a stream is abandoned while the agent process stays alive. Manual output interruption does not necessarily kill the process, so dead-PID draining cannot recover these sessions. This preserves the captured request as pending evidence; unsupported states are skipped. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
Classify timeout keywords only from structured call errors and inspect response bodies for provider errors only on non-success status codes. Successful assistant text can legitimately mention timeout, auth, rate limits, or context limits as troubleshooting content. This keeps interruption detection focused on runtime failures; provider-specific wording still depends on captured error fields. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
Convert Anthropic request content blocks into unified message parts, including tool_use, tool_result, and thinking blocks. The grader relies on structured input evidence instead of raw event JSON to avoid prompt-context false positives. Historical rows are unchanged; new captures preserve tool failures for deterministic scoring. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
Document the manual conversation grader APIs, persistence model, current rule version, and dashboard-facing changelog entries. Keeping the operational guide and semantic design note together makes the MVP discoverable without changing runtime behavior. The repository documentation-standard file was not present in this worktree, so this keeps the doc change narrowly scoped. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
33a7efe to
ba8c19f
Compare
Apply current Clippy mechanical suggestions in AgentSight code touched by the PR and adjacent existing paths. This keeps the community preflight check `cargo clippy -- -D warnings` passing on the Linux test host without changing runtime behavior. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
chengshuyi
left a comment
There was a problem hiding this comment.
Review 意见
总体评价
功能完整且设计合理的 MVP 对话评估模块。核心架构清晰:rule-based grader 五维评分、SQLite 幂等持久化、手动触发模式。同时修复了中断检测误报、Anthropic tool result 丢失和空闲流丢弃等问题。代码质量整体较高,无 unwrap/expect/dbg 违规,SQL 使用参数化查询,错误处理链路完整。
主要建议:拆分为多个 PR
当前 PR 共 3244 行 / 31 文件,远超 AGENTS.md 中 800 行的硬性限制。建议按职责拆分为 3-4 个独立 PR,便于 review 和回溯:
-
fix(sight): avoid false interruption signals— 中断检测误报修复(~85 行)。这个改动独立且逻辑严谨,区分了structured_error(仅 error 字段)和response_error_body(status >= 400),附带 5 个精确的回归测试,建议单独合入。 -
fix(sight): persist idle streamed calls + preserve Anthropic tool results— 聚合器 idle 流排空 + Anthropic tool_result 保留修复(~250 行)。两者都是数据采集层面的 bug fix,关联性强。 -
feat(sight): add conversation grader API— grader 后端模块(~1800 行)。作为 Level 3 新功能可接受,但仍偏大,可考虑将 rule.rs 的测试拆到独立文件。 -
feat(sight): add grader dashboard controls— 前端 UI(~700 行)。与后端解耦,可独立 review。
其他需要关注的 finding
Major:
-
evict_idle_and_oversized不再驱逐 oversized 非 Idle 连接 — 当连接 body 超过max_body_bytes但状态不是Idle时,被加入to_evict列表但在内部if matches!(..., ConnectionState::Idle)检查时被跳过,导致不被移除。下次调用仍会重复此过程,连接永远留在内存中直到状态转为 Idle。建议 oversized 的非 Idle 连接至少有一个最终保护机制,防止异常大请求导致内存耗尽。 -
每个 grader API 请求都新建 SQLite 连接 —
evaluate_grader和latest_graderhandler 中每次都调用EvaluationStore::new_with_path(),执行CREATE TABLE IF NOT EXISTS+ schema 初始化。建议将EvaluationStore加入AppState作为Arc<EvaluationStore>,与InterruptionStore保持一致的使用模式。
Minor:
-
load_conversation_interruptions硬编码了 interruption DB 路径推导(假设与storage_path同目录),如果上游修改了命名或位置会静默返回空结果。建议从 config 或AppState中获取路径。 -
evaluate_graderhandler 在 SQLite 锁内执行 CPU 评估(load_conversation_input→RuleGrader::evaluate→store.insert_completed全程持有 Mutex),建议分离加载/评估/持久化步骤,仅在 SQL 操作时持有锁。
亮点
- 中断检测误报修复逻辑严谨,区分了哪些关键字应扫描 response body(如
context_length_exceeded),哪些只应匹配 error 字段(如timeout) - 幂等评估设计 —
(target_type, target_id, input_hash, grader_type, grader_version)唯一约束 +INSERT OR IGNORE+ 重试查找 - Anthropic tool result 保留完整覆盖了 Text/ToolUse/ToolResult/Thinking 四种 content block 类型
- 评估规则版本化 —
RULE_GRADER_VERSION参与幂等键和 input hash 计算,版本升级自动触发重新评估
Keep only SQLite reads and writes under the EvaluationStore mutex. JSON serialization and record conversion now run outside the lock, which addresses the review concern without changing the rule grader execution path. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
Reuse the grader evaluation store from server state instead of reopening SQLite on each API request. Load interruption evidence from the existing interruption store rather than deriving a sibling database path, and add regression coverage for oversized request-body eviction. Assisted-by: Codex Signed-off-by: wanghao <1562495626@qq.com>
|
已处理本轮 review 里可直接落地的 finding,并准备按职责拆分 PR。 当前大 PR head 已追加两类 review 修复:
已在 Linux AgentSight 测试机验证:
接下来按 review 建议拆成独立 PR,避免继续在这个大 PR 上叠加:
拆分完成后,这个大 PR 会被替换为上述 smaller PRs。 |
|
已按 review 建议拆分为 smaller PRs:
这个聚合 PR 不再继续 review,后续请看上述拆分 PR。 |
Description
Adds a manual AgentSight conversation grader MVP for persisted agent-quality evaluation. The change introduces a rule-based grader over GenAI and interruption evidence, SQLite-backed idempotent evaluation runs, dashboard controls for running and viewing evaluations, and ATIF deeplinks for evidence navigation.
It also fixes capture and scoring issues found while validating the grader flow: manually interrupted streamed calls are persisted as pending evidence, successful assistant text is no longer misclassified as runtime interruption text, and Anthropic request-side
tool_resultblocks are preserved as structured tool-call responses for deterministic tool-failure grading.Related Issue
Closes #1304
Type of Change
Scope
cosh(copilot-shell)cosh-ng(cosh-ng)sec-core(agent-sec-core)skill(os-skills)sight(agentsight)tokenless(tokenless)ckpt(ws-ckpt)memory(agent-memory)anolisa(anolisa-cli)skillfs(SkillFS)Checklist
cosh: Lint passes, type check passes, and tests passcosh-ng:cargo clippy --all-targets -- -D warningsandcargo fmt --checkpasssec-core(Rust):cargo clippy -- -D warningsandcargo fmt --checkpasssec-core(Python): Ruff format and pytest passskill: Skill directory structure is valid and shell scripts pass syntax checksight:cargo clippy -- -D warningsandcargo fmt --checkpasstokenless:cargo clippy -- -D warningsandcargo fmt --checkpassmemory(Linux only):cargo clippy --all-targets -- -D warnings,cargo fmt --check, andcargo testpassanolisa:cargo clippy --all-targets --locked -- -D warnings,cargo fmt --all --check, andcargo test --lockedpassskillfs:cargo fmt --all --check,cargo clippy --workspace --all-targets -- -D warnings, andcargo test --workspacepasspackage-lock.json/Cargo.lock)Testing
Ran on the Linux AgentSight test host:
cargo fmt --all -- --checkcargo clippy -- -D warningscargo testcargo test -p agentsight grader --lockedcargo test -p agentsight genai::call_builder --lockedcargo test -p agentsight aggregator::http::aggregator --lockedcargo test -p agentsight interruption::detector --lockedcd dashboard && npm run typecheckcd dashboard && npm test -- src/test/apiClient.test.ts src/test/EvaluationBadge.test.tsx src/test/EvaluationPanel.test.tsx src/test/ConversationList.test.tsx src/test/AtifViewerPage.test.tsxmake install INSTALL_PROFILE=system SETCAP=1systemctl restart agentsightcurl -sS -m 5 http://127.0.0.1:7396/healthDeployment smoke result:
active{"status":"ok","version":"0.7.0"}Additional Notes
The grader is intentionally manual for the MVP. It reuses completed runs for the same target, input hash, grader type, and grader version, while producing a new run when the captured input or grader version changes.
Historical rows whose normalized
input_messagesalready dropped Anthropictool_resultblocks are not backfilled by this PR. New captures preserve those blocks as structured evidence so the grader can score tool failures without scanning raw event JSON and reintroducing prompt-context false positives.