会话检索
一句话版:
ctx.sessionQuery是会话检索能力缝:在 live 与 durable 会话日志上做授权读取、关系轨迹和搜索,独立于 compaction。session-query是服务定义,session-query-sqlite用 SQLite FTS5 实现,tool-session-query把工作区授权的检索暴露给模型。
一、是什么
会话检索让 DSH 能在不依赖压缩的前提下,检索自己的历史会话——精确读历史、追关系、全文搜。抽象服务组合了精确会话历史检索、关系追踪、以及与 provider 无关的过滤,作用于 live ctx.sessions 加上可选的动态挂载 ctx.sessionPersistence。
| 包 | ctx key | 角色 |
|---|---|---|
session-query | ctx.sessionQuery | 定义可信读取、关系查询与搜索操作 |
session-query-sqlite | ctx.sessionQuery | 用 SQLite 全文检索实现会话查询 |
tool-session-query | (注册在 ctx.tools 上) | 把工作区授权的会话查询暴露给模型 |
匹配到同一 id 只产生一条记录:live 事件优先,live/persisted 报告双方的源可用性;冲突的不可变头失败于 SESSION_QUERY_SOURCE_CONFLICT。
二、读取 API(session-query)
SessionQueryEngine 是组合的抽象 ctx.sessionQuery 契约:
| Member | 语义 |
|---|---|
listSessions(signal?) | 读当前持久化元数据,live 优先合并,返回确定性 newest-first 排序的克隆记录 |
readSession(sessionId) | 返回一份完整分离的原始日志(经与 resume 相同的核心回放校验),不把会话放进 live store |
filterSessions(filters, signal?) | 对同一克隆逻辑语料应用 provider 无关的会话元数据与可用性谓词 |
filterEvents(sessionId, filters) | 抽取一方案语义文档,按升序 seq 应用元数据与字面文本谓词 |
listEvents(sessionId) | 把每个事件分类为 current / shadowed / log-only |
readSurface(sessionId) | 返回克隆头、原始日志捕获边界、完整折叠的当前 surface(模型历史序) |
readEvent(request, signal?) | 返回克隆头、完整目标事件、有界原始 seq 窗口(before/after 缺省 0,不超 readWindowMax) |
traceSession(sessionId, signal?) | 读一次语料,返回向外祖先 + 确定性递归后代树;complete: false 标识首个缺失父节点 |
traceEvent(request, signal?) | 返回克隆源头、直接位置替换、直接引用源事件链(replacementChain 跟随位置替换到最终替换) |
持久化可选、可动态挂载/卸载。挂载的持久化不可读时,跨语料列表与关系追踪失败于 SESSION_QUERY_PERSISTENCE_FAILED;成功读出但未过 Session 校验的 durable 记录报 SESSION_QUERY_CORRUPT_SESSION。针对已知 live 会话的标题读、事件轨迹、事件读不查持久化,所以 durable 后端健康不影响当前内存状态。
三、过滤与文本提取
SessionResultFilter:id、可空 cwd、created-at 范围、可空 parent、源可用性SessionEventResultFilter:seq/time 范围、事件类型、surface、语义文本
过滤数组 AND,单个列表子句内的值 OR;空列表值不匹配任何东西,范围含端点。文本子句独立于 FTS provider:调用方文本转义成 Unicode、大小写不敏感正则,每个空白串匹配一个或多个空白字符——这是字面语义文本扫描,不是全文查询。
extractSessionEventText() / buildSessionEventSearchDocuments() 定义共享的一方案文档投影;reasoning 块、结构边界、stream chunk、请求头、未知 declaration-merged 变体不产生文档。
四、全文检索(session-query-sqlite)
SqliteSessionQueryEngine 继承精确读/轨迹/provider 无关过滤,用 SQLite FTS5 实现两个全文方法。
searchSessions(request, exec?)跨语料按最强匹配事件分组返回SessionSearchHit页;searchEvents(request, exec?)搜单个逻辑会话- 查询必填,是 trim 后空白归一化的字面短语;FTS5 语法(引号、
OR、NEAR、*)按数据对待,不按可执行 MATCH 语法 - 相关性跨持久表与 TEMP 表可比:FTS5 高亮匹配 span 数降序,再存文档码点长度升序;事件时间 / 会话 id / seq 打破平局
- 游标是不透明品牌值,绑定归一化请求与服务实例,相关代变化时失败;会话内游标不因无关会话变化而失效
- 索引用 FTS5
unicode61:是 token/phrase 召回,不是任意子串召回(AI匹配不到 tokenBRAID);要字面子串用filterEvents()的text子句 - 三个 surface(
current/shadowed/log-only)默认都可搜,传 surface 过滤收窄
五、模型工具(tool-session-query)
tool-session-query 注册 session_search、session_event_search、session_trace、session_event_trace、session_event_read,opt-in(出厂组合默认不挂载)。
- 调用方只来自
ToolExecution.exec.agent;跨会话访问要求目标与调用方会话cwd精确相等,无cwd的调用方只能检视自己 - 搜索从不暴露 provider 游标、offset、页大小或模型可控的 limit;两个搜索工具与其他工具调用互斥执行,三个精确轨迹/读工具可并行
session_search始终省略调用方自身会话;请求的 parent id 先去重并按工作区授权检查再进 FTS- 系统提示注入一段固定的 prior-history guidance,指引模型"用
session_search找历史、用session_event_search搜单会话、命中后用session_trace/session_event_trace/session_event_read取关系或精确数据" - 每个
ctx.sessionQuery调用都过一道模型边界 sanitizer,取消原因精确保留
六、配置
session-query 服务定义:
| Key | 默认 | 契约 |
|---|---|---|
readWindowMax | 50 | before/after 原始事件计数上限 |
persistedInspectConcurrency | 4 | 单批读并发检查持久化日志数上限(正整数) |
session-query-sqlite:
| Key | 默认 | 契约 |
|---|---|---|
path | 必填 | 专用派生索引 SQLite 路径;:memory: 可用 |
openAt | startup | startup 激活前打开;first-search 推迟到首次搜索;never 关闭全文检索但保留精确读取/过滤/trace |
journalMode | wal | wal / delete / truncate / persist |
defaultLimit | 20 | 请求省略 limit 时的页大小 |
maxLimit | 100 | 接受的最大请求页大小 |
snippetChars | 240 | snippet 最大长度(Unicode 码点) |
tool-session-query:
| Key | 默认 | 含义 |
|---|---|---|
maxSearchResults | 100 | 跨 provider 页收集的最大授权非自身命中数 |
searchTimeoutMs | 30000 | 附加到两个全文搜索工具的合作截止时间 |
七、挂载状态
session-query-sqlite默认挂载(base 组合),中性默认path: ':memory:'、openAt: first-search——进程本地、只在用到时打开tool-session-queryopt-in,出厂组合不默认挂载session-query是抽象服务定义,无独立具体插件
八、已知限制
- 无调用方授权:
session-query/session-query-sqlite是可信的全上下文基础设施;模型工具或 UI 必须自行约束可检视的会话 - 同步查询执行:
DatabaseSync在 MATCH 执行时阻塞 JS 线程,无法打断已运行的语句 openAt: never是部署级关闭开关:两个全文搜索入口在参数规范化前返回SESSION_QUERY_SEARCH_DISABLED,node:sqlite、source observation 与 reconciliation 均不启动;继承的精确读取、过滤和 trace 仍可用- token 召回而非任意子串:
unicode61不匹配更大 token 内的子串 - 单所有者派生索引:一个索引路径只归一个进程里的一个服务;外部写入与多进程共享不支持
九、验证
# 看 session-query-sqlite 是否装载(默认挂载)
dsh web --dump-config | grep -iE "session-query"
# tool-session-query opt-in,默认不挂,应看不到
dsh web --dump-config | grep -iE "tool-session-query"