@agentxm/knowledge-query 0.28.11 → 0.28.13
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/dist/src/corpus/corpus-status.d.ts +134 -0
- package/dist/src/corpus/corpus-status.js +74 -0
- package/dist/src/corpus/installed-corpus.d.ts +46 -0
- package/dist/src/corpus/installed-corpus.js +62 -0
- package/dist/src/documents.d.ts +349 -0
- package/dist/src/documents.js +168 -0
- package/dist/src/errors.d.ts +38 -0
- package/dist/src/errors.js +20 -0
- package/dist/src/index.d.ts +8 -1
- package/dist/src/index.js +9 -1
- package/dist/src/knowledge-capabilities.js +1 -1
- package/dist/src/knowledge-capture.js +1 -1
- package/dist/src/knowledge-discovery.d.ts +394 -0
- package/dist/src/knowledge-discovery.js +171 -0
- package/dist/src/knowledge-graph.js +5 -4
- package/dist/src/knowledge-index.d.ts +14 -1
- package/dist/src/knowledge-index.js +15 -1
- package/dist/src/knowledge-projection.d.ts +1 -1
- package/dist/src/lint/lint-knowledge.d.ts +47 -0
- package/dist/src/lint/lint-knowledge.js +61 -0
- package/dist/src/query/request.d.ts +58 -0
- package/dist/src/query/request.js +242 -0
- package/dist/src/testing.d.ts +46 -0
- package/dist/src/testing.js +139 -0
- package/package.json +13 -5
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only application API behind `axm knowledge concepts …`.
|
|
3
|
+
*
|
|
4
|
+
* Each operation takes a typed request, captures the selected installed
|
|
5
|
+
* corpus once, and returns the typed outcome document automation decodes.
|
|
6
|
+
* Grammar, bounds, conditional-revision semantics, readiness, and the ranking
|
|
7
|
+
* explanation are decided here; the application maps outcomes onto exit codes
|
|
8
|
+
* and rendering.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace-scope";
|
|
14
|
+
import { KnowledgeConceptNotFound, KnowledgeRequestInvalid } from "./errors.js";
|
|
15
|
+
import { KnowledgeIndex } from "./knowledge-index.js";
|
|
16
|
+
import { type KnowledgeQueryRequest, type KnowledgeSearchRequest } from "./query/request.js";
|
|
17
|
+
/** Every discovery operation reports the same two refusals it cannot recover from. */
|
|
18
|
+
export type KnowledgeDiscoveryOutcome<A> = {
|
|
19
|
+
readonly outcome: "corpus-changing";
|
|
20
|
+
} | {
|
|
21
|
+
readonly outcome: "cursor-expired";
|
|
22
|
+
} | ({
|
|
23
|
+
readonly outcome: "ready";
|
|
24
|
+
} & A);
|
|
25
|
+
export declare const KnowledgeDiscovery: {
|
|
26
|
+
/** Structured query over the installed corpus. */
|
|
27
|
+
query: (request: KnowledgeQueryRequest & {
|
|
28
|
+
readonly explain?: boolean;
|
|
29
|
+
}) => Effect.Effect<{
|
|
30
|
+
readonly outcome: "corpus-changing";
|
|
31
|
+
readonly page?: never;
|
|
32
|
+
} | {
|
|
33
|
+
readonly outcome: "cursor-expired";
|
|
34
|
+
readonly page?: never;
|
|
35
|
+
} | {
|
|
36
|
+
readonly outcome: "ready";
|
|
37
|
+
readonly page: {
|
|
38
|
+
readonly query: {
|
|
39
|
+
readonly version: "axm-knowledge-query-v1";
|
|
40
|
+
readonly scope: "project" | "user";
|
|
41
|
+
readonly clauses: readonly ({
|
|
42
|
+
readonly kind: "term";
|
|
43
|
+
readonly value: string;
|
|
44
|
+
} | {
|
|
45
|
+
readonly kind: "phrase";
|
|
46
|
+
readonly value: string;
|
|
47
|
+
} | {
|
|
48
|
+
readonly kind: "literal";
|
|
49
|
+
readonly value: string;
|
|
50
|
+
} | {
|
|
51
|
+
readonly kind: "field";
|
|
52
|
+
readonly field: "bundle" | "conceptId" | "title" | "description" | "tag" | "type" | "body" | "resource" | "status" | "staleAfter" | "generated" | "verified" | "trust";
|
|
53
|
+
readonly clause: {
|
|
54
|
+
readonly kind: "term";
|
|
55
|
+
readonly value: string;
|
|
56
|
+
} | {
|
|
57
|
+
readonly kind: "phrase";
|
|
58
|
+
readonly value: string;
|
|
59
|
+
} | {
|
|
60
|
+
readonly kind: "literal";
|
|
61
|
+
readonly value: string;
|
|
62
|
+
};
|
|
63
|
+
} | {
|
|
64
|
+
readonly kind: "metadata";
|
|
65
|
+
readonly field: "bundle" | "conceptId" | "title" | "description" | "tag" | "type" | "resource" | "kind";
|
|
66
|
+
readonly operator: "equals" | "not-equals" | "contains";
|
|
67
|
+
readonly value: string;
|
|
68
|
+
} | {
|
|
69
|
+
readonly kind: "lifecycle";
|
|
70
|
+
readonly field: "status" | "staleAfter" | "generated" | "verified" | "trust";
|
|
71
|
+
readonly operator: "equals" | "not-equals";
|
|
72
|
+
readonly value: string;
|
|
73
|
+
} | {
|
|
74
|
+
readonly kind: "property";
|
|
75
|
+
readonly pointer: string;
|
|
76
|
+
readonly operator: "equals" | "not-equals" | "contains";
|
|
77
|
+
readonly value: string;
|
|
78
|
+
})[];
|
|
79
|
+
readonly ordering: "metadata" | "relevance";
|
|
80
|
+
readonly resultLimit: number;
|
|
81
|
+
readonly passageLimit: number;
|
|
82
|
+
readonly passageLength: number;
|
|
83
|
+
readonly cursor?: string | undefined;
|
|
84
|
+
};
|
|
85
|
+
readonly items: readonly {
|
|
86
|
+
readonly kind: "concept" | "index" | "log";
|
|
87
|
+
readonly relativePath: string;
|
|
88
|
+
readonly matchedFields: readonly string[];
|
|
89
|
+
readonly passages: readonly {
|
|
90
|
+
readonly text: string;
|
|
91
|
+
readonly section: readonly string[];
|
|
92
|
+
readonly startLine: number;
|
|
93
|
+
readonly endLine: number;
|
|
94
|
+
readonly spans: readonly {
|
|
95
|
+
readonly clauseIndex: number;
|
|
96
|
+
readonly field: string;
|
|
97
|
+
readonly start: number;
|
|
98
|
+
readonly end: number;
|
|
99
|
+
}[];
|
|
100
|
+
}[];
|
|
101
|
+
readonly ref: {
|
|
102
|
+
readonly bundle: string;
|
|
103
|
+
readonly conceptId: string;
|
|
104
|
+
readonly bundleVersion: string;
|
|
105
|
+
readonly bundleFingerprint: string;
|
|
106
|
+
readonly contentRevision: string;
|
|
107
|
+
};
|
|
108
|
+
readonly orderingKey: string;
|
|
109
|
+
readonly title?: string | undefined;
|
|
110
|
+
readonly description?: string | undefined;
|
|
111
|
+
readonly status?: string | undefined;
|
|
112
|
+
readonly staleAfter?: string | undefined;
|
|
113
|
+
readonly generated?: {
|
|
114
|
+
readonly by: string;
|
|
115
|
+
readonly at?: string | undefined;
|
|
116
|
+
} | undefined;
|
|
117
|
+
readonly verified?: readonly {
|
|
118
|
+
readonly by: string;
|
|
119
|
+
readonly at?: string | undefined;
|
|
120
|
+
}[] | undefined;
|
|
121
|
+
readonly trust?: "unverified" | "machine-confirmed" | "human-reviewed" | undefined;
|
|
122
|
+
}[];
|
|
123
|
+
readonly count: number;
|
|
124
|
+
readonly hasMore: boolean;
|
|
125
|
+
readonly corpusFingerprint: string;
|
|
126
|
+
readonly cursor?: string | undefined;
|
|
127
|
+
readonly explanation?: {
|
|
128
|
+
readonly strategy: "lexical";
|
|
129
|
+
readonly ordering: "metadata" | "relevance";
|
|
130
|
+
readonly rankFactors: readonly {
|
|
131
|
+
readonly field: string;
|
|
132
|
+
readonly weight: number;
|
|
133
|
+
}[];
|
|
134
|
+
readonly tieBreak: string;
|
|
135
|
+
} | undefined;
|
|
136
|
+
};
|
|
137
|
+
}, KnowledgeRequestInvalid | import("./errors.js").KnowledgeCorpusUnavailable | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported, KnowledgeIndex | import("effect/FileSystem").FileSystem | import("effect/Path").Path | import("@agentxm/workspace-state").DesiredStateReader | import("@agentxm/workspace-state").WorkspaceLocation | import("@agentxm/workspace-state").LockfileReader>;
|
|
138
|
+
/** Lexical search over the installed corpus. */
|
|
139
|
+
search: (request: KnowledgeSearchRequest) => Effect.Effect<{
|
|
140
|
+
readonly outcome: "corpus-changing";
|
|
141
|
+
readonly page?: never;
|
|
142
|
+
} | {
|
|
143
|
+
readonly outcome: "cursor-expired";
|
|
144
|
+
readonly page?: never;
|
|
145
|
+
} | {
|
|
146
|
+
readonly outcome: "ready";
|
|
147
|
+
readonly page: {
|
|
148
|
+
readonly query: {
|
|
149
|
+
readonly version: "axm-knowledge-query-v1";
|
|
150
|
+
readonly scope: "project" | "user";
|
|
151
|
+
readonly clauses: readonly ({
|
|
152
|
+
readonly kind: "term";
|
|
153
|
+
readonly value: string;
|
|
154
|
+
} | {
|
|
155
|
+
readonly kind: "phrase";
|
|
156
|
+
readonly value: string;
|
|
157
|
+
} | {
|
|
158
|
+
readonly kind: "literal";
|
|
159
|
+
readonly value: string;
|
|
160
|
+
} | {
|
|
161
|
+
readonly kind: "field";
|
|
162
|
+
readonly field: "bundle" | "conceptId" | "title" | "description" | "tag" | "type" | "body" | "resource" | "status" | "staleAfter" | "generated" | "verified" | "trust";
|
|
163
|
+
readonly clause: {
|
|
164
|
+
readonly kind: "term";
|
|
165
|
+
readonly value: string;
|
|
166
|
+
} | {
|
|
167
|
+
readonly kind: "phrase";
|
|
168
|
+
readonly value: string;
|
|
169
|
+
} | {
|
|
170
|
+
readonly kind: "literal";
|
|
171
|
+
readonly value: string;
|
|
172
|
+
};
|
|
173
|
+
} | {
|
|
174
|
+
readonly kind: "metadata";
|
|
175
|
+
readonly field: "bundle" | "conceptId" | "title" | "description" | "tag" | "type" | "resource" | "kind";
|
|
176
|
+
readonly operator: "equals" | "not-equals" | "contains";
|
|
177
|
+
readonly value: string;
|
|
178
|
+
} | {
|
|
179
|
+
readonly kind: "lifecycle";
|
|
180
|
+
readonly field: "status" | "staleAfter" | "generated" | "verified" | "trust";
|
|
181
|
+
readonly operator: "equals" | "not-equals";
|
|
182
|
+
readonly value: string;
|
|
183
|
+
} | {
|
|
184
|
+
readonly kind: "property";
|
|
185
|
+
readonly pointer: string;
|
|
186
|
+
readonly operator: "equals" | "not-equals" | "contains";
|
|
187
|
+
readonly value: string;
|
|
188
|
+
})[];
|
|
189
|
+
readonly ordering: "metadata" | "relevance";
|
|
190
|
+
readonly resultLimit: number;
|
|
191
|
+
readonly passageLimit: number;
|
|
192
|
+
readonly passageLength: number;
|
|
193
|
+
readonly cursor?: string | undefined;
|
|
194
|
+
};
|
|
195
|
+
readonly items: readonly {
|
|
196
|
+
readonly kind: "concept" | "index" | "log";
|
|
197
|
+
readonly relativePath: string;
|
|
198
|
+
readonly matchedFields: readonly string[];
|
|
199
|
+
readonly passages: readonly {
|
|
200
|
+
readonly text: string;
|
|
201
|
+
readonly section: readonly string[];
|
|
202
|
+
readonly startLine: number;
|
|
203
|
+
readonly endLine: number;
|
|
204
|
+
readonly spans: readonly {
|
|
205
|
+
readonly clauseIndex: number;
|
|
206
|
+
readonly field: string;
|
|
207
|
+
readonly start: number;
|
|
208
|
+
readonly end: number;
|
|
209
|
+
}[];
|
|
210
|
+
}[];
|
|
211
|
+
readonly ref: {
|
|
212
|
+
readonly bundle: string;
|
|
213
|
+
readonly conceptId: string;
|
|
214
|
+
readonly bundleVersion: string;
|
|
215
|
+
readonly bundleFingerprint: string;
|
|
216
|
+
readonly contentRevision: string;
|
|
217
|
+
};
|
|
218
|
+
readonly orderingKey: string;
|
|
219
|
+
readonly title?: string | undefined;
|
|
220
|
+
readonly description?: string | undefined;
|
|
221
|
+
readonly status?: string | undefined;
|
|
222
|
+
readonly staleAfter?: string | undefined;
|
|
223
|
+
readonly generated?: {
|
|
224
|
+
readonly by: string;
|
|
225
|
+
readonly at?: string | undefined;
|
|
226
|
+
} | undefined;
|
|
227
|
+
readonly verified?: readonly {
|
|
228
|
+
readonly by: string;
|
|
229
|
+
readonly at?: string | undefined;
|
|
230
|
+
}[] | undefined;
|
|
231
|
+
readonly trust?: "unverified" | "machine-confirmed" | "human-reviewed" | undefined;
|
|
232
|
+
}[];
|
|
233
|
+
readonly count: number;
|
|
234
|
+
readonly hasMore: boolean;
|
|
235
|
+
readonly corpusFingerprint: string;
|
|
236
|
+
readonly cursor?: string | undefined;
|
|
237
|
+
readonly explanation?: {
|
|
238
|
+
readonly strategy: "lexical";
|
|
239
|
+
readonly ordering: "metadata" | "relevance";
|
|
240
|
+
readonly rankFactors: readonly {
|
|
241
|
+
readonly field: string;
|
|
242
|
+
readonly weight: number;
|
|
243
|
+
}[];
|
|
244
|
+
readonly tieBreak: string;
|
|
245
|
+
} | undefined;
|
|
246
|
+
};
|
|
247
|
+
}, KnowledgeRequestInvalid | import("./errors.js").KnowledgeCorpusUnavailable | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported, KnowledgeIndex | import("effect/FileSystem").FileSystem | import("effect/Path").Path | import("@agentxm/workspace-state").DesiredStateReader | import("@agentxm/workspace-state").WorkspaceLocation | import("@agentxm/workspace-state").LockfileReader>;
|
|
248
|
+
/**
|
|
249
|
+
* One concept by exact identity, optionally conditional on its content
|
|
250
|
+
* revision. A changed revision is a reported outcome, not a failure: the
|
|
251
|
+
* caller re-reads at the current revision.
|
|
252
|
+
*/
|
|
253
|
+
get: (request: {
|
|
254
|
+
readonly reference: string;
|
|
255
|
+
readonly ifRevision?: string;
|
|
256
|
+
readonly raw?: boolean;
|
|
257
|
+
}) => Effect.Effect<{
|
|
258
|
+
readonly outcome: "corpus-changing";
|
|
259
|
+
readonly document?: never;
|
|
260
|
+
} | {
|
|
261
|
+
readonly outcome: "revision-changed";
|
|
262
|
+
readonly document: {
|
|
263
|
+
outcome: "failed";
|
|
264
|
+
reason: "revision-changed";
|
|
265
|
+
ref: {
|
|
266
|
+
readonly bundle: string;
|
|
267
|
+
readonly conceptId: string;
|
|
268
|
+
readonly bundleVersion: string;
|
|
269
|
+
readonly bundleFingerprint: string;
|
|
270
|
+
readonly contentRevision: string;
|
|
271
|
+
};
|
|
272
|
+
expectedRevision: string;
|
|
273
|
+
currentRevision: string;
|
|
274
|
+
concept?: never;
|
|
275
|
+
};
|
|
276
|
+
} | {
|
|
277
|
+
readonly outcome: "ready";
|
|
278
|
+
readonly document: {
|
|
279
|
+
outcome: "found";
|
|
280
|
+
concept: {
|
|
281
|
+
readonly body: string;
|
|
282
|
+
readonly kind: "concept" | "index" | "log";
|
|
283
|
+
readonly relativePath: string;
|
|
284
|
+
readonly ref: {
|
|
285
|
+
readonly bundle: string;
|
|
286
|
+
readonly conceptId: string;
|
|
287
|
+
readonly bundleVersion: string;
|
|
288
|
+
readonly bundleFingerprint: string;
|
|
289
|
+
readonly contentRevision: string;
|
|
290
|
+
};
|
|
291
|
+
readonly projectionRevision: string;
|
|
292
|
+
readonly title?: string | undefined;
|
|
293
|
+
readonly description?: string | undefined;
|
|
294
|
+
readonly type?: string | undefined;
|
|
295
|
+
readonly resource?: string | undefined;
|
|
296
|
+
readonly status?: string | undefined;
|
|
297
|
+
readonly staleAfter?: string | undefined;
|
|
298
|
+
readonly generated?: {
|
|
299
|
+
readonly by: string;
|
|
300
|
+
readonly at?: string | undefined;
|
|
301
|
+
} | undefined;
|
|
302
|
+
readonly verified?: readonly {
|
|
303
|
+
readonly by: string;
|
|
304
|
+
readonly at?: string | undefined;
|
|
305
|
+
}[] | undefined;
|
|
306
|
+
readonly trust?: "unverified" | "machine-confirmed" | "human-reviewed" | undefined;
|
|
307
|
+
readonly tags?: readonly string[] | undefined;
|
|
308
|
+
readonly frontmatter?: {
|
|
309
|
+
readonly [x: string]: unknown;
|
|
310
|
+
} | undefined;
|
|
311
|
+
readonly raw?: string | undefined;
|
|
312
|
+
};
|
|
313
|
+
reason?: never;
|
|
314
|
+
ref?: never;
|
|
315
|
+
expectedRevision?: never;
|
|
316
|
+
currentRevision?: never;
|
|
317
|
+
};
|
|
318
|
+
}, KnowledgeRequestInvalid | import("./errors.js").KnowledgeCorpusUnavailable | KnowledgeConceptNotFound | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported, KnowledgeIndex | import("effect/FileSystem").FileSystem | import("effect/Path").Path | import("@agentxm/workspace-state").DesiredStateReader | import("@agentxm/workspace-state").WorkspaceLocation | import("@agentxm/workspace-state").LockfileReader>;
|
|
319
|
+
/**
|
|
320
|
+
* Resolve a reference to one installed concept. Fuzzy candidate matching is
|
|
321
|
+
* an explicit request; without it, only an exact reference resolves.
|
|
322
|
+
*/
|
|
323
|
+
resolve: (request: {
|
|
324
|
+
readonly input: string;
|
|
325
|
+
readonly fuzzy?: boolean;
|
|
326
|
+
}) => Effect.Effect<{
|
|
327
|
+
readonly outcome: "corpus-changing";
|
|
328
|
+
readonly document?: never;
|
|
329
|
+
} | {
|
|
330
|
+
readonly outcome: "not-found";
|
|
331
|
+
readonly document: {
|
|
332
|
+
outcome: "not-found";
|
|
333
|
+
};
|
|
334
|
+
} | {
|
|
335
|
+
readonly outcome: "resolved" | "ambiguous";
|
|
336
|
+
readonly document: {
|
|
337
|
+
readonly outcome: "not-found" | "resolved" | "ambiguous";
|
|
338
|
+
readonly reason?: "ambiguous-reference" | undefined;
|
|
339
|
+
readonly candidate?: {
|
|
340
|
+
readonly reason: "exact-reference" | "exact-concept-id" | "exact-title" | "token-match";
|
|
341
|
+
readonly ref: {
|
|
342
|
+
readonly bundle: string;
|
|
343
|
+
readonly conceptId: string;
|
|
344
|
+
readonly bundleVersion: string;
|
|
345
|
+
readonly bundleFingerprint: string;
|
|
346
|
+
readonly contentRevision: string;
|
|
347
|
+
};
|
|
348
|
+
readonly orderingKey: string;
|
|
349
|
+
readonly score: number;
|
|
350
|
+
readonly title?: string | undefined;
|
|
351
|
+
} | undefined;
|
|
352
|
+
readonly candidates?: readonly {
|
|
353
|
+
readonly reason: "exact-reference" | "exact-concept-id" | "exact-title" | "token-match";
|
|
354
|
+
readonly ref: {
|
|
355
|
+
readonly bundle: string;
|
|
356
|
+
readonly conceptId: string;
|
|
357
|
+
readonly bundleVersion: string;
|
|
358
|
+
readonly bundleFingerprint: string;
|
|
359
|
+
readonly contentRevision: string;
|
|
360
|
+
};
|
|
361
|
+
readonly orderingKey: string;
|
|
362
|
+
readonly score: number;
|
|
363
|
+
readonly title?: string | undefined;
|
|
364
|
+
}[] | undefined;
|
|
365
|
+
};
|
|
366
|
+
}, import("./errors.js").KnowledgeCorpusUnavailable | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported, KnowledgeIndex | import("effect/FileSystem").FileSystem | import("effect/Path").Path | import("@agentxm/workspace-state").DesiredStateReader | import("@agentxm/workspace-state").WorkspaceLocation | import("@agentxm/workspace-state").LockfileReader>;
|
|
367
|
+
/** Traverse authored links and derived backlinks from one concept. */
|
|
368
|
+
related: (request: {
|
|
369
|
+
readonly reference: string;
|
|
370
|
+
readonly maximumDepth?: number;
|
|
371
|
+
readonly includeIndexBacklinks?: boolean;
|
|
372
|
+
}) => Effect.Effect<{
|
|
373
|
+
readonly outcome: "corpus-changing";
|
|
374
|
+
readonly document?: never;
|
|
375
|
+
} | {
|
|
376
|
+
readonly outcome: "ready";
|
|
377
|
+
readonly document: {
|
|
378
|
+
ref: {
|
|
379
|
+
readonly bundle: string;
|
|
380
|
+
readonly conceptId: string;
|
|
381
|
+
readonly bundleVersion: string;
|
|
382
|
+
readonly bundleFingerprint: string;
|
|
383
|
+
readonly contentRevision: string;
|
|
384
|
+
};
|
|
385
|
+
maximumDepth: number;
|
|
386
|
+
includesIndexBacklinks: boolean;
|
|
387
|
+
items: readonly import("./knowledge-graph.js").KnowledgeRelatedConcept[];
|
|
388
|
+
count: number;
|
|
389
|
+
corpusFingerprint: string;
|
|
390
|
+
};
|
|
391
|
+
}, KnowledgeRequestInvalid | import("./errors.js").KnowledgeCorpusUnavailable | KnowledgeConceptNotFound | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").LockfileIoError | import("@agentxm/workspace-state").LockfileParseError | import("@agentxm/workspace-state").LockfileDecodeError | import("@agentxm/workspace-state").LockfileVersionUnsupported, KnowledgeIndex | import("effect/FileSystem").FileSystem | import("effect/Path").Path | import("@agentxm/workspace-state").DesiredStateReader | import("@agentxm/workspace-state").WorkspaceLocation | import("@agentxm/workspace-state").LockfileReader>;
|
|
392
|
+
};
|
|
393
|
+
export type { KnowledgeQueryRequest, KnowledgeSearchRequest, WorkspaceScope };
|
|
394
|
+
//# sourceMappingURL=knowledge-discovery.d.ts.map
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only application API behind `axm knowledge concepts …`.
|
|
3
|
+
*
|
|
4
|
+
* Each operation takes a typed request, captures the selected installed
|
|
5
|
+
* corpus once, and returns the typed outcome document automation decodes.
|
|
6
|
+
* Grammar, bounds, conditional-revision semantics, readiness, and the ranking
|
|
7
|
+
* explanation are decided here; the application maps outcomes onto exit codes
|
|
8
|
+
* and rendering.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Result from "effect/Result";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import { KnowledgeRevisionSchema, parseConceptRef, } from "@agentxm/extension-model/unstable/knowledge";
|
|
16
|
+
import { captureInstalledKnowledgeCorpus } from "./corpus/installed-corpus.js";
|
|
17
|
+
import { KnowledgeConceptNotFound, KnowledgeRequestInvalid } from "./errors.js";
|
|
18
|
+
import { KNOWLEDGE_DISCOVERY_CAPABILITIES } from "./knowledge-capabilities.js";
|
|
19
|
+
import { relatedKnowledgeConcepts, resolveKnowledgeConcept } from "./knowledge-graph.js";
|
|
20
|
+
import { getKnowledgeIndexConcept, KnowledgeIndex, } from "./knowledge-index.js";
|
|
21
|
+
import { checkTraversalDepth, explainKnowledgeQuery, makeKnowledgeQueryRequest, makeKnowledgeSearchRequest, } from "./query/request.js";
|
|
22
|
+
const decodeRevision = Schema.decodeUnknownResult(KnowledgeRevisionSchema);
|
|
23
|
+
const conceptDocument = (indexed, raw) => {
|
|
24
|
+
const source = indexed.source;
|
|
25
|
+
return {
|
|
26
|
+
ref: indexed.ref,
|
|
27
|
+
projectionRevision: indexed.projectionRevision,
|
|
28
|
+
kind: source.kind,
|
|
29
|
+
...(source.authoredTitle === undefined ? {} : { title: source.authoredTitle }),
|
|
30
|
+
...(source.type === undefined ? {} : { type: source.type }),
|
|
31
|
+
...(source.description === undefined ? {} : { description: source.description }),
|
|
32
|
+
...(source.tags === undefined ? {} : { tags: source.tags }),
|
|
33
|
+
...(source.resource === undefined ? {} : { resource: source.resource }),
|
|
34
|
+
...(source.status === undefined ? {} : { status: source.status }),
|
|
35
|
+
...(source.staleAfter === undefined ? {} : { staleAfter: source.staleAfter }),
|
|
36
|
+
...(source.generated === undefined ? {} : { generated: source.generated }),
|
|
37
|
+
...(source.verified === undefined ? {} : { verified: source.verified }),
|
|
38
|
+
...(source.trust === undefined ? {} : { trust: source.trust }),
|
|
39
|
+
...(source.frontmatter === undefined ? {} : { frontmatter: source.frontmatter }),
|
|
40
|
+
relativePath: source.relativePath,
|
|
41
|
+
body: source.body,
|
|
42
|
+
...(raw ? { raw: new TextDecoder().decode(indexed.sourceBytes) } : {}),
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const runPage = Effect.fn("Knowledge.runPage")(function* (args) {
|
|
46
|
+
const index = yield* KnowledgeIndex;
|
|
47
|
+
const captured = yield* captureInstalledKnowledgeCorpus(args.bundle === undefined ? undefined : { bundle: args.bundle });
|
|
48
|
+
if (captured.outcome === "corpus-changing") {
|
|
49
|
+
return { outcome: "corpus-changing" };
|
|
50
|
+
}
|
|
51
|
+
const pageResult = yield* Effect.result(index.query(captured.snapshot, args.query));
|
|
52
|
+
if (!Result.isSuccess(pageResult))
|
|
53
|
+
return { outcome: "cursor-expired" };
|
|
54
|
+
const page = {
|
|
55
|
+
query: args.query,
|
|
56
|
+
corpusFingerprint: captured.snapshot.fingerprint,
|
|
57
|
+
...pageResult.success,
|
|
58
|
+
...(args.explain ? { explanation: explainKnowledgeQuery(args.query) } : {}),
|
|
59
|
+
};
|
|
60
|
+
return { outcome: "ready", page };
|
|
61
|
+
});
|
|
62
|
+
export const KnowledgeDiscovery = {
|
|
63
|
+
/** Structured query over the installed corpus. */
|
|
64
|
+
query: Effect.fn("KnowledgeDiscovery.query")(function* (request) {
|
|
65
|
+
const query = yield* makeKnowledgeQueryRequest(request);
|
|
66
|
+
return yield* runPage({ query, explain: request.explain === true });
|
|
67
|
+
}),
|
|
68
|
+
/** Lexical search over the installed corpus. */
|
|
69
|
+
search: Effect.fn("KnowledgeDiscovery.search")(function* (request) {
|
|
70
|
+
const query = yield* makeKnowledgeSearchRequest(request);
|
|
71
|
+
return yield* runPage({ query, explain: false });
|
|
72
|
+
}),
|
|
73
|
+
/**
|
|
74
|
+
* One concept by exact identity, optionally conditional on its content
|
|
75
|
+
* revision. A changed revision is a reported outcome, not a failure: the
|
|
76
|
+
* caller re-reads at the current revision.
|
|
77
|
+
*/
|
|
78
|
+
get: Effect.fn("KnowledgeDiscovery.get")(function* (request) {
|
|
79
|
+
const parsed = parseConceptRef(request.reference);
|
|
80
|
+
if (!Result.isSuccess(parsed)) {
|
|
81
|
+
return yield* new KnowledgeRequestInvalid({
|
|
82
|
+
detail: "Expected a concept reference in @owner/knowledge/name#concept-id form",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const expected = request.ifRevision === undefined ? undefined : decodeRevision(request.ifRevision);
|
|
86
|
+
if (expected !== undefined && !Result.isSuccess(expected)) {
|
|
87
|
+
return yield* new KnowledgeRequestInvalid({
|
|
88
|
+
detail: "--if-revision must be an opaque sha256: revision",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const captured = yield* captureInstalledKnowledgeCorpus();
|
|
92
|
+
if (captured.outcome === "corpus-changing")
|
|
93
|
+
return { outcome: "corpus-changing" };
|
|
94
|
+
const indexed = getKnowledgeIndexConcept(captured.snapshot, parsed.success.bundle, parsed.success.conceptId);
|
|
95
|
+
if (indexed === undefined) {
|
|
96
|
+
return yield* new KnowledgeConceptNotFound({ reference: request.reference });
|
|
97
|
+
}
|
|
98
|
+
if (expected !== undefined &&
|
|
99
|
+
Result.isSuccess(expected) &&
|
|
100
|
+
expected.success !== indexed.ref.contentRevision) {
|
|
101
|
+
return {
|
|
102
|
+
outcome: "revision-changed",
|
|
103
|
+
document: {
|
|
104
|
+
outcome: "failed",
|
|
105
|
+
reason: "revision-changed",
|
|
106
|
+
ref: indexed.ref,
|
|
107
|
+
expectedRevision: expected.success,
|
|
108
|
+
currentRevision: indexed.ref.contentRevision,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
outcome: "ready",
|
|
114
|
+
document: {
|
|
115
|
+
outcome: "found",
|
|
116
|
+
concept: conceptDocument(indexed, request.raw === true),
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}),
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a reference to one installed concept. Fuzzy candidate matching is
|
|
122
|
+
* an explicit request; without it, only an exact reference resolves.
|
|
123
|
+
*/
|
|
124
|
+
resolve: Effect.fn("KnowledgeDiscovery.resolve")(function* (request) {
|
|
125
|
+
const captured = yield* captureInstalledKnowledgeCorpus();
|
|
126
|
+
if (captured.outcome === "corpus-changing")
|
|
127
|
+
return { outcome: "corpus-changing" };
|
|
128
|
+
const resolved = resolveKnowledgeConcept(captured.snapshot, request.input, KNOWLEDGE_DISCOVERY_CAPABILITIES.limits.maximumFuzzyCandidates, request.fuzzy === true);
|
|
129
|
+
if (resolved.outcome === "not-found") {
|
|
130
|
+
return {
|
|
131
|
+
outcome: "not-found",
|
|
132
|
+
document: { outcome: "not-found" },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const document = resolved.outcome === "ambiguous" ? { ...resolved, reason: "ambiguous-reference" } : resolved;
|
|
136
|
+
return { outcome: resolved.outcome, document };
|
|
137
|
+
}),
|
|
138
|
+
/** Traverse authored links and derived backlinks from one concept. */
|
|
139
|
+
related: Effect.fn("KnowledgeDiscovery.related")(function* (request) {
|
|
140
|
+
const parsed = parseConceptRef(request.reference);
|
|
141
|
+
if (!Result.isSuccess(parsed)) {
|
|
142
|
+
return yield* new KnowledgeRequestInvalid({
|
|
143
|
+
detail: "Expected a concept reference in @owner/knowledge/name#concept-id form",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const maximumDepth = yield* checkTraversalDepth(request.maximumDepth ?? 1);
|
|
147
|
+
const captured = yield* captureInstalledKnowledgeCorpus();
|
|
148
|
+
if (captured.outcome === "corpus-changing")
|
|
149
|
+
return { outcome: "corpus-changing" };
|
|
150
|
+
const root = getKnowledgeIndexConcept(captured.snapshot, parsed.success.bundle, parsed.success.conceptId);
|
|
151
|
+
if (root === undefined) {
|
|
152
|
+
return yield* new KnowledgeConceptNotFound({ reference: request.reference });
|
|
153
|
+
}
|
|
154
|
+
const includesIndexBacklinks = request.includeIndexBacklinks === true;
|
|
155
|
+
const items = relatedKnowledgeConcepts(captured.snapshot, parsed.success, maximumDepth, {
|
|
156
|
+
includeIndexBacklinks: includesIndexBacklinks,
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
outcome: "ready",
|
|
160
|
+
document: {
|
|
161
|
+
ref: root.ref,
|
|
162
|
+
maximumDepth,
|
|
163
|
+
includesIndexBacklinks,
|
|
164
|
+
items,
|
|
165
|
+
count: items.length,
|
|
166
|
+
corpusFingerprint: captured.snapshot.fingerprint,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}),
|
|
170
|
+
};
|
|
171
|
+
//# sourceMappingURL=knowledge-discovery.js.map
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as Result from "effect/Result";
|
|
2
2
|
import { parseConceptRef, } from "@agentxm/extension-model/unstable/knowledge/concept-ref";
|
|
3
3
|
import { getKnowledgeIndexConcept, } from "./knowledge-index.js";
|
|
4
|
-
import { tokenizeKnowledgeSearchText } from "@agentxm/
|
|
4
|
+
import { tokenizeKnowledgeSearchText } from "@agentxm/extension-content/knowledge";
|
|
5
|
+
import { KNOWLEDGE_DISCOVERY_CAPABILITIES } from "./knowledge-capabilities.js";
|
|
5
6
|
const compactKey = (ref) => `${ref.bundle}#${ref.conceptId}`;
|
|
6
7
|
/** Traverse authored outgoing links and derived backlinks with cycle suppression. */
|
|
7
8
|
export const relatedKnowledgeConcepts = (snapshot, start, maximumDepth = 1, options) => {
|
|
8
9
|
const root = getKnowledgeIndexConcept(snapshot, start.bundle, start.conceptId);
|
|
9
10
|
if (root === undefined)
|
|
10
11
|
return [];
|
|
11
|
-
const depthLimit = Math.max(1, Math.min(
|
|
12
|
+
const depthLimit = Math.max(1, Math.min(KNOWLEDGE_DISCOVERY_CAPABILITIES.limits.maximumTraversalDepth, maximumDepth));
|
|
12
13
|
const visited = new Set([compactKey(start)]);
|
|
13
14
|
const queue = [{ concept: root, depth: 0 }];
|
|
14
15
|
const results = [];
|
|
@@ -88,7 +89,7 @@ const candidate = (concept, reason, score) => ({
|
|
|
88
89
|
orderingKey: `${concept.ref.bundle}#${concept.ref.conceptId}`,
|
|
89
90
|
});
|
|
90
91
|
/** Resolve an exact concept ref or return a bounded deterministic fuzzy candidate set. */
|
|
91
|
-
export const resolveKnowledgeConcept = (snapshot, input, maximumCandidates =
|
|
92
|
+
export const resolveKnowledgeConcept = (snapshot, input, maximumCandidates = KNOWLEDGE_DISCOVERY_CAPABILITIES.limits.maximumFuzzyCandidates, fuzzy = false) => {
|
|
92
93
|
const parsed = parseConceptRef(input);
|
|
93
94
|
if (Result.isSuccess(parsed)) {
|
|
94
95
|
const exact = getKnowledgeIndexConcept(snapshot, parsed.success.bundle, parsed.success.conceptId);
|
|
@@ -116,7 +117,7 @@ export const resolveKnowledgeConcept = (snapshot, input, maximumCandidates = 10,
|
|
|
116
117
|
return [];
|
|
117
118
|
})
|
|
118
119
|
.sort((left, right) => right.score - left.score || left.orderingKey.localeCompare(right.orderingKey))
|
|
119
|
-
.slice(0, Math.max(1,
|
|
120
|
+
.slice(0, Math.max(1, maximumCandidates));
|
|
120
121
|
if (candidates.length === 0)
|
|
121
122
|
return { outcome: "not-found", candidates: [] };
|
|
122
123
|
if (candidates.length === 1) {
|
|
@@ -5,7 +5,7 @@ import { type KnowledgeBundleFqn, type KnowledgeRevision, type ResolvedConceptRe
|
|
|
5
5
|
import { type KnowledgeBodyPassage, type KnowledgeProjectedConcept, type KnowledgeSearchableField } from "./knowledge-projection.js";
|
|
6
6
|
import { type KnowledgeQuery } from "./knowledge-query.js";
|
|
7
7
|
import { type CapturedKnowledgeSource } from "./knowledge-revision.js";
|
|
8
|
-
import type { KnowledgeConcept, KnowledgeInspection } from "@agentxm/
|
|
8
|
+
import type { KnowledgeConcept, KnowledgeInspection } from "@agentxm/extension-content/knowledge";
|
|
9
9
|
export interface KnowledgeIndexBundleInput {
|
|
10
10
|
readonly bundle: KnowledgeBundleFqn;
|
|
11
11
|
readonly version: string;
|
|
@@ -62,6 +62,19 @@ export declare class KnowledgeCursorInvalidError extends KnowledgeCursorInvalidE
|
|
|
62
62
|
}> {
|
|
63
63
|
}
|
|
64
64
|
export declare const makeKnowledgeIndexSnapshot: (bundles: ReadonlyArray<KnowledgeIndexBundleInput>) => KnowledgeIndexSnapshot;
|
|
65
|
+
/** One ranking factor of the lexical strategy, derived from the same weights the ranker uses. */
|
|
66
|
+
export interface KnowledgeRankFactor {
|
|
67
|
+
readonly field: string;
|
|
68
|
+
readonly weight: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The published ranking explanation: the fields the lexical strategy weights,
|
|
72
|
+
* highest first, and the catch-all weight every other field carries. Derived
|
|
73
|
+
* from `fieldWeight`, so an explanation can never drift from the ranking.
|
|
74
|
+
*/
|
|
75
|
+
export declare const KNOWLEDGE_RANK_FACTORS: ReadonlyArray<KnowledgeRankFactor>;
|
|
76
|
+
/** How the lexical strategy orders results that rank equally. */
|
|
77
|
+
export declare const KNOWLEDGE_RANK_TIE_BREAK = "bundle FQN, then concept ID";
|
|
65
78
|
export declare const queryKnowledgeIndexResult: (snapshot: KnowledgeIndexSnapshot, query: KnowledgeQuery, now: number) => Result.Result<KnowledgeQueryPage, KnowledgeCursorInvalidError>;
|
|
66
79
|
export declare const queryKnowledgeIndex: (snapshot: KnowledgeIndexSnapshot, query: KnowledgeQuery, now: number) => KnowledgeQueryPage;
|
|
67
80
|
export declare const getKnowledgeIndexConcept: (snapshot: KnowledgeIndexSnapshot, bundle: string, conceptId: string) => KnowledgeIndexedConcept | undefined;
|
|
@@ -8,7 +8,7 @@ import { resolveKnowledgeFrontmatterPointer } from "./knowledge-projection.js";
|
|
|
8
8
|
import { projectKnowledgeConcepts, } from "./knowledge-projection.js";
|
|
9
9
|
import { knowledgeQueryIdentity, } from "./knowledge-query.js";
|
|
10
10
|
import { computeKnowledgeCorpusFingerprint, computeKnowledgeProjectionRevision, } from "./knowledge-revision.js";
|
|
11
|
-
import { tokenizeKnowledgeSearchText } from "@agentxm/
|
|
11
|
+
import { tokenizeKnowledgeSearchText } from "@agentxm/extension-content/knowledge";
|
|
12
12
|
export class KnowledgeCursorInvalidError extends Data.TaggedError("KnowledgeCursorInvalidError") {
|
|
13
13
|
}
|
|
14
14
|
const CURSOR_VERSION = "axm-knowledge-cursor-v1";
|
|
@@ -219,6 +219,20 @@ const fieldWeight = (field) => {
|
|
|
219
219
|
return 1;
|
|
220
220
|
}
|
|
221
221
|
};
|
|
222
|
+
/**
|
|
223
|
+
* The published ranking explanation: the fields the lexical strategy weights,
|
|
224
|
+
* highest first, and the catch-all weight every other field carries. Derived
|
|
225
|
+
* from `fieldWeight`, so an explanation can never drift from the ranking.
|
|
226
|
+
*/
|
|
227
|
+
export const KNOWLEDGE_RANK_FACTORS = [
|
|
228
|
+
...["title", "conceptId", "tag", "description", "type", "body"].map((field) => ({
|
|
229
|
+
field,
|
|
230
|
+
weight: fieldWeight(field),
|
|
231
|
+
})),
|
|
232
|
+
{ field: "other", weight: fieldWeight("bundle") },
|
|
233
|
+
];
|
|
234
|
+
/** How the lexical strategy orders results that rank equally. */
|
|
235
|
+
export const KNOWLEDGE_RANK_TIE_BREAK = "bundle FQN, then concept ID";
|
|
222
236
|
const locateTokenSequence = (text, tokens) => {
|
|
223
237
|
if (tokens.length === 0)
|
|
224
238
|
return undefined;
|