@qlzt/dsh-session-query-sqlite 0.0.0-stage → 0.2.1-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +67 -0
- package/README.md +159 -2
- package/README.zh.md +160 -0
- package/lib/index.js +1155 -0
- package/lib/types/index.d.ts +118 -0
- package/lib/types/query.d.ts +106 -0
- package/lib/types/schema.d.ts +16 -0
- package/package.json +51 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/session-query/session-query-sqlite/README.md
|
|
5
|
+
/:
|
|
6
|
+
en: c47de69fc9906da1
|
|
7
|
+
zh: 6b89540bb5977d34
|
|
8
|
+
/deepseek-ai-dsh-session-query-sqlite:
|
|
9
|
+
en: 1ea8c855c9e399bc
|
|
10
|
+
zh: 6c04c65b56aebf8b
|
|
11
|
+
/deepseek-ai-dsh-session-query-sqlite/summary:
|
|
12
|
+
en: e8970d4d9500f484
|
|
13
|
+
zh: d96abbbe143b3ca9
|
|
14
|
+
/deepseek-ai-dsh-session-query-sqlite/table-of-contents:
|
|
15
|
+
en: d152484eb41ac6b4
|
|
16
|
+
zh: 09388d293f9be9cb
|
|
17
|
+
/deepseek-ai-dsh-session-query-sqlite/use-this-package:
|
|
18
|
+
en: d3bed0996d9ba473
|
|
19
|
+
zh: 2bbcbc19264c9e60
|
|
20
|
+
/deepseek-ai-dsh-session-query-sqlite/use-this-package/when-to-choose-it:
|
|
21
|
+
en: d77054a6e8023089
|
|
22
|
+
zh: d44f9a5cd54dd43a
|
|
23
|
+
/deepseek-ai-dsh-session-query-sqlite/use-this-package/minimal-configuration:
|
|
24
|
+
en: 1c9d4d7e60b93c65
|
|
25
|
+
zh: b55bc598768398d3
|
|
26
|
+
/deepseek-ai-dsh-session-query-sqlite/use-this-package/search-behavior:
|
|
27
|
+
en: 746bd842a7b9c157
|
|
28
|
+
zh: 2515443f5d3f6656
|
|
29
|
+
/deepseek-ai-dsh-session-query-sqlite/use-this-package/when-to-defer-or-disable-search:
|
|
30
|
+
en: 8df2c14374a1f3a6
|
|
31
|
+
zh: e1dd3ff73de187c4
|
|
32
|
+
/deepseek-ai-dsh-session-query-sqlite/use-this-package/failures-and-recovery:
|
|
33
|
+
en: 2baafe3969855b2a
|
|
34
|
+
zh: 2781c97457191214
|
|
35
|
+
/deepseek-ai-dsh-session-query-sqlite/understand-the-implementation:
|
|
36
|
+
en: 1b4ba96f994a361d
|
|
37
|
+
zh: 50148b7af190aa0c
|
|
38
|
+
/deepseek-ai-dsh-session-query-sqlite/understand-the-implementation/design-philosophy:
|
|
39
|
+
en: 97d8f71fda5ed9b6
|
|
40
|
+
zh: fe1d0bd886dc2437
|
|
41
|
+
/deepseek-ai-dsh-session-query-sqlite/understand-the-implementation/source-map:
|
|
42
|
+
en: b3815ff8f97ba2c2
|
|
43
|
+
zh: 2955152a8f33b40a
|
|
44
|
+
/deepseek-ai-dsh-session-query-sqlite/understand-the-implementation/index-lifecycle:
|
|
45
|
+
en: 3a99cf9f8f64ec0e
|
|
46
|
+
zh: 40585b4764282881
|
|
47
|
+
/deepseek-ai-dsh-session-query-sqlite/understand-the-implementation/schema-ownership:
|
|
48
|
+
en: cb1e6861a47a618c
|
|
49
|
+
zh: 18863cdd4986f4b7
|
|
50
|
+
/deepseek-ai-dsh-session-query-sqlite/further-exploration:
|
|
51
|
+
en: b563921a29050088
|
|
52
|
+
zh: 9a0b3d365b38bbb8
|
|
53
|
+
/deepseek-ai-dsh-session-query-sqlite/model-experience:
|
|
54
|
+
en: ff9dc9f0f67efd4d
|
|
55
|
+
zh: ad284a65c2091e0f
|
|
56
|
+
/deepseek-ai-dsh-session-query-sqlite/model-experience/kv-cache-effect:
|
|
57
|
+
en: ca75c51c89c2c9b0
|
|
58
|
+
zh: f57cc48a1b5cbfa9
|
|
59
|
+
/deepseek-ai-dsh-session-query-sqlite/known-limitations-and-deferred-work:
|
|
60
|
+
en: 9be1b4a66f06c413
|
|
61
|
+
zh: 39b29034f3cc08b1
|
|
62
|
+
/deepseek-ai-dsh-session-query-sqlite/known-limitations-and-deferred-work/dev-note:
|
|
63
|
+
en: d2f0d68fe29fb750
|
|
64
|
+
zh: 323d21ee73a9e3f6
|
|
65
|
+
/deepseek-ai-dsh-session-query-sqlite/known-limitations-and-deferred-work/dev-note/future-alternate-tokenizers-and-search-providers:
|
|
66
|
+
en: 66b67df07594267a
|
|
67
|
+
zh: 73b6e1fd6362f168
|
package/README.md
CHANGED
|
@@ -1,3 +1,160 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: "The SQLite FTS5 full-text search backend for session history, for deployments and maintainers choosing, configuring, or debugging full-text search over the query service."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
# @deepseek-ai/dsh-session-query-sqlite
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
Use this package to add ranked SQLite FTS5 search across session history, either across sessions or within one session, with cursor pagination. It indexes live and persisted history in a separate derived database, so searches reflect current state without modifying the session-persistence store. Exact reads, filters, and traces remain available through the same query API. Search is opt-in in shipped compositions; configure `openAt` to open the index at startup, on first search, or never. Results match tokens and phrases rather than arbitrary substrings, and each index path has a single process owner.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Mount this package when a composition needs ranked full-text search over session history — for example the Web content search or `/resume` prior-work retrieval. The common path is explicit: mount the plugin, give it a dedicated database path, and call `ctx.sessionQuery.searchSessions` or `searchEvents` from code.
|
|
29
|
+
|
|
30
|
+
### When to choose it
|
|
31
|
+
|
|
32
|
+
Choose it when you want full-text recall over prior sessions with ranking and paging. Choose it together with `dsh-session-query` and the session service; a persistence backend is optional but recommended so persisted history is searchable after restarts. Avoid pointing `path` at the session-persistence database — this package owns a separate derived index.
|
|
33
|
+
|
|
34
|
+
### Minimal configuration
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
- name: '@deepseek-ai/dsh-session'
|
|
38
|
+
- name: '@deepseek-ai/dsh-session-query-sqlite'
|
|
39
|
+
config:
|
|
40
|
+
path: /absolute/path/to/session-search.db
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Field | Default | Meaning |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `path` | required | Dedicated derived-index SQLite path, or `:memory:`; missing paths are created owner-only on POSIX |
|
|
46
|
+
| `openAt` | `startup` | `startup` opens at activation; `first-search` defers the SQLite module until the first search; `never` disables full-text search while inherited reads stay available |
|
|
47
|
+
| `journalMode` | `wal` | `wal`, `delete`, `truncate`, or `persist` |
|
|
48
|
+
| `defaultLimit` | `20` | Page size when a request omits `limit` |
|
|
49
|
+
| `maxLimit` | `100` | Largest accepted request page size |
|
|
50
|
+
| `snippetChars` | `240` | Maximum snippet length in Unicode code points |
|
|
51
|
+
| `readWindowMax` | `50` | Maximum `before`/`after` raw events for the inherited `readEvent()` |
|
|
52
|
+
| `persistedReadConcurrency` | `4` | Concurrent persisted-log reads for inherited batch reads |
|
|
53
|
+
| `preparedSessionCacheSize` | `5` | Cold prepared-Session observations the inherited `observeSession` reader retains for reuse |
|
|
54
|
+
|
|
55
|
+
The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-session-query-sqlite) is the exhaustive source for every accepted field and its JSDoc.
|
|
56
|
+
|
|
57
|
+
### Search behavior
|
|
58
|
+
|
|
59
|
+
`searchSessions` searches the whole corpus and groups results by each session's strongest matching event; `searchEvents` searches one logical session. Queries are literal phrases: they are trimmed and whitespace-normalized, and FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data, never as executable query syntax. Metadata filters (session id, cwd, created-at, parent, availability, event seq/time/type/surface) narrow results before ranking. All `current`, `shadowed`, and `log-only` events are searchable by default; pass a surface filter to narrow.
|
|
60
|
+
|
|
61
|
+
Ranking is deterministic: more actual FTS5 highlighted-match spans first, then shorter documents, with event time, session id, and seq breaking ties. Results carry plain-text snippets bounded by `snippetChars` Unicode code points, with no provider-specific numeric score. Pages continue through an opaque `SessionSearchCursor` bound to the exact normalized request; a cursor becomes stale when its relevant corpus changes (`SESSION_QUERY_STALE_CURSOR`), and a within-session cursor survives changes to unrelated sessions while a cross-session cursor does not.
|
|
62
|
+
|
|
63
|
+
The `unicode61` tokenizer matches tokens and phrases, not arbitrary substrings: `AI` does not match the token `BRAID`. Use `ctx.sessionQuery.filterEvents()` with a `text` clause when a literal whitespace-flexible substring scan is required.
|
|
64
|
+
|
|
65
|
+
### When to defer or disable search
|
|
66
|
+
|
|
67
|
+
With `openAt: first-search`, the service activates without importing `node:sqlite` or opening the index, deferring SQLite's experimental warning until the first actual search; an invalid database fails that first search instead of service activation. With `openAt: never`, full-text search is off for the deployment: `searchSessions` and `searchEvents` fail with `SESSION_QUERY_SEARCH_DISABLED` before any request normalization, while every inherited exact read, filter, and trace keeps working. Requests that exceed the compiled-predicate budget (14 combined predicates across sessions, 13 within a session) or SQLite's portable 32,766-binding limit fail with `SESSION_QUERY_INVALID_FILTER` before statement preparation.
|
|
68
|
+
|
|
69
|
+
### Failures and recovery
|
|
70
|
+
|
|
71
|
+
Typed `SessionQueryError` failures carry stable codes: `SESSION_QUERY_SEARCH_DISABLED` when search is configured off; `SESSION_QUERY_INDEX_FAILED` when the index cannot open or reconcile; `SESSION_QUERY_SESSION_NOT_FOUND` when a search target is absent; `SESSION_QUERY_STALE_CURSOR` when the corpus changed between pages — retry the complete search call; and `SESSION_QUERY_INVALID_CURSOR` for a cursor that does not belong to this request. Cancellation is honored between synchronous SQLite calls; a statement already executing on the JavaScript thread cannot be interrupted.
|
|
72
|
+
|
|
73
|
+
-----
|
|
74
|
+
|
|
75
|
+
<a id="understand-the-implementation"></a>
|
|
76
|
+
## Understand the implementation
|
|
77
|
+
|
|
78
|
+
<details>
|
|
79
|
+
<summary>Implementation internals — click to expand</summary>
|
|
80
|
+
|
|
81
|
+
This section explains the design decisions behind the backend and points at the code that realizes them; the observable behavior is fully covered in [Use this package](#use-this-package).
|
|
82
|
+
|
|
83
|
+
### Design philosophy
|
|
84
|
+
|
|
85
|
+
The backend is built on one separation and three commitments:
|
|
86
|
+
|
|
87
|
+
- **Derived index, never the source store.** The FTS rows live in a dedicated disposable database; the session-persistence database is never opened here.
|
|
88
|
+
- **Live-preferred observation.** One serialized state machine compares persistence snapshot revisions, reads only new or changed logs through short-lived read handles, and reconciles in one transaction, so a search reflects the newest stable state.
|
|
89
|
+
- **Generation-bound cursors.** Every corpus change bumps a generation; cursors carry the generation they were created under and fail stale rather than returning a shifted page.
|
|
90
|
+
- **Literal phrases as data.** Caller query text is quoted into one FTS5 phrase so query syntax stays inert, and reserved highlight markers are stripped from documents before indexing.
|
|
91
|
+
|
|
92
|
+
The design history lives in the [SQLite FTS5 session search note](../../../.agents/notes/archived/feature/2026-07-10-sqlite-session-query-provider.md) and the [unified service decision](../../../.agents/notes/archived/architecture/2026-07-23-unified-session-query-service.md).
|
|
93
|
+
|
|
94
|
+
### Source map
|
|
95
|
+
|
|
96
|
+
| File | Role |
|
|
97
|
+
|---|---|
|
|
98
|
+
| [`src/index.ts`](src/index.ts) | Service: config, openAt lifecycle, serialized reconciliation, query execution, cursors |
|
|
99
|
+
| [`src/query.ts`](src/query.ts) | Request normalization, parameterized predicates, snippets, predicate and binding budgets |
|
|
100
|
+
| [`src/schema.ts`](src/schema.ts) | Database schema, application-id ownership, in-place reset, owner-only file creation |
|
|
101
|
+
|
|
102
|
+
### Index lifecycle
|
|
103
|
+
|
|
104
|
+
Persisted FTS rows live in a dedicated derived database and survive restarts; live sessions use connection-local TEMP tables that shadow the durable base for the same session and reveal it again when the live owner detaches. Both tables retain the exact inherited cut in numeric `seed_length`; reconstructed headers expose only `isSeeded`, while the cut participates in live fingerprints and persisted source revisions. Each search runs one serialized observation: list persistence snapshots, compare per-session revisions with the indexed rows, read only new or changed logs through a read handle (balancing an interrupted final turn in memory, never writing back), extract semantic documents, and commit the reconciliation in one transaction before running the query. Repeated queries and unchanged reopens read nothing; switching stores or observing new, changed, deleted, or externally repaired sources reconciles on the next stable observation. Source or transaction failure commits nothing and the next search retries.
|
|
105
|
+
|
|
106
|
+
### Schema ownership
|
|
107
|
+
|
|
108
|
+
The database carries an application id and schema version 8. Opening refuses a file owned by another application or a canonical database, rejects unknown user tables, and only a recognized incompatible derived schema resets in place — so an unrelated or session-persistence database is never touched. On POSIX filesystems, missing directories and database files are created owner-only (`0700` and `0600` before the process umask). Exactly one service in one process owns a derived-index path; generations and TEMP shadow state are connection-owned.
|
|
109
|
+
|
|
110
|
+
</details>
|
|
111
|
+
|
|
112
|
+
-----
|
|
113
|
+
|
|
114
|
+
<a id="further-exploration"></a>
|
|
115
|
+
## Further Exploration
|
|
116
|
+
|
|
117
|
+
Read these pages when the package-level contract is not enough. They move from the shared query service to the type-level contract and the design evidence.
|
|
118
|
+
|
|
119
|
+
- [Session Query subsystem reference](../../../docs/subsystems/session-query.md) — the full type-level contract this backend implements.
|
|
120
|
+
- [dsh-session-query](../session-query/README.md) — the service definition: exact reads, filters, and traces this backend inherits.
|
|
121
|
+
- [dsh-tool-session-query](../../experimental/tool-session-query/README.md) — the model-facing consumer that calls these search methods.
|
|
122
|
+
- [SQLite FTS5 session search](../../../.agents/notes/archived/feature/2026-07-10-sqlite-session-query-provider.md) — search semantics, reconciliation, and the tokenizer decision.
|
|
123
|
+
- [JSONL session persistence](../../session/session-persistence-jsonl/README.md) — the authoritative Session store this disposable index observes; keep its root separate from this package's database path.
|
|
124
|
+
|
|
125
|
+
-----
|
|
126
|
+
|
|
127
|
+
<a id="model-experience"></a>
|
|
128
|
+
## Model Experience
|
|
129
|
+
|
|
130
|
+
None, as the search backend returns hits only to callers and registers nothing model-facing.
|
|
131
|
+
|
|
132
|
+
#### KV Cache effect
|
|
133
|
+
|
|
134
|
+
None; this package neither assembles nor sends a provider request.
|
|
135
|
+
|
|
136
|
+
## Known Limitations and Deferred Work
|
|
137
|
+
|
|
138
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
These limits define when this package is a poor fit or needs special operational care. They are current package constraints, not a general SQLite comparison or a task backlog.
|
|
142
|
+
|
|
143
|
+
- **No caller authorization** — this is a trusted context-wide service; a model tool or UI must enforce its own access policy.
|
|
144
|
+
- **Synchronous query execution** — `DatabaseSync` blocks the JavaScript thread during MATCH execution and cannot interrupt a statement already running.
|
|
145
|
+
- **Token recall, not arbitrary substrings** — the `unicode61` tokenizer does not match substrings inside a larger token; use `filterEvents()` for literal scans.
|
|
146
|
+
- **Single-owner derived index** — one service in one process must own each index path; external writers and multi-process sharing are unsupported.
|
|
147
|
+
|
|
148
|
+
<a id="dev-note"></a>
|
|
149
|
+
### Dev Note
|
|
150
|
+
|
|
151
|
+
<details>
|
|
152
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
153
|
+
|
|
154
|
+
This Dev Note is working context for maintainers: open design questions and directions that are not decided. It is explicitly non-authoritative — shipped behavior, limits, and accepted rationale live in the sections above, the package code, and the linked Agent Notes.
|
|
155
|
+
|
|
156
|
+
#### Future: alternate tokenizers and search providers
|
|
157
|
+
|
|
158
|
+
The `unicode61` tokenizer choice trades substring recall for index size and two-character token support; the trigram alternative was measured and rejected. Switching tokenizers or adding another search backend would change indexed recall and require its own reconciliation and generation story.
|
|
159
|
+
|
|
160
|
+
</details>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "面向部署方与维护者的 SQLite FTS5 会话历史全文搜索后端,用于选择、配置或排查查询服务之上的全文搜索。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-session-query-sqlite
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
使用本包可为会话历史增加带排序的 SQLite FTS5 搜索,既能跨会话搜索,也能在单个会话内搜索,并支持游标分页。它把实时与持久化历史索引到独立的派生数据库,因此搜索反映当前状态,同时不会修改会话持久化存储。精确读取、过滤与追踪仍通过同一查询 API 提供。已发布组合中的搜索是可选能力;配置 `openAt` 可让索引在启动时、首次搜索时打开,或永不打开。结果匹配 token 与短语,而非任意子字符串;每个索引路径只能由一个进程持有。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
当组合需要对会话历史进行排序后的全文搜索时——例如 Web 内容搜索或 `/resume` 既往工作检索——挂载本包。常用路径是显式的:挂载插件、给它一个专用数据库路径,然后从代码调用 `ctx.sessionQuery.searchSessions` 或 `searchEvents`。
|
|
29
|
+
|
|
30
|
+
### 何时选择
|
|
31
|
+
|
|
32
|
+
当你想对既往会话进行带排序与分页的全文召回时选择它。它与 `dsh-session-query` 和会话服务一起使用;持久化后端可选但建议挂载,这样重启后持久化历史仍可搜索。不要把 `path` 指向 session-persistence 数据库——本包拥有独立的派生索引。
|
|
33
|
+
|
|
34
|
+
### 最小配置
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
- name: '@deepseek-ai/dsh-session'
|
|
38
|
+
- name: '@deepseek-ai/dsh-session-query-sqlite'
|
|
39
|
+
config:
|
|
40
|
+
path: /absolute/path/to/session-search.db
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| 字段 | 默认值 | 含义 |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `path` | 必填 | 专用派生索引 SQLite 路径,或 `:memory:`;POSIX 上缺失的路径会以仅所有者可访问的方式创建 |
|
|
46
|
+
| `openAt` | `startup` | `startup` 在激活时打开;`first-search` 把 SQLite 模块推迟到首次搜索;`never` 关闭全文搜索,继承的读取保持可用 |
|
|
47
|
+
| `journalMode` | `wal` | `wal`、`delete`、`truncate` 或 `persist` |
|
|
48
|
+
| `defaultLimit` | `20` | 请求省略 `limit` 时的分页大小 |
|
|
49
|
+
| `maxLimit` | `100` | 接受的最大请求分页大小 |
|
|
50
|
+
| `snippetChars` | `240` | 按 Unicode 码点计算的最大 snippet 长度 |
|
|
51
|
+
| `readWindowMax` | `50` | 继承的 `readEvent()` 的 `before`/`after` 原始事件数上限 |
|
|
52
|
+
| `persistedReadConcurrency` | `4` | 继承批量读取的并发持久化日志读取数 |
|
|
53
|
+
| `preparedSessionCacheSize` | `5` | 继承的 `observeSession` 读取器为复用保留的冷 prepared-Session 观察数 |
|
|
54
|
+
|
|
55
|
+
生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-session-query-sqlite)是每个受支持字段及其 JSDoc 的穷尽式真源。
|
|
56
|
+
|
|
57
|
+
### 搜索行为
|
|
58
|
+
|
|
59
|
+
`searchSessions` 搜索整个语料库,并按每个会话匹配最强的事件分组结果;`searchEvents` 搜索一个逻辑会话。查询是字面短语:首尾空白会被移除、内部空白会被规范化,引号、`OR`、`NEAR` 和 `*` 等 FTS5 语法被视为数据,绝不作为可执行查询语法。元数据过滤器(会话 id、cwd、创建时间、父级、可用性、事件 seq/时间/类型/表层)在排序前缩小结果。默认搜索全部 `current`、`shadowed` 与 `log-only` 事件;传入表层过滤器可缩小范围。
|
|
60
|
+
|
|
61
|
+
排序是确定性的:实际 FTS5 高亮匹配 span 更多的在前,然后文档更短的在前,事件时间、会话 id 与 seq 打破平局。结果携带按 `snippetChars` 个 Unicode 码点截断的纯文本摘录,没有提供方专用数值分数。分页通过不透明 `SessionSearchCursor` 延续,游标绑定到规范化后的确切请求;相关语料库变化时游标变为陈旧(`SESSION_QUERY_STALE_CURSOR`),会话内游标可在不相关会话变化后延续,跨会话游标则不能。
|
|
62
|
+
|
|
63
|
+
`unicode61` tokenizer 匹配 token 与短语,而非任意子字符串:`AI` 不匹配 token `BRAID`。需要执行字面、空白灵活的字符串子串扫描时,使用带 `text` 子句的 `ctx.sessionQuery.filterEvents()`。
|
|
64
|
+
|
|
65
|
+
### 何时推迟或关闭搜索
|
|
66
|
+
|
|
67
|
+
使用 `openAt: first-search` 时,服务在不导入 `node:sqlite`、不打开索引的情况下激活,把 SQLite 的实验性警告推迟到首次实际搜索;无效数据库让首次搜索失败,而不是服务激活失败。使用 `openAt: never` 时,全文搜索对该部署关闭:`searchSessions` 与 `searchEvents` 在任何请求规范化之前就以 `SESSION_QUERY_SEARCH_DISABLED` 失败,而继承的全部精确读取、过滤与追踪保持可用。请求超过编译谓词预算(跨会话 14 个组合谓词、会话内 13 个)或 SQLite 可移植的 32,766 绑定上限时,会在准备语句前以 `SESSION_QUERY_INVALID_FILTER` 失败。
|
|
68
|
+
|
|
69
|
+
### 失败与恢复
|
|
70
|
+
|
|
71
|
+
带类型的 `SessionQueryError` 失败携带稳定代码:搜索配置为关闭时 `SESSION_QUERY_SEARCH_DISABLED`;索引无法打开或对账时 `SESSION_QUERY_INDEX_FAILED`;搜索目标不存在时 `SESSION_QUERY_SESSION_NOT_FOUND`;语料库在分页之间变化时 `SESSION_QUERY_STALE_CURSOR`——请重试完整的搜索调用;游标不属于该请求时 `SESSION_QUERY_INVALID_CURSOR`。取消在同步 SQLite 调用之间被尊重;已在 JavaScript 线程上执行的语句无法被中断。
|
|
72
|
+
|
|
73
|
+
-----
|
|
74
|
+
|
|
75
|
+
<a id="understand-the-implementation"></a>
|
|
76
|
+
## 理解实现
|
|
77
|
+
|
|
78
|
+
<details>
|
|
79
|
+
<summary>实现细节——点击展开</summary>
|
|
80
|
+
|
|
81
|
+
本节解释后端背后的设计决策,并指出实现它们的代码位置;可观察行为已在[使用本包](#use-this-package)中完整说明。
|
|
82
|
+
|
|
83
|
+
### 设计理念
|
|
84
|
+
|
|
85
|
+
本后端建立在一个分离与三项承诺之上:
|
|
86
|
+
|
|
87
|
+
- **派生索引,绝不动源存储。** FTS 行存放在专用可丢弃数据库中;这里的代码从不打开 session-persistence 数据库。
|
|
88
|
+
- **实时优先的观察。** 一个串行化状态机比较持久化快照修订,只通过短生命周期读取句柄读取新增或已更改日志,并在一个事务中对账,因此搜索反映最新的稳定状态。
|
|
89
|
+
- **世代绑定的游标。** 每次语料库变化都会递增世代;游标携带其创建时的世代,宁可陈旧失败也不返回偏移后的页面。
|
|
90
|
+
- **字面短语即数据。** 调用方查询文本被引成一个 FTS5 短语,查询语法保持惰性;保留高亮标记在索引前从文档中剥离。
|
|
91
|
+
|
|
92
|
+
设计历史记录在 [SQLite FTS5 会话搜索笔记](../../../.agents/notes/archived/feature/2026-07-10-sqlite-session-query-provider.md)与[统一服务决策](../../../.agents/notes/archived/architecture/2026-07-23-unified-session-query-service.md)中。
|
|
93
|
+
|
|
94
|
+
### 源码地图
|
|
95
|
+
|
|
96
|
+
| 文件 | 职责 |
|
|
97
|
+
|---|---|
|
|
98
|
+
| [`src/index.ts`](src/index.ts) | 服务:配置、openAt 生命周期、串行化对账、查询执行、游标 |
|
|
99
|
+
| [`src/query.ts`](src/query.ts) | 请求规范化、参数化谓词、摘录、谓词与绑定预算 |
|
|
100
|
+
| [`src/schema.ts`](src/schema.ts) | 数据库 schema、application id 归属、原地重置、仅所有者文件创建 |
|
|
101
|
+
|
|
102
|
+
### 索引生命周期
|
|
103
|
+
|
|
104
|
+
持久化 FTS 行存放在专用派生数据库中并跨重启保留;实时会话使用连接本地 TEMP 表,遮蔽同一会话的持久化基库,并在实时所有者脱离后再次显示基库。两类表都在数字 `seed_length` 中保留精确继承切点;重建的 header 只公开 `isSeeded`,而切点参与实时指纹与持久来源修订。每次搜索执行一次串行化观察:列出持久化快照、把逐会话修订与已索引行比较、只通过读取句柄读取新增或已更改日志(在内存中补齐被中断的末尾轮次,从不写回)、提取语义文档,并在运行查询前于一个事务中提交对账。重复查询与不变的重新打开不读取任何内容;切换存储或观察到新增、已更改、已删除或经外部修复的来源时,会在下次稳定观察时对账。来源或事务失败不提交任何内容,下一次搜索重试。
|
|
105
|
+
|
|
106
|
+
### Schema 归属
|
|
107
|
+
|
|
108
|
+
数据库携带 application id 与 schema 版本 8。打开时拒绝其他应用程序拥有的文件或规范数据库,拒绝未知用户表;只有已识别的不兼容派生 schema 才会原地重置——因此不相关或 session-persistence 数据库绝不会被触碰。在 POSIX 文件系统上,缺失的目录与数据库文件以仅所有者可访问的方式创建(进程 umask 前为 `0700` 与 `0600`)。每个派生索引路径在一个进程中只能由一个服务拥有;世代与 TEMP 遮蔽状态由连接持有。
|
|
109
|
+
|
|
110
|
+
</details>
|
|
111
|
+
|
|
112
|
+
-----
|
|
113
|
+
|
|
114
|
+
<a id="further-exploration"></a>
|
|
115
|
+
## 进一步探索
|
|
116
|
+
|
|
117
|
+
当包级约定不够用时阅读以下页面。它们从共享查询服务逐步进入类型级约定与设计证据。
|
|
118
|
+
|
|
119
|
+
- [会话查询子系统参考](../../../docs/subsystems/session-query.zh.md)——本后端实现的完整类型级约定。
|
|
120
|
+
- [dsh-session-query](../session-query/README.zh.md)——服务定义:本后端继承的精确读取、过滤与追踪。
|
|
121
|
+
- [dsh-tool-session-query](../../experimental/tool-session-query/README.zh.md)——调用这些搜索方法的面向模型消费方。
|
|
122
|
+
- [SQLite FTS5 会话搜索](../../../.agents/notes/archived/feature/2026-07-10-sqlite-session-query-provider.md)——搜索语义、对账与 tokenizer 决策。
|
|
123
|
+
- [JSONL 会话持久化](../../session/session-persistence-jsonl/README.zh.md)——本可丢弃索引观察的权威 Session store;其 root 必须与本包的数据库路径分开。
|
|
124
|
+
|
|
125
|
+
-----
|
|
126
|
+
|
|
127
|
+
<a id="model-experience"></a>
|
|
128
|
+
## 模型体验
|
|
129
|
+
|
|
130
|
+
无,因为该搜索后端只向调用方返回命中,且不注册任何面向模型的内容。
|
|
131
|
+
|
|
132
|
+
#### KV Cache 影响
|
|
133
|
+
|
|
134
|
+
无;本包既不组装也不发送提供方请求。
|
|
135
|
+
|
|
136
|
+
## 已知限制与延期工作
|
|
137
|
+
|
|
138
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
这些限制说明本包何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是通用 SQLite 对比或任务积压。
|
|
142
|
+
|
|
143
|
+
- **无调用方授权**——这是上下文范围内的可信服务;模型工具或 UI 必须强制执行自己的访问策略。
|
|
144
|
+
- **同步查询执行**——`DatabaseSync` 在 MATCH 执行期间会阻塞 JavaScript 线程,且无法中断已运行的语句。
|
|
145
|
+
- **Token 召回,而非任意子字符串**——`unicode61` tokenizer 不会匹配更大 token 中的子字符串;对字面扫描使用 `filterEvents()`。
|
|
146
|
+
- **单一所有者的派生索引**——每个索引路径必须仅归一个进程中的一个服务所有;不支持外部写入者与多进程共享。
|
|
147
|
+
|
|
148
|
+
<a id="dev-note"></a>
|
|
149
|
+
### 开发备注
|
|
150
|
+
|
|
151
|
+
<details>
|
|
152
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
153
|
+
|
|
154
|
+
本开发备注是维护者的工作上下文:开放设计问题与尚未决定的探索方向。它明确不具权威性——已交付的行为、限制与既定理由以上文、包代码和相关 Agent Note 为准。
|
|
155
|
+
|
|
156
|
+
#### 未来:其他 tokenizer 与搜索提供方
|
|
157
|
+
|
|
158
|
+
`unicode61` tokenizer 的选择牺牲子字符串召回,以换取较小的索引体积与双字符 token 支持;trigram 备选方案经实测后被否决。切换 tokenizer 或增加另一个搜索后端会改变索引召回,并需要各自的对账与世代方案。
|
|
159
|
+
|
|
160
|
+
</details>
|