@avantf/dsh-mem 0.6.4 → 0.8.0
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/README.md +19 -10
- package/lib/client.js +1665 -3466
- package/lib/dsh-build.json +6 -5
- package/lib/engine/graph-recall/in-memory.d.ts +93 -0
- package/lib/engine/graph-recall/index.d.ts +22 -0
- package/lib/engine/graph-recall/traverse.d.ts +119 -0
- package/lib/engine/graph-recall/types.d.ts +188 -0
- package/lib/engine/mem/config/config_files.d.ts +1 -1
- package/lib/engine/mem/config/loader.d.ts +2 -3
- package/lib/engine/mem/config/paths.d.ts +2 -13
- package/lib/engine/mem/db/dao/contradictions.d.ts +4 -22
- package/lib/engine/mem/db/dao/entities.d.ts +80 -7
- package/lib/engine/mem/db/dao/fact_sources.d.ts +3 -13
- package/lib/engine/mem/db/dao/facts.d.ts +311 -56
- package/lib/engine/mem/db/dao/triples.d.ts +1 -26
- package/lib/engine/mem/db/graph.d.ts +249 -0
- package/lib/engine/mem/db/journal_notes.d.ts +35 -0
- package/lib/engine/mem/db/migrations.d.ts +9 -0
- package/lib/engine/mem/db/port.d.ts +22 -3
- package/lib/engine/mem/db/schema.d.ts +119 -0
- package/lib/engine/mem/db/tokenizer.d.ts +9 -0
- package/lib/engine/mem/dbdrivers/fake/driver.d.ts +75 -0
- package/lib/engine/mem/dbdrivers/fake/index.d.ts +7 -0
- package/lib/engine/mem/dbdrivers/fake/surface.d.ts +34 -0
- package/lib/engine/mem/dbdrivers/fake/transport.d.ts +61 -0
- package/lib/engine/mem/dbdrivers/sqlite/connection.d.ts +14 -0
- package/lib/engine/mem/dbdrivers/sqlite/contradictions.d.ts +35 -0
- package/lib/engine/mem/dbdrivers/sqlite/dao/index.d.ts +16 -0
- package/lib/engine/mem/dbdrivers/sqlite/driver.d.ts +54 -0
- package/lib/engine/mem/dbdrivers/sqlite/facts.d.ts +117 -0
- package/lib/engine/mem/dbdrivers/sqlite/index.d.ts +6 -0
- package/lib/engine/mem/dbdrivers/sqlite/migrations.d.ts +15 -0
- package/lib/engine/mem/dbdrivers/sqlite/relations.d.ts +62 -0
- package/lib/engine/mem/dbdrivers/sqlite/search.d.ts +56 -0
- package/lib/engine/mem/dbdrivers/sqlite/sources.d.ts +37 -0
- package/lib/engine/mem/defaults.d.ts +3 -4
- package/lib/engine/mem/dispatch.d.ts +7 -32
- package/lib/engine/mem/entities/extract.d.ts +44 -47
- package/lib/engine/mem/eval/derived_runner.d.ts +6 -1
- package/lib/engine/mem/eval/relation_gold.d.ts +251 -0
- package/lib/engine/mem/eval/write_metrics.d.ts +1 -1
- package/lib/engine/mem/facts_io.d.ts +328 -0
- package/lib/engine/mem/index.d.ts +10 -2
- package/lib/engine/mem/interfaces/capabilities.d.ts +30 -0
- package/lib/engine/mem/interfaces/common.d.ts +11 -0
- package/lib/engine/mem/interfaces/errors.d.ts +65 -0
- package/lib/engine/mem/interfaces/index.d.ts +18 -0
- package/lib/engine/mem/interfaces/migrations.d.ts +21 -0
- package/lib/engine/mem/interfaces/repositories.d.ts +471 -0
- package/lib/engine/mem/interfaces/search_index.d.ts +113 -0
- package/lib/engine/mem/interfaces/storage_backend.d.ts +84 -0
- package/lib/engine/mem/interfaces/storage_driver.d.ts +43 -0
- package/lib/engine/mem/interfaces/version.d.ts +34 -0
- package/lib/engine/mem/lifecycle/contradiction.d.ts +2 -2
- package/lib/engine/mem/maintenance_paths.d.ts +41 -0
- package/lib/engine/mem/modelBootstrap.d.ts +1 -1
- package/lib/engine/mem/relations/confidence.d.ts +39 -0
- package/lib/engine/mem/relations/extract.d.ts +128 -0
- package/lib/engine/mem/relations/index.d.ts +32 -0
- package/lib/engine/mem/relations/name-quality.d.ts +78 -0
- package/lib/engine/mem/relations/normalize.d.ts +275 -0
- package/lib/engine/mem/relations/patterns.d.ts +67 -0
- package/lib/engine/mem/relations/statement.d.ts +88 -0
- package/lib/engine/mem/relations/types.d.ts +79 -0
- package/lib/engine/mem/runtime.d.ts +117 -90
- package/lib/engine/mem/storage/create.d.ts +42 -0
- package/lib/engine/mem/storage/errors.d.ts +65 -0
- package/lib/engine/mem/storage/index.d.ts +15 -0
- package/lib/engine/mem/storage/ports.d.ts +472 -0
- package/lib/engine/mem/storage/registry.d.ts +37 -0
- package/lib/engine/mem/storage/sqlite.d.ts +28 -0
- package/lib/engine/mem/store/common.d.ts +1 -1
- package/lib/engine/mem/store/entity_leg.d.ts +59 -2
- package/lib/engine/mem/store/entity_sweep.d.ts +4 -3
- package/lib/engine/mem/store/explicit_relations.d.ts +52 -0
- package/lib/engine/mem/store/facts_restore.d.ts +124 -0
- package/lib/engine/mem/store/floors.d.ts +4 -1
- package/lib/engine/mem/store/graph_reader.d.ts +146 -0
- package/lib/engine/mem/store/hybrid.d.ts +50 -13
- package/lib/engine/mem/store/kinds.d.ts +47 -0
- package/lib/engine/mem/store/legs.d.ts +24 -29
- package/lib/engine/mem/store/lexical.d.ts +36 -45
- package/lib/engine/mem/store/memory.d.ts +486 -82
- package/lib/engine/mem/store/recall_policy.d.ts +49 -0
- package/lib/engine/mem/store/relation_backfill.d.ts +210 -0
- package/lib/engine/mem/store/relation_planner.d.ts +191 -0
- package/lib/engine/mem/store/secret_guard.d.ts +0 -1
- package/lib/engine/mem/store/self_query.d.ts +4 -2
- package/lib/engine/mem/store/time_filter.d.ts +121 -0
- package/lib/engine/mem/store/titles.d.ts +52 -0
- package/lib/engine/mem/store/vector_repair.d.ts +44 -54
- package/lib/engine/mem-contract/config.d.ts +44 -38
- package/lib/engine/mem-contract/text.d.ts +1 -1
- package/lib/engine/mem-contract/tools.d.ts +184 -117
- package/lib/engine/mem-contract/types.d.ts +364 -288
- package/lib/index.js +13898 -11500
- package/lib/interface-version.json +1 -1
- package/lib/types/client/index.d.ts +2 -2
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/paging.d.ts +3 -12
- package/lib/types/client/paging.d.ts.map +1 -1
- package/lib/types/client/summarize.d.ts.map +1 -1
- package/lib/types/command.d.ts +61 -0
- package/lib/types/command.d.ts.map +1 -0
- package/lib/types/envinit-bootstrap.d.ts +1 -1
- package/lib/types/envinit.d.ts +2 -6
- package/lib/types/envinit.d.ts.map +1 -1
- package/lib/types/hints.d.ts +28 -24
- package/lib/types/hints.d.ts.map +1 -1
- package/lib/types/index.d.ts +21 -40
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/inject.d.ts +3 -2
- package/lib/types/inject.d.ts.map +1 -1
- package/lib/types/interface_gate.d.ts +9 -9
- package/lib/types/prompt.d.ts +17 -41
- package/lib/types/prompt.d.ts.map +1 -1
- package/lib/types/provision.d.ts +3 -0
- package/lib/types/provision.d.ts.map +1 -1
- package/lib/types/remote.d.ts +23 -9
- package/lib/types/remote.d.ts.map +1 -1
- package/lib/types/render.d.ts +3 -3
- package/lib/types/tool_schema.d.ts +4 -0
- package/lib/types/tool_schema.d.ts.map +1 -1
- package/lib/types/vectorMigration.d.ts +5 -7
- package/lib/types/vectorMigration.d.ts.map +1 -1
- package/package.json +16 -15
- package/lib/engine/mem/config/domains.d.ts +0 -20
- package/lib/engine/mem/db/dao/chunks.d.ts +0 -231
- package/lib/engine/mem/db/dao/documents.d.ts +0 -51
- package/lib/engine/mem/db/hash.d.ts +0 -2
- package/lib/engine/mem/db/knowledge.d.ts +0 -17
- package/lib/engine/mem/eval/index.d.ts +0 -4
- package/lib/engine/mem/git.d.ts +0 -73
- package/lib/engine/mem/router.d.ts +0 -51
- package/lib/engine/mem/store/doc_files.d.ts +0 -125
- package/lib/engine/mem/store/document_text.d.ts +0 -47
- package/lib/engine/mem/store/ingest_guard.d.ts +0 -25
- package/lib/engine/mem/store/knowledge.d.ts +0 -598
- package/lib/engine/mem/store/source_picker.d.ts +0 -43
- package/lib/engine/mem-retrieval/adapters/local_reranker.d.ts +0 -52
- package/lib/engine/mem-retrieval/adapters/none_reranker.d.ts +0 -10
- package/lib/engine/mem-retrieval/rerank.d.ts +0 -13
- package/lib/types/client/domains.d.ts +0 -53
- package/lib/types/client/domains.d.ts.map +0 -1
- package/lib/types/client/ingest.d.ts +0 -24
- package/lib/types/client/ingest.d.ts.map +0 -1
- package/lib/types/open.d.ts +0 -77
- package/lib/types/open.d.ts.map +0 -1
- package/lib/types/reconcile.d.ts +0 -64
- package/lib/types/reconcile.d.ts.map +0 -1
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
/** Shared domain types for avantf-mem. Single source of truth in @avantf/mem-contract. */
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The memory has TWO layers, and `kind` says which one a fact belongs to
|
|
4
|
+
* (JOURNAL_NOTES_REDESIGN N1/N2).
|
|
5
|
+
*
|
|
6
|
+
* - `journal` is EPISODIC: what was done / talked about / thought about, one entry per episode,
|
|
7
|
+
* anchored by the caller's `event_date`. A journal row without an event date cannot answer
|
|
8
|
+
* "what did I do yesterday", so the write path refuses one.
|
|
9
|
+
* - `note` is SEMANTIC: a stable fact, preference, constraint, decision or pitfall that is worth
|
|
10
|
+
* recalling without knowing when it was learned.
|
|
11
|
+
*
|
|
12
|
+
* This replaces the eight-value `category` vocabulary (and its `categories` lookup table): the model
|
|
13
|
+
* no longer classifies by topic, it picks a layer. The set lives here because four surfaces read it —
|
|
14
|
+
* `mem_remember`'s schema (required, enum), `mem_recall`/`mem_admin`'s filters, the store's write
|
|
15
|
+
* guard and the one migration that maps the old 16 free-form values onto it.
|
|
16
|
+
*/
|
|
17
|
+
export declare const MEMORY_KINDS: readonly ["journal", "note"];
|
|
18
|
+
export type MemoryKind = (typeof MEMORY_KINDS)[number];
|
|
19
|
+
/**
|
|
20
|
+
* What each layer is FOR — the text the tool schema and the prompt section show.
|
|
21
|
+
*
|
|
22
|
+
* Spelled once beside the vocabulary so a caller reading `mem_remember`'s parameter help and one
|
|
23
|
+
* reading `mem_recall`'s filter help see the same two meanings.
|
|
24
|
+
*/
|
|
25
|
+
export declare const MEMORY_KIND_DESCRIPTIONS: Readonly<Record<MemoryKind, string>>;
|
|
26
|
+
/**
|
|
27
|
+
* The three time AXES a `mem_recall` call may filter on (TIME_SEARCH_AND_CATEGORIES D1).
|
|
28
|
+
*
|
|
29
|
+
* `created` = when the row was written, `updated` = when it was last modified, `event` = when the
|
|
30
|
+
* fact was TRUE (the caller's `event_date`, stored in `valid_from`). The axes never fall back into
|
|
31
|
+
* one another: a fact with no event time does not participate in an `event` filter, and a row that
|
|
32
|
+
* was never updated does not participate in an `updated` one (D3 in the implementation doc's §3.1).
|
|
33
|
+
*
|
|
34
|
+
* Declared here (not in `tools.ts`) because both the zod schema and the engine's normalizer read it:
|
|
35
|
+
* one list, so a fourth axis cannot reach the tool surface without reaching the SQL.
|
|
36
|
+
*/
|
|
37
|
+
export declare const TIME_FIELDS: readonly ["created", "updated", "event"];
|
|
38
|
+
export type TimeField = (typeof TIME_FIELDS)[number];
|
|
39
|
+
/**
|
|
40
|
+
* One explicit time filter — the shape `mem_recall.search`/`titles` accept on the wire.
|
|
41
|
+
*
|
|
42
|
+
* `field` is required (D1). Bounds: `on` (a whole day, or one minute when a time is given) XOR
|
|
43
|
+
* `from`/`to` (half-open range, `to` exclusive). Minute precision throughout (D3) — see
|
|
44
|
+
* `@avantf/mem`'s `store/time_filter.ts` for the normalization the engine applies.
|
|
45
|
+
*/
|
|
46
|
+
export interface TimeFilter {
|
|
47
|
+
field: TimeField;
|
|
48
|
+
on?: string;
|
|
49
|
+
from?: string;
|
|
50
|
+
to?: string;
|
|
51
|
+
timezone?: string;
|
|
52
|
+
}
|
|
4
53
|
/**
|
|
5
54
|
* The fact statuses a caller may filter by, as the ONE list every surface reads: the tool schema's
|
|
6
55
|
* `z.enum`, the derived MCP inputSchema and DSH parameter spec, and the CLI's `--status` flag (which
|
|
@@ -8,10 +57,34 @@ export type FactCategory = (typeof CATEGORY_VALUES)[number] | string;
|
|
|
8
57
|
*/
|
|
9
58
|
export declare const FACT_STATUSES: readonly ["active", "archived"];
|
|
10
59
|
export type FactStatus = (typeof FACT_STATUSES)[number];
|
|
60
|
+
/**
|
|
61
|
+
* The status FILTER vocabulary: a fact-status set plus `all`.
|
|
62
|
+
*
|
|
63
|
+
* The two filter surfaces that accept it (`mem_admin export` and `mem_recall titles`) need
|
|
64
|
+
* "either status", while a fact VIEW can only ever carry one of {@link FACT_STATUSES}. Declared here
|
|
65
|
+
* so the two filters cannot drift into two spellings of "all".
|
|
66
|
+
*/
|
|
67
|
+
export declare const STATUS_FILTERS: readonly ["active", "archived", "all"];
|
|
68
|
+
export type StatusFilter = (typeof STATUS_FILTERS)[number];
|
|
69
|
+
/**
|
|
70
|
+
* The longest title a write may carry, in characters (contract, engine and every surface agree).
|
|
71
|
+
*
|
|
72
|
+
* 120, the upper end of the range the design allows: a title is a human handle for a journal entry
|
|
73
|
+
* ("which transaction was this"), not prose, and the cap is what keeps it from becoming one. The
|
|
74
|
+
* SEARCH query shares the bound because it is compared against the stored title with `=`/`LIKE`.
|
|
75
|
+
*/
|
|
76
|
+
export declare const TITLE_MAX_CHARS = 120;
|
|
11
77
|
export interface FactSummary {
|
|
12
78
|
fact_id: number;
|
|
13
79
|
content: string;
|
|
14
|
-
|
|
80
|
+
/**
|
|
81
|
+
* The short handle of a journal entry (see {@link TITLE_MAX_CHARS}); `null` on a legacy journal
|
|
82
|
+
* and on every note that was written without one. Display only — it never participates in the
|
|
83
|
+
* content relevance score.
|
|
84
|
+
*/
|
|
85
|
+
title: string | null;
|
|
86
|
+
/** Which memory layer this fact belongs to (see {@link MEMORY_KINDS}). */
|
|
87
|
+
kind: MemoryKind;
|
|
15
88
|
status: FactStatus;
|
|
16
89
|
/**
|
|
17
90
|
* Trust as of now: the decayed value for an ACTIVE fact, the stored value for a
|
|
@@ -33,6 +106,20 @@ export interface FactTriple {
|
|
|
33
106
|
obj: string;
|
|
34
107
|
confidence: number;
|
|
35
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* One relation a CALLER stated on a note (`mem_remember.relations`), read back for the detail view
|
|
111
|
+
* (STRUCTURED_RELATIONS §2/§5).
|
|
112
|
+
*
|
|
113
|
+
* This is the EXPLICIT half of the graph resolved back to its stored names (after entity/predicate
|
|
114
|
+
* normalization) — the same three slots the write took. Extracted edges (`source: 'svo'`) are
|
|
115
|
+
* deliberately not part of this list: they are derivable from `content`, and mixing them in would
|
|
116
|
+
* make "what did the caller state" unanswerable. A journal has none by construction (note-only).
|
|
117
|
+
*/
|
|
118
|
+
export interface FactRelation {
|
|
119
|
+
subject: string;
|
|
120
|
+
predicate: string;
|
|
121
|
+
object: string;
|
|
122
|
+
}
|
|
36
123
|
/**
|
|
37
124
|
* The retention diagnostics on a fact view: the trust value, the active days left before the
|
|
38
125
|
* trust clock forgets it, and the reinforcement counter.
|
|
@@ -54,6 +141,15 @@ export interface FactDetail extends FactSummary {
|
|
|
54
141
|
supersedes_id: number | null;
|
|
55
142
|
entities: string[];
|
|
56
143
|
triples: FactTriple[];
|
|
144
|
+
/**
|
|
145
|
+
* The relations a CALLER stated on this note (`source: 'explicit'`), in insertion order.
|
|
146
|
+
*
|
|
147
|
+
* Empty for a note nobody declared relations for and for every journal (the layer refuses them).
|
|
148
|
+
* `update` REPLACES this set; an update that omits `relations` and lands on the same row leaves
|
|
149
|
+
* it untouched, while a changed content starts a new revision with no explicit edges of its own
|
|
150
|
+
* (STRUCTURED_RELATIONS §5).
|
|
151
|
+
*/
|
|
152
|
+
relations: FactRelation[];
|
|
57
153
|
/** Active-day clock value at the last settle. */
|
|
58
154
|
settle_clock: number;
|
|
59
155
|
pinned_at: string | null;
|
|
@@ -94,36 +190,25 @@ export interface FactSourceView {
|
|
|
94
190
|
kind: 'session' | 'kb_doc' | 'tool' | 'manual';
|
|
95
191
|
ref: string;
|
|
96
192
|
}
|
|
97
|
-
/** A single hit from hybrid retrieval over the
|
|
193
|
+
/** A single hit from hybrid retrieval over the memory corpus. */
|
|
98
194
|
export interface RecallHit {
|
|
99
|
-
|
|
195
|
+
/** The hit type. Only memory facts remain, so this is always `fact`. */
|
|
196
|
+
kind: 'fact';
|
|
100
197
|
ref_id: number;
|
|
101
198
|
text: string;
|
|
102
199
|
score: number;
|
|
103
|
-
/**
|
|
104
|
-
* Knowledge-base taxonomy (`domain → source`) of a `doc_chunk`, taken from the
|
|
105
|
-
* `documents` row by the store that owns it. Both are null for memory facts.
|
|
106
|
-
*
|
|
107
|
-
* Carried as fields rather than re-parsed out of `source_ref`: either name may
|
|
108
|
-
* itself contain `:` (`domain:source:docId:idx`), so any split of `source_ref`
|
|
109
|
-
* is a guess. Filters must use these, and so must the UI.
|
|
110
|
-
*/
|
|
111
|
-
domain: string | null;
|
|
112
|
-
source: string | null;
|
|
113
200
|
source_ref: string;
|
|
114
201
|
entities: string[];
|
|
115
202
|
/**
|
|
116
203
|
* When this hit was first recorded: a fact's revision chain keeps the ORIGINAL row's
|
|
117
204
|
* `created_at` across a supersede (`mem_remember update`), so this is when the memory was
|
|
118
|
-
* first asserted, not when its current text was written (see `updated_at`).
|
|
119
|
-
* carries its owning document's `created_at`.
|
|
205
|
+
* first asserted, not when its current text was written (see `updated_at`).
|
|
120
206
|
*/
|
|
121
207
|
created_at: string;
|
|
122
208
|
/**
|
|
123
209
|
* When this row was last CHANGED — an edit, pin/unpin, reinforcement, archive or restore.
|
|
124
210
|
* Retrieval and the daily settle deliberately do not write it, so it never means "last
|
|
125
|
-
* retrieved"; a copy can carry `null` on a legacy row.
|
|
126
|
-
* document's `updated_at` (re-ingest bumps it).
|
|
211
|
+
* retrieved"; a copy can carry `null` on a legacy row.
|
|
127
212
|
*/
|
|
128
213
|
updated_at: string | null;
|
|
129
214
|
/**
|
|
@@ -143,11 +228,10 @@ export interface RecallHit {
|
|
|
143
228
|
*/
|
|
144
229
|
scores?: Record<string, RecallLegScore | null>;
|
|
145
230
|
/**
|
|
146
|
-
* P-01: the FUSION output score for this hit, before
|
|
231
|
+
* P-01: the FUSION output score for this hit, before the output budget reshapes the list.
|
|
147
232
|
*
|
|
148
|
-
* `score` is what the surface ranks by
|
|
149
|
-
*
|
|
150
|
-
* the fusion value itself rather than a number that means a different thing per surface.
|
|
233
|
+
* `score` is what the surface ranks by, so a caller reasoning about "which leg carried this"
|
|
234
|
+
* needs the fusion value itself rather than the rounded number a surface prints.
|
|
151
235
|
*/
|
|
152
236
|
final?: number;
|
|
153
237
|
/**
|
|
@@ -157,7 +241,240 @@ export interface RecallHit {
|
|
|
157
241
|
*/
|
|
158
242
|
valid_from?: string;
|
|
159
243
|
valid_to?: string;
|
|
244
|
+
/**
|
|
245
|
+
* The fact's title, when it has one (journal entries normally do, notes usually do not).
|
|
246
|
+
*
|
|
247
|
+
* A DISPLAY field: it is serialized only when non-null (the same convention as `valid_from`) and
|
|
248
|
+
* it is deliberately not part of any retrieval score — title search is its own action
|
|
249
|
+
* (`mem_recall.titles`), and mixing the two score semantics is what that action exists to
|
|
250
|
+
* avoid.
|
|
251
|
+
*/
|
|
252
|
+
title?: string;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* One candidate of `mem_recall.titles` — a title match, NOT a content hit.
|
|
256
|
+
*
|
|
257
|
+
* Deliberately its own shape instead of {@link RecallHit}: `RecallHit.kind` means "the hit type"
|
|
258
|
+
* (`fact`), while this shape needs the memory LAYER (`journal`/`note`), and the identity field the
|
|
259
|
+
* caller acts on is `fact_id` (`RecallHit` calls it `ref_id`). Reusing the hit would make `kind`
|
|
260
|
+
* carry two meanings and would let the model mistake a title match for a content relevance score.
|
|
261
|
+
*
|
|
262
|
+
* There is NO `score` field on purpose (JOURNAL_TITLE_SEARCH §11.4): the ordering (exact title >
|
|
263
|
+
* prefix > matched terms > recency) is computed on the server, and a number exported here would be
|
|
264
|
+
* read as "how relevant the CONTENT is", which is `mem_recall.search`'s answer, not this one's.
|
|
265
|
+
*/
|
|
266
|
+
export interface TitleCandidate {
|
|
267
|
+
fact_id: number;
|
|
268
|
+
/** The row's CURRENT title — the handle to continue the transaction with. */
|
|
269
|
+
title: string;
|
|
270
|
+
/**
|
|
271
|
+
* The title text the query matched: normally `title`, and one of the aliases a CORRECTED
|
|
272
|
+
* transaction used to carry when the old handle is what matched (v17's controlled `retitle`).
|
|
273
|
+
*
|
|
274
|
+
* Always present, so a caller can compare the two without a special case: `matched_title !== title`
|
|
275
|
+
* means "this hit came from an old name" — the row is the same transaction, just renamed.
|
|
276
|
+
*/
|
|
277
|
+
matched_title: string;
|
|
278
|
+
memory_kind: MemoryKind;
|
|
279
|
+
status: FactStatus;
|
|
280
|
+
created_at: string;
|
|
281
|
+
updated_at: string | null;
|
|
282
|
+
/** The fact's event time (`valid_from`), when it has one — the journal axis that tells two entries apart. */
|
|
283
|
+
event_date?: string;
|
|
284
|
+
/** The first characters of the content, for judging "same transaction or not"; absent when `include_excerpt` is false. */
|
|
285
|
+
excerpt?: string;
|
|
286
|
+
}
|
|
287
|
+
/** One page of an EXACT result — the envelope both exact surfaces report (RECALL_INTERFACE §3). */
|
|
288
|
+
export interface ExactPageEnvelope {
|
|
289
|
+
/** How many facts matched the literal query (before paging). */
|
|
290
|
+
total: number;
|
|
291
|
+
/** The page's first row index (`0`-based). */
|
|
292
|
+
offset: number;
|
|
293
|
+
/** The page size that was applied (after the 50 cap). */
|
|
294
|
+
limit: number;
|
|
295
|
+
/** `offset + hits.length < total` — there is another page. */
|
|
296
|
+
truncated: boolean;
|
|
297
|
+
}
|
|
298
|
+
/** `mem_recall.search` when the literal (exact) pass matched: RAW hits, never floored (RECALL_INTERFACE §2.2/§5). */
|
|
299
|
+
export type ExactSearchResult = ExactPageEnvelope & {
|
|
300
|
+
mode: 'exact';
|
|
301
|
+
hits: RecallHit[];
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* `mem_recall.search` when the caller gave a TIME WINDOW and no query (RECALL_INTERFACE §2.4).
|
|
305
|
+
*
|
|
306
|
+
* The window IS the question: no literal pass, no relation plan, no fuzzy legs. `hits` are the
|
|
307
|
+
* active facts inside the window, newest first along `time.field`, and `score` is the same constant
|
|
308
|
+
* 1 the exact page reports — there is no relevance number here to compare with anything.
|
|
309
|
+
*/
|
|
310
|
+
export type TimeSearchResult = ExactPageEnvelope & {
|
|
311
|
+
mode: 'time';
|
|
312
|
+
hits: RecallHit[];
|
|
313
|
+
};
|
|
314
|
+
/**
|
|
315
|
+
* `mem_recall.search` when no literal match existed: the hybrid retrieval, unchanged except that its
|
|
316
|
+
* knobs are the engine's fixed rules (`min_score = 0.5`, `topK = 5`) instead of caller parameters.
|
|
317
|
+
*/
|
|
318
|
+
export type FuzzySearchResult = RecallResult & {
|
|
319
|
+
mode: 'fuzzy';
|
|
320
|
+
};
|
|
321
|
+
/** One endpoint of a relation path — the STORED entity, by id and canonical name. */
|
|
322
|
+
export interface RelationNode {
|
|
323
|
+
/** `entities.entity_id` — stable across renames of the display label. */
|
|
324
|
+
entity_id: number;
|
|
325
|
+
/** `entities.name`, the canonical name (an alias in the query resolves to this). */
|
|
326
|
+
name: string;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* One hop of a relation path: the stored `subject —predicate→ object` of ONE edge, plus the fact it
|
|
330
|
+
* was extracted from. `fact_id` is the evidence — the row `mem_admin detail` opens — so a path is
|
|
331
|
+
* never a string answer without a source.
|
|
332
|
+
*/
|
|
333
|
+
export interface RelationPathEdge {
|
|
334
|
+
subject: string;
|
|
335
|
+
predicate: string;
|
|
336
|
+
object: string;
|
|
337
|
+
/**
|
|
338
|
+
* The ACTIVE fact this edge came from. Every edge of every path carries one: the relation stage
|
|
339
|
+
* never reuses a path whose evidence cannot be opened.
|
|
340
|
+
*/
|
|
341
|
+
fact_id: number;
|
|
342
|
+
/** This edge's extractor confidence in `[0,1]`; the path's own `confidence` is the product of its edges'. */
|
|
343
|
+
confidence: number;
|
|
160
344
|
}
|
|
345
|
+
/** A complete relation path (RELATIONAL_RECALL §7), from the queried node to the node walked to. */
|
|
346
|
+
export interface RelationPath {
|
|
347
|
+
start: RelationNode;
|
|
348
|
+
end: RelationNode;
|
|
349
|
+
/** Number of edges — 1 or 2 in this version ("最大 2 跳,不做任意递归"). */
|
|
350
|
+
hops: number;
|
|
351
|
+
/** The edges in walk order; `edges[0].subject` is `start.name` and the last `object` is `end.name`. */
|
|
352
|
+
edges: RelationPathEdge[];
|
|
353
|
+
/** Product of the edge confidences, rounded by the graph library. */
|
|
354
|
+
confidence: number;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* The fact behind a relation answer.
|
|
358
|
+
*
|
|
359
|
+
* Deliberately NOT a {@link RecallHit}: a relation answer is not a ranked content match, so this
|
|
360
|
+
* shape has NO `score` (there is nothing to rank it against), and the handle a caller acts on is
|
|
361
|
+
* `fact_id` (`RecallHit` calls it `ref_id`). Keeping them apart is what stops a model from reading
|
|
362
|
+
* "this path's evidence" as "a relevance number".
|
|
363
|
+
*/
|
|
364
|
+
export interface RelationEvidence {
|
|
365
|
+
/** The fact id every path edge and `mem_admin detail` share. */
|
|
366
|
+
fact_id: number;
|
|
367
|
+
/** The fact's content, verbatim (bounded by the retrieval output budget, like a hit). */
|
|
368
|
+
text: string;
|
|
369
|
+
/** The memory layer, so a caller knows whether it is reading a journal or a note. */
|
|
370
|
+
memory_kind: MemoryKind;
|
|
371
|
+
title?: string;
|
|
372
|
+
created_at: string;
|
|
373
|
+
updated_at: string | null;
|
|
374
|
+
/** Set when the output budget shortened `text` (never when the evidence itself was dropped). */
|
|
375
|
+
truncated?: boolean;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* `mem_recall.search` when the query named a relation the graph could answer
|
|
379
|
+
* (RELATIONAL_RECALL §6–7, Phase 4).
|
|
380
|
+
*
|
|
381
|
+
* It carries STRUCTURE (`paths`, each edge pointing at its fact) and the evidence rows — never a
|
|
382
|
+
* natural-language answer, and never a relevance score. An empty `paths` is not a relation result
|
|
383
|
+
* at all: the store falls back to {@link FuzzySearchResult} instead, so `mode:"relation"` always
|
|
384
|
+
* means "at least one path (and therefore at least one openable fact) was found".
|
|
385
|
+
*
|
|
386
|
+
* A PURE multi-entity question ("张伟和李娜") is not a relation question: it is answered at the
|
|
387
|
+
* fact level by {@link FactSearchResult} (`mode:"facts"`), over `fact_entities`, so journal entries
|
|
388
|
+
* and notes without any relation edge are covered. The graph library's `andPaths` is still available
|
|
389
|
+
* to adapters that want edge evidence, but `mem_recall.search` no longer routes a query to it.
|
|
390
|
+
*/
|
|
391
|
+
export interface RelationSearchResult {
|
|
392
|
+
mode: 'relation';
|
|
393
|
+
/** The paths, best first (confidence DESC, hops ASC, evidence recency DESC). */
|
|
394
|
+
paths: RelationPath[];
|
|
395
|
+
/** The distinct facts the paths' edges point at, in path order. */
|
|
396
|
+
evidence: RelationEvidence[];
|
|
397
|
+
/** Distinct candidate paths found before paging (`paths.length` may be smaller). */
|
|
398
|
+
total: number;
|
|
399
|
+
/** `true` when more paths existed than this result returns. */
|
|
400
|
+
truncated: boolean;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* The citation handle of a fact row: `memory:fact:<id>`.
|
|
404
|
+
*
|
|
405
|
+
* ONE definition, because three surfaces spell this string: a {@link RecallHit}'s `source_ref`, a
|
|
406
|
+
* {@link FactEvidence}'s, and the model projection's fallback for a host that predates the field
|
|
407
|
+
* (an added field does not bump `WIRE_VERSION`, see `tools.ts#factsForModel`). The read surface
|
|
408
|
+
* DERIVES it — nothing is stored — so a handle that disagreed between two of them would be a
|
|
409
|
+
* citation the other surface cannot resolve (REVIEW-FACT-AND-R2 P2-1).
|
|
410
|
+
*/
|
|
411
|
+
export declare function factSourceRef(factId: number): string;
|
|
412
|
+
/**
|
|
413
|
+
* The fact behind a fact-level AND answer (docs/GRAPH_RECALL_AND_SEMANTICS.md §7.9).
|
|
414
|
+
*
|
|
415
|
+
* Deliberately NOT a {@link RecallHit}: this is not a ranked content match, so the shape has NO
|
|
416
|
+
* `score` (there is nothing to rank it against), and the handle a caller acts on is `fact_id`
|
|
417
|
+
* (`RecallHit` calls it `ref_id`). `memory_kind` + `status` say which layer and which revision the
|
|
418
|
+
* fact is, and `event_date` is the journal axis (the stored `valid_from`).
|
|
419
|
+
*/
|
|
420
|
+
export interface FactEvidence {
|
|
421
|
+
/** The fact id `mem_admin detail` opens. */
|
|
422
|
+
fact_id: number;
|
|
423
|
+
/**
|
|
424
|
+
* The citation handle, spelled exactly as a {@link RecallHit}'s `source_ref`
|
|
425
|
+
* (`memory:fact:<id>`) so an answer can cite a fact page row the same way it cites a hit.
|
|
426
|
+
*
|
|
427
|
+
* It is DERIVED from `fact_id` (the read surface builds it; nothing is stored), which is why it
|
|
428
|
+
* says nothing about P-08 provenance — that is `mem_admin detail`'s `sources`. Carried anyway
|
|
429
|
+
* because a caller that only sees this page must be able to quote a source without a second call.
|
|
430
|
+
*/
|
|
431
|
+
source_ref: string;
|
|
432
|
+
/** The fact's content, verbatim (bounded by the retrieval output budget, like a hit). */
|
|
433
|
+
content: string;
|
|
434
|
+
/** The memory layer, so a caller knows whether it is reading a journal or a note. */
|
|
435
|
+
memory_kind: MemoryKind;
|
|
436
|
+
/** `active` for every row this stage returns; carried so the field is explicit, not implied. */
|
|
437
|
+
status: FactStatus;
|
|
438
|
+
title?: string;
|
|
439
|
+
/** The fact's event time (`valid_from`), when it has one. */
|
|
440
|
+
event_date?: string;
|
|
441
|
+
created_at: string;
|
|
442
|
+
updated_at: string | null;
|
|
443
|
+
/** Set when the output budget shortened `content` (never when the fact itself was dropped). */
|
|
444
|
+
truncated?: boolean;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* `mem_recall.search` when the query was a PURE multi-entity connection
|
|
448
|
+
* (docs/GRAPH_RECALL_AND_SEMANTICS.md §7.9): every `facts` row mentions EVERY entity the query
|
|
449
|
+
* named, and `total`/`offset`/`limit`/`truncated` page the FACTS, not paths or edges.
|
|
450
|
+
*
|
|
451
|
+
* An empty page is not a result at all — the store continues to the relation stage and then fuzzy —
|
|
452
|
+
* so `mode:"facts"` always means at least one fact was found, and the caller never has to tell an
|
|
453
|
+
* empty answer from a failed one.
|
|
454
|
+
*/
|
|
455
|
+
export interface FactSearchResult extends ExactPageEnvelope {
|
|
456
|
+
mode: 'facts';
|
|
457
|
+
/** The facts, newest row first, each mentioning every queried entity. */
|
|
458
|
+
facts: FactEvidence[];
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* The `mem_recall.search` payload — ONE type for the five modes, so a caller must look at `mode`
|
|
462
|
+
* before it reads pagination (an exact, time or facts page), the paths and evidence (a relation
|
|
463
|
+
* answer) or the retrieval diagnostics (a fuzzy answer).
|
|
464
|
+
*/
|
|
465
|
+
export type MemorySearchResult = ExactSearchResult | TimeSearchResult | FactSearchResult | RelationSearchResult | FuzzySearchResult;
|
|
466
|
+
/** `mem_recall.titles` when one title is EXACTLY the query (case-sensitive; RECALL_INTERFACE §2.3). */
|
|
467
|
+
export type ExactTitlesResult = ExactPageEnvelope & {
|
|
468
|
+
mode: 'exact';
|
|
469
|
+
candidates: TitleCandidate[];
|
|
470
|
+
};
|
|
471
|
+
/** `mem_recall.titles` when no title equals the query: the title-index shortlist, fixed at `topK = 5`. */
|
|
472
|
+
export interface FuzzyTitlesResult {
|
|
473
|
+
mode: 'fuzzy';
|
|
474
|
+
candidates: TitleCandidate[];
|
|
475
|
+
}
|
|
476
|
+
/** The `mem_recall.titles` payload. */
|
|
477
|
+
export type TitlesResult = ExactTitlesResult | FuzzyTitlesResult;
|
|
161
478
|
/** P-01: one leg's contribution to a hit (see {@link RecallHit.scores}). */
|
|
162
479
|
export interface RecallLegScore {
|
|
163
480
|
/** The leg's own raw score, on its own scale. */
|
|
@@ -178,7 +495,11 @@ export interface RetrievalFloors {
|
|
|
178
495
|
semantic: number;
|
|
179
496
|
/** Distinct-query-term floor for the FTS leg (`retriever.min_fts_terms`; 1 when degraded). */
|
|
180
497
|
fts: number;
|
|
181
|
-
/**
|
|
498
|
+
/**
|
|
499
|
+
* Configured LOWER BOUND of the entity leg's evidence bar (`retriever.min_jaccard`). The leg
|
|
500
|
+
* applies a per-candidate anchor-rarity bar on top of it, in the same anchored-overlap unit — see
|
|
501
|
+
* `store/entity_leg.ts` and DESIGN §20.19 续.
|
|
502
|
+
*/
|
|
182
503
|
jaccard: number;
|
|
183
504
|
}
|
|
184
505
|
/**
|
|
@@ -226,12 +547,21 @@ export interface RecallResult {
|
|
|
226
547
|
};
|
|
227
548
|
/**
|
|
228
549
|
* The effective relevance floors for this query, when it ran through the hybrid orchestration.
|
|
229
|
-
* Absent on
|
|
550
|
+
* Absent on literal-only answers (an exact page) and non-hybrid payloads, which never scored a leg.
|
|
230
551
|
* When {@link RecallResult.relaxed} is true these are the RELAXED values that produced the hits.
|
|
231
552
|
*/
|
|
232
553
|
floors?: RetrievalFloors;
|
|
233
554
|
/** Per-leg candidates removed by those floors (see {@link RetrievalFloorDrops}). */
|
|
234
555
|
dropped_by_floor?: RetrievalFloorDrops;
|
|
556
|
+
/**
|
|
557
|
+
* Candidates the FUSED-score floor (`retriever.min_score`, default 0.5) removed after fusion.
|
|
558
|
+
*
|
|
559
|
+
* Absent when nothing was dropped (including when the floor is off). It is NOT part of
|
|
560
|
+
* `dropped_by_floor`: that structure attributes drops to a leg, and this threshold is applied after
|
|
561
|
+
* every leg has been fused. When {@link RecallResult.relaxed} is true this is the RELAXED pass's
|
|
562
|
+
* count, the same convention as `floors` / `dropped_by_floor`.
|
|
563
|
+
*/
|
|
564
|
+
dropped_by_score?: number;
|
|
235
565
|
/**
|
|
236
566
|
* The strict floors emptied this query's result and ONE relaxed pass supplied these hits (`floors`
|
|
237
567
|
* are that pass's values). Absent on an ordinary answer, on an explicit `floors: 'loose'` request
|
|
@@ -242,8 +572,8 @@ export interface RecallResult {
|
|
|
242
572
|
}
|
|
243
573
|
/**
|
|
244
574
|
* Weights reported when the semantic leg is unavailable (FTS+entity rebalance).
|
|
245
|
-
* Single source for
|
|
246
|
-
* same literal lived in
|
|
575
|
+
* Single source for the store and every surface that reports them — previously the
|
|
576
|
+
* same literal lived in more than one file and could silently desync.
|
|
247
577
|
*/
|
|
248
578
|
export declare const DEGRADED_WEIGHTS: RecallResult['weights'];
|
|
249
579
|
/**
|
|
@@ -264,8 +594,9 @@ export interface ContradictionRecord {
|
|
|
264
594
|
detected_at: string;
|
|
265
595
|
content_a: string;
|
|
266
596
|
content_b: string;
|
|
267
|
-
|
|
268
|
-
|
|
597
|
+
/** The two facts' memory layers (see {@link MEMORY_KINDS}); `null` on a legacy row. */
|
|
598
|
+
kind_a: string | null;
|
|
599
|
+
kind_b: string | null;
|
|
269
600
|
resolved: number;
|
|
270
601
|
}
|
|
271
602
|
/**
|
|
@@ -541,271 +872,16 @@ export interface VectorsFixStoreReport {
|
|
|
541
872
|
reindexed?: number;
|
|
542
873
|
}
|
|
543
874
|
/**
|
|
544
|
-
* `mem_admin vectors_fix`: what a repair did, or — with `dry_run` — what it WOULD do
|
|
875
|
+
* `mem_admin vectors_fix`: what a repair did, or — with `dry_run` — what it WOULD do.
|
|
545
876
|
*
|
|
546
|
-
* The
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
* AND over the stores actually repaired.
|
|
877
|
+
* The wrapper is kept separate from {@link VectorsFixStoreReport} because the repair reports a
|
|
878
|
+
* store-level result and a call-level one: `semantic_available` is "the model was available for
|
|
879
|
+
* the whole call", while the store report carries the counts.
|
|
550
880
|
*/
|
|
551
881
|
export interface VectorsFixReport {
|
|
552
882
|
stores: {
|
|
553
883
|
memory?: VectorsFixStoreReport;
|
|
554
|
-
knowledge?: VectorsFixStoreReport;
|
|
555
884
|
};
|
|
556
885
|
semantic_available: boolean;
|
|
557
886
|
dry_run: boolean;
|
|
558
887
|
}
|
|
559
|
-
/** `kb_manage ingest`: what one document produced. */
|
|
560
|
-
export interface IngestResult {
|
|
561
|
-
doc_id: number;
|
|
562
|
-
chunks: number;
|
|
563
|
-
/**
|
|
564
|
-
* How many chunks did NOT get a semantic vector. Absent when every chunk did, so a healthy ingest
|
|
565
|
-
* stays as quiet as it was.
|
|
566
|
-
*
|
|
567
|
-
* `chunks` counts what was CHUNKED, not what became semantically searchable: an encode failure (no
|
|
568
|
-
* model, bad input) or a write failure (`SQLITE_BUSY` under multi-process contention) skips that
|
|
569
|
-
* chunk while the text/entity/FTS indexes stay complete. Reporting the shortfall here is what stops
|
|
570
|
-
* "入库成功 N 段" from implying "N 段都能被语义检索到" — before this, the only way to find out was to
|
|
571
|
-
* run `kb_reindex` and compare `vectors_stale` against `vectors_encoded`. A missing embedding model
|
|
572
|
-
* reports every chunk, which is the honest reading of "indexed, but not semantically".
|
|
573
|
-
*/
|
|
574
|
-
vectors_failed?: number;
|
|
575
|
-
/**
|
|
576
|
-
* How the source bytes became text: `utf-8`, `utf-8-bom`, `utf-16le`, `utf-16be` or `gb18030`
|
|
577
|
-
* (absent for pasted text, for a document pulled back from its managed file, and for a PDF —
|
|
578
|
-
* whose text comes from an extracted layer rather than from a byte encoding). Reported because
|
|
579
|
-
* decoding a legacy-encoded file is a GUESS the caller should be able to see.
|
|
580
|
-
*/
|
|
581
|
-
encoding?: string;
|
|
582
|
-
/**
|
|
583
|
-
* Which converter turned the source into Markdown — `docx`, `xlsx`, `html` or `csv` (absent for
|
|
584
|
-
* text, PDF, and a body re-read from its managed file). The body is derived rather than read in
|
|
585
|
-
* that case, so the caller is told what derived it.
|
|
586
|
-
*/
|
|
587
|
-
converter?: string;
|
|
588
|
-
/** What that conversion could not carry over (dropped media, a truncated sheet, ragged rows). */
|
|
589
|
-
warnings?: string[];
|
|
590
|
-
/** The managed file this ingest wrote (`knowledge.docs.dir/<domain>/<source>/<title>.md`). */
|
|
591
|
-
file?: string;
|
|
592
|
-
/** Why the managed file could not be written; the document itself is still searchable. */
|
|
593
|
-
file_error?: string;
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* One existing document an ingest would land on — the machine-readable half of a collision.
|
|
597
|
-
*
|
|
598
|
-
* `path` is the managed `.md` copy (`knowledge.docs.dir/<domain>/<source>/<title>.md`), which is
|
|
599
|
-
* what the caller edits to change that document; `doc_id`/`title` are what it takes to name the
|
|
600
|
-
* collision. Reported by BOTH the add-only refusal (as text, for the agent) and the replace
|
|
601
|
-
* confirmation (as a list, for the UI's dialog and the CLI).
|
|
602
|
-
*/
|
|
603
|
-
export interface KbIngestConflict {
|
|
604
|
-
doc_id: number;
|
|
605
|
-
title: string;
|
|
606
|
-
path: string;
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* What `kb_manage` answers when a write would REPLACE an existing document and the caller did not
|
|
610
|
-
* confirm it. `conflict: true` is the flag the UI's 入库 form and the CLI dispatch on; nothing was
|
|
611
|
-
* written when this comes back, so "取消" is a no-op rather than a rollback.
|
|
612
|
-
*
|
|
613
|
-
* `would_overwrite`/`would_add` are the summary the confirmation dialog shows ("将覆盖 N 篇 /
|
|
614
|
-
* 新增 M 篇") — computed at plan time, when the targets are known, rather than re-derived by the
|
|
615
|
-
* caller from `conflicts`.
|
|
616
|
-
*/
|
|
617
|
-
export interface KbConflictReport {
|
|
618
|
-
conflict: true;
|
|
619
|
-
/** Chinese, actionable: names the colliding documents and says nothing was written. */
|
|
620
|
-
error: string;
|
|
621
|
-
conflicts: KbIngestConflict[];
|
|
622
|
-
would_overwrite: number;
|
|
623
|
-
would_add: number;
|
|
624
|
-
}
|
|
625
|
-
/**
|
|
626
|
-
* `kb_manage import`: what landed, what failed (with the reason), and what was skipped.
|
|
627
|
-
*
|
|
628
|
-
* `skipped` is the DIRECTORY walk's rejections (files whose name is not an ingestable format) — a
|
|
629
|
-
* silent list before this, which made "3 of 200 files imported" indistinguishable from "3 files".
|
|
630
|
-
* Only the first `SKIPPED_REPORTED` (a `core` constant) paths are listed; `skipped_total` is the real count.
|
|
631
|
-
*/
|
|
632
|
-
export interface ImportResult {
|
|
633
|
-
imported: IngestResult[];
|
|
634
|
-
failed: {
|
|
635
|
-
path: string;
|
|
636
|
-
error: string;
|
|
637
|
-
}[];
|
|
638
|
-
skipped: string[];
|
|
639
|
-
skipped_total: number;
|
|
640
|
-
}
|
|
641
|
-
/**
|
|
642
|
-
* One document's managed file, as the file system sees it right now.
|
|
643
|
-
*
|
|
644
|
-
* `stale` means the file's body no longer matches what the KB indexed (someone edited it and
|
|
645
|
-
* the change has not been ingested); `missing` means there is no file for this document (never
|
|
646
|
-
* written, deleted by hand, or replaced by another document's file).
|
|
647
|
-
*/
|
|
648
|
-
export interface KbDocFile {
|
|
649
|
-
doc_id: number;
|
|
650
|
-
title: string;
|
|
651
|
-
path: string;
|
|
652
|
-
stale: boolean;
|
|
653
|
-
missing: boolean;
|
|
654
|
-
}
|
|
655
|
-
/**
|
|
656
|
-
* `kb_manage sync`: the managed files vs what the KB indexed.
|
|
657
|
-
*
|
|
658
|
-
* `stale` is the plan and `reingested` what happened (equal unless `dry_run`); `orphans` are
|
|
659
|
-
* managed files with no document behind them — left by a hand-deleted row, and safe to delete.
|
|
660
|
-
*/
|
|
661
|
-
export interface KbSyncReport {
|
|
662
|
-
checked: number;
|
|
663
|
-
stale: KbDocFile[];
|
|
664
|
-
missing: KbDocFile[];
|
|
665
|
-
orphans: string[];
|
|
666
|
-
/**
|
|
667
|
-
* Files that sit exactly where a document's path says its own copy belongs, yet do not claim that
|
|
668
|
-
* document — a whole-file overwrite that destroyed the frontmatter.
|
|
669
|
-
*
|
|
670
|
-
* These ARE recovered automatically, but only behind guards: no `doc_id` at all, a non-empty
|
|
671
|
-
* body, a stamp that holds still (see `ADOPT_SETTLE_MS`) and a path exactly one document maps
|
|
672
|
-
* to. A candidate that fails any of them stays here, unclaimed, and `sync {adopt: true}` is the
|
|
673
|
-
* explicit per-document way to take it back immediately.
|
|
674
|
-
*/
|
|
675
|
-
unclaimed: KbUnclaimedFile[];
|
|
676
|
-
reingested: number;
|
|
677
|
-
/** How many documents this call adopted (`sync {adopt: true}`); 0 otherwise. */
|
|
678
|
-
adopted: number;
|
|
679
|
-
dry_run: boolean;
|
|
680
|
-
}
|
|
681
|
-
/** One adoptable file: its path names this document, but the file does not claim it. */
|
|
682
|
-
export interface KbUnclaimedFile {
|
|
683
|
-
doc_id: number;
|
|
684
|
-
title: string;
|
|
685
|
-
path: string;
|
|
686
|
-
}
|
|
687
|
-
/**
|
|
688
|
-
* `kb_manage reindex`: what it did, and what it deliberately did NOT redo (DESIGN §20).
|
|
689
|
-
*
|
|
690
|
-
* `vectors_stale` is the plan and `vectors_encoded` what happened; they differ when the embedder
|
|
691
|
-
* is unavailable, which is the case a caller needs to see instead of "nothing to do".
|
|
692
|
-
*/
|
|
693
|
-
export interface ReindexReport {
|
|
694
|
-
chunks: number;
|
|
695
|
-
entities_rebuilt: number;
|
|
696
|
-
vectors_stale: number;
|
|
697
|
-
vectors_encoded: number;
|
|
698
|
-
semantic_available: boolean;
|
|
699
|
-
dry_run: boolean;
|
|
700
|
-
}
|
|
701
|
-
/** `kb_manage list`: the stored document columns (everything but `meta`/`status`). */
|
|
702
|
-
export interface DocumentSummary {
|
|
703
|
-
doc_id: number;
|
|
704
|
-
domain: string;
|
|
705
|
-
source: string;
|
|
706
|
-
title: string;
|
|
707
|
-
source_uri: string | null;
|
|
708
|
-
created_at: string;
|
|
709
|
-
updated_at: string;
|
|
710
|
-
}
|
|
711
|
-
/** The full stored document row (`kb detail` minus its chunks). */
|
|
712
|
-
export interface DocumentRecord extends DocumentSummary {
|
|
713
|
-
meta: string;
|
|
714
|
-
status: string;
|
|
715
|
-
}
|
|
716
|
-
/** One stored chunk as `kb detail` returns it. */
|
|
717
|
-
export interface DocumentChunk {
|
|
718
|
-
chunk_id: number;
|
|
719
|
-
idx: number;
|
|
720
|
-
text: string;
|
|
721
|
-
headings_path: string;
|
|
722
|
-
source_ref: string;
|
|
723
|
-
}
|
|
724
|
-
/** `kb_manage detail`: the document row plus its chunks, in document order. */
|
|
725
|
-
export interface DocumentDetail extends DocumentRecord {
|
|
726
|
-
chunks: DocumentChunk[];
|
|
727
|
-
}
|
|
728
|
-
/** What one `kb_manage` source string turned out to be. */
|
|
729
|
-
export type SourceKind = 'url' | 'file' | 'directory' | 'text' | 'missing';
|
|
730
|
-
/**
|
|
731
|
-
* The answer the UI needs to label the input and pick the right `kb_manage` action.
|
|
732
|
-
*
|
|
733
|
-
* It lives in the CONTRACT rather than next to the engine that computes it, because the browser half
|
|
734
|
-
* cannot import the engine (it must not pull node into the client bundle) and used to hand-mirror this
|
|
735
|
-
* shape — the same "mirror drifts, then a render body dereferences a field the host stopped sending"
|
|
736
|
-
* failure that has already cost this family once.
|
|
737
|
-
*/
|
|
738
|
-
export interface SourceClassification {
|
|
739
|
-
readonly kind: SourceKind;
|
|
740
|
-
/** Resolved, boundary-checked absolute paths (when `kind` is `file`/`directory`). */
|
|
741
|
-
readonly paths: readonly string[];
|
|
742
|
-
/** Inputs that look like paths but do not resolve, or resolve outside the allowed roots. */
|
|
743
|
-
readonly missing: readonly string[];
|
|
744
|
-
/** Why the missing ones are missing (the boundary's own message; they differ per input). */
|
|
745
|
-
readonly reasons: readonly string[];
|
|
746
|
-
/** How many files a directory holds that ingestion would actually take. */
|
|
747
|
-
readonly files: number;
|
|
748
|
-
}
|
|
749
|
-
/** One row of a directory listing (the 选择 picker's `browseDir`). */
|
|
750
|
-
export interface BrowseEntry {
|
|
751
|
-
readonly name: string;
|
|
752
|
-
readonly path: string;
|
|
753
|
-
/** `dir` navigates; `ingestable` can be picked; `other` exists but ingestion would refuse it. */
|
|
754
|
-
readonly kind: 'dir' | 'ingestable' | 'other';
|
|
755
|
-
}
|
|
756
|
-
/**
|
|
757
|
-
* One directory as the browser picker sees it.
|
|
758
|
-
*
|
|
759
|
-
* Pinned to the engine's `browseDirectory` return BY the host Remote declaration, which annotates its
|
|
760
|
-
* payload with this interface: the two cannot drift without a type error. That check is the reason this
|
|
761
|
-
* shape is spelled here rather than mirrored in the browser half.
|
|
762
|
-
*/
|
|
763
|
-
export interface BrowseListing {
|
|
764
|
-
readonly path: string;
|
|
765
|
-
/** The parent directory, or `null` when this is an allowed root (or the filesystem root). */
|
|
766
|
-
readonly parent: string | null;
|
|
767
|
-
/** The configured roots — what the picker may walk when `unrestricted` is false. */
|
|
768
|
-
readonly roots: readonly string[];
|
|
769
|
-
/**
|
|
770
|
-
* `knowledge.ingest.allow_outside_workspace`: the whole filesystem is fair game, so `roots` is
|
|
771
|
-
* informational only and the UI must say "不限制" rather than show a boundary it does not honour.
|
|
772
|
-
*/
|
|
773
|
-
readonly unrestricted: boolean;
|
|
774
|
-
readonly entries: readonly BrowseEntry[];
|
|
775
|
-
}
|
|
776
|
-
/**
|
|
777
|
-
* The 知识页 domain picker's option list: the configured `knowledge.domains` allowlist ∪ the
|
|
778
|
-
* domains the library already holds, plus whether the allowlist is active.
|
|
779
|
-
*
|
|
780
|
-
* `restricted` mirrors "the allowlist is non-empty": then the control is a closed `<select>` and a
|
|
781
|
-
* new domain is a config change, not a second spelling of an existing one; an explicitly empty
|
|
782
|
-
* allowlist means no restriction, so the control stays a free input. The union half is not a
|
|
783
|
-
* compatibility layer — without it, narrowing the allowlist would make every existing document
|
|
784
|
-
* un-re-ingestable.
|
|
785
|
-
*
|
|
786
|
-
* It lives in the CONTRACT rather than being mirrored on both halves for the reason every UI payload
|
|
787
|
-
* here does: the host half declared it as an anonymous shape and the browser half hand-copied it,
|
|
788
|
-
* which is exactly how a field goes missing. `KnowledgeStore.domainCatalog()` / `addDomain()` (the
|
|
789
|
-
* real producers) and the picker (the real consumer) now name this one type.
|
|
790
|
-
*/
|
|
791
|
-
export interface DomainCatalog {
|
|
792
|
-
readonly domains: readonly string[];
|
|
793
|
-
readonly restricted: boolean;
|
|
794
|
-
}
|
|
795
|
-
/** Which of the two things a document row can open (`openDoc`). */
|
|
796
|
-
export type OpenTarget = 'file' | 'dir';
|
|
797
|
-
/**
|
|
798
|
-
* What `openDoc` launched, for the UI's status line.
|
|
799
|
-
*
|
|
800
|
-
* In the contract, not beside `openDocumentPath` (the host-side producer), for the same reason as
|
|
801
|
-
* {@link DomainCatalog}: the browser half cannot import that module — it pulls `node:child_process` —
|
|
802
|
-
* and used to hand-copy `{ path, opener }` (dropping `target`). The host Remote declaration annotates
|
|
803
|
-
* its payload with this interface, so producer and wire cannot drift without a type error.
|
|
804
|
-
*/
|
|
805
|
-
export interface OpenOutcome {
|
|
806
|
-
/** The managed path actually handed to the opener (the file, or the directory holding it). */
|
|
807
|
-
readonly path: string;
|
|
808
|
-
readonly target: OpenTarget;
|
|
809
|
-
/** The command that was actually used (`code`, `explorer.exe`, …). */
|
|
810
|
-
readonly opener: string;
|
|
811
|
-
}
|