feat: 重构问问微信并完善知识库增量检索

统一问问微信与 Agent Hub 的查询链路
完善查询覆盖度、新鲜度和部分结果表达,避免索引滞后产生错误结论
基于会话实现真正的增量追新与历史补齐
支持后台同步、取消恢复、重启续传以及同步期间继续查询
优化知识库跨会话检索、同步状态、进度展示和侧栏布局
This commit is contained in:
Wxw-Gu
2026-09-11 17:44:48 +08:00
parent 0c4932d740
commit ab3b3731b7
69 changed files with 8317 additions and 898 deletions
+117
View File
@@ -0,0 +1,117 @@
import { describe, expect, it } from 'vitest'
import {
matchGroupReportIntent,
queryAgentReplyText,
QUERY_AGENT_UNAVAILABLE_TEXT,
resolveInboundRoute
} from '../../src/main/services/agent-hub-routing'
import type { AskWechatQueryResult } from '../../src/shared/query-agent'
describe('Agent Hub 入站路由 — Query / Action 分流', () => {
it('A. 「TraceMemo 交流群最近聊了啥」→ Query Agent(不是 report)', () => {
expect(resolveInboundRoute('TraceMemo 交流群最近聊了啥')).toEqual({ kind: 'knowledge_query' })
})
it('B. 「总结一下 TraceMemo 交流群最近聊了什么」→ Query Agent("总结"不等于 report)', () => {
expect(resolveInboundRoute('总结一下 TraceMemo 交流群最近聊了什么')).toEqual({
kind: 'knowledge_query'
})
})
it('B2. 「总结」缺少产物词时,report 快捷匹配不成立', () => {
expect(matchGroupReportIntent('总结一下这个群最近聊了什么')).toBeNull()
expect(matchGroupReportIntent('帮我总结一下 TraceMemo 交流群的近期内容')).toBeNull()
})
it('C. 「生成 TraceMemo 交流群今天的群聊总结图片」→ Report Action(图片)', () => {
const route = resolveInboundRoute('生成 TraceMemo 交流群今天的群聊总结图片')
expect(route.kind).toBe('report_action')
if (route.kind !== 'report_action') throw new Error('unreachable')
expect(route.intent.group).toContain('TraceMemo')
expect(route.intent.range).toBe('today')
})
it('D. 「帮我做一份 TraceMemo 交流群今日日报」→ Report Action(日报)', () => {
const route = resolveInboundRoute('帮我做一份 TraceMemo 交流群今日日报')
expect(route.kind).toBe('report_action')
if (route.kind !== 'report_action') throw new Error('unreachable')
expect(route.intent.group).toContain('TraceMemo')
})
it('D2. 群 + 时间但不要产物 → Query Agent', () => {
expect(resolveInboundRoute('TraceMemo 交流群昨天聊了啥')).toEqual({ kind: 'knowledge_query' })
})
it('E. 「BOBO 最近说过什么」→ Query Agent', () => {
expect(resolveInboundRoute('BOBO 最近说过什么')).toEqual({ kind: 'knowledge_query' })
})
it('F. 「我和 BOBO 第一次聊了什么」→ Query Agent', () => {
expect(resolveInboundRoute('我和 BOBO 第一次聊了什么')).toEqual({ kind: 'knowledge_query' })
})
it('G. 群成员分析仍是专用 Action', () => {
const route = resolveInboundRoute('看看 TraceMemo交流群里 BOBO 最近说了什么')
expect(route.kind).toBe('group_member_action')
if (route.kind !== 'group_member_action') throw new Error('unreachable')
expect(route.intent.member).toBe('BOBO')
expect(route.intent.group).toContain('TraceMemo')
})
it('H. 会话列表是确定性快捷路径(不经过模型)', () => {
expect(resolveInboundRoute('最近有哪些会话')).toEqual({ kind: 'recent_list', limit: 5 })
expect(resolveInboundRoute('最近3条消息')).toEqual({ kind: 'recent_list', limit: 3 })
})
})
describe('Agent Hub 回复文案映射', () => {
const diagnostics = {
entry: 'agent-hub' as const,
provider: 'P',
model: 'm',
modelCallCount: 2,
toolCallCount: 1,
tools: ['query_messages'],
totalMs: 10,
outcome: 'answered' as const
}
it('answered → 直接用 Query Agent 的文本回答', () => {
expect(
queryAgentReplyText({
engine: 'query-agent',
status: 'answered',
answer: '最近聊了两件事。',
diagnostics
})
).toBe('最近聊了两件事。')
})
it('provider_unavailable / error → 使用安全文案', () => {
const unavailable: AskWechatQueryResult = {
engine: 'query-agent',
status: 'provider_unavailable',
message: '当前 AI 查询服务暂时不可用,请稍后再试。',
diagnostics: { ...diagnostics, outcome: 'provider_failure' }
}
expect(queryAgentReplyText(unavailable)).toBe('当前 AI 查询服务暂时不可用,请稍后再试。')
const error: AskWechatQueryResult = {
engine: 'query-agent',
status: 'error',
message: '本次查询没有完成,请稍后再试或换一种问法。',
diagnostics: { ...diagnostics, outcome: 'runtime_error' }
}
expect(queryAgentReplyText(error)).toBe('本次查询没有完成,请稍后再试或换一种问法。')
})
it('legacy 结果不会出现在 Agent Hub 路径上,兜底为服务不可用文案', () => {
const legacy: AskWechatQueryResult = {
engine: 'legacy',
status: 'legacy',
reason: 'runtime_error',
result: {} as never
}
expect(queryAgentReplyText(legacy)).toBe(QUERY_AGENT_UNAVAILABLE_TEXT)
})
})