@fortemi/core 2026.6.8 → 2026.7.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 +49 -0
- package/dist/aiwg-index.d.ts +99 -4
- package/dist/aiwg-index.js +345 -15
- package/dist/aiwg-index.js.map +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.js +357 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -178,6 +178,55 @@ Unfiltered browse requests fetch only the part files intersecting the requested
|
|
|
178
178
|
results, but the controller keeps only a bounded part cache and never sets a
|
|
179
179
|
materialized full export in `getIndex()`.
|
|
180
180
|
|
|
181
|
+
AIWG records can use project-specific string types such as `aiwg.skill`,
|
|
182
|
+
`aiwg.command`, `aiwg.rule`, `aiwg.requirement`, and `research.ref`. Validation
|
|
183
|
+
still enforces required record fields, but it does not require unknown AIWG,
|
|
184
|
+
research, or documentation domains to collapse into `aiwg.artifact`.
|
|
185
|
+
|
|
186
|
+
For AIWG command-palette parity, opt into discovery ranking instead of the
|
|
187
|
+
default deterministic substring lookup:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const ranked = controller.query('address the open issues', {
|
|
191
|
+
searchProfile: 'aiwg-discovery',
|
|
192
|
+
rank: true,
|
|
193
|
+
includeMatches: true,
|
|
194
|
+
})
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The discovery profile normalizes hyphen/space variants, strips common stopwords,
|
|
198
|
+
boosts trigger and capability facets, and returns match reasons for UI debugging.
|
|
199
|
+
|
|
200
|
+
Chunked indexes also support graph navigation without loading a full export:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
const neighbors = await controller.neighbors('aiwg:requirement:search', {
|
|
204
|
+
direction: 'both',
|
|
205
|
+
relationshipType: 'cites',
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const graph = await controller.toCommunityGraphChunked()
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
When scan parts are projected, relationship traversal scans the parts and
|
|
212
|
+
lazy-loads detail records only when relationships are not present in the scan
|
|
213
|
+
projection.
|
|
214
|
+
|
|
215
|
+
Static semantic search uses an optional sidecar contract:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { queryAiwgHybridIndex } from '@fortemi/core/aiwg-index'
|
|
219
|
+
|
|
220
|
+
const embeddingSet = await fetch('/search/aiwg-index/embeddings.json').then((res) => res.json())
|
|
221
|
+
const queryEmbedding = await hostEmbed('workspace health check')
|
|
222
|
+
const semanticResults = queryAiwgHybridIndex(index, embeddingSet, 'health check', queryEmbedding)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`aiwg.fortemi.embedding.set.v1` records the model, dimensions, granularity
|
|
226
|
+
(`title-summary`, `body`, `chunked-body`, or a project value), source record IDs,
|
|
227
|
+
and per-vector input hashes. Hosts provide query embeddings; `@fortemi/core` does
|
|
228
|
+
not add a model runtime dependency for static AIWG search.
|
|
229
|
+
|
|
181
230
|
## What You Get
|
|
182
231
|
|
|
183
232
|
| Surface | Description |
|
package/dist/aiwg-index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
type
|
|
1
|
+
type AiwgFortemiKnownRecordType = 'crm.contact' | 'crm.organization' | 'crm.event' | 'crm.interaction' | 'aiwg.artifact' | 'docs.page';
|
|
2
|
+
type AiwgFortemiRecordType = AiwgFortemiKnownRecordType | `aiwg.${string}` | `research.${string}` | `docs.${string}` | string;
|
|
2
3
|
type AiwgPrivacyClassification = 'private' | 'sanitized' | 'public';
|
|
3
4
|
type AiwgProvenanceConfidence = 'source' | 'candidate' | 'reviewed' | 'rejected';
|
|
4
5
|
type AiwgReviewAction = 'accept' | 'reject' | 'defer';
|
|
@@ -118,7 +119,7 @@ interface AiwgFortemiChunkPart {
|
|
|
118
119
|
interface AiwgIndexValidationResult {
|
|
119
120
|
valid: boolean;
|
|
120
121
|
errors: string[];
|
|
121
|
-
counts: Partial<Record<
|
|
122
|
+
counts: Partial<Record<string, number>>;
|
|
122
123
|
}
|
|
123
124
|
interface AiwgChunkedIndexValidationResult {
|
|
124
125
|
valid: boolean;
|
|
@@ -138,16 +139,22 @@ interface AiwgIndexQueryOptions {
|
|
|
138
139
|
snippetLength?: number;
|
|
139
140
|
weights?: Partial<AiwgIndexQueryWeights>;
|
|
140
141
|
includeMatches?: boolean;
|
|
142
|
+
searchProfile?: 'default' | 'aiwg-discovery';
|
|
141
143
|
}
|
|
142
144
|
interface AiwgIndexQueryWeights {
|
|
143
145
|
title: number;
|
|
144
146
|
text: number;
|
|
145
147
|
tag: number;
|
|
146
148
|
concept: number;
|
|
149
|
+
facet: number;
|
|
150
|
+
id: number;
|
|
151
|
+
source: number;
|
|
147
152
|
}
|
|
148
153
|
interface AiwgIndexQueryMatch {
|
|
149
|
-
field: 'title' | 'text' | 'tag' | 'concept';
|
|
154
|
+
field: 'title' | 'text' | 'tag' | 'concept' | 'facet' | 'id' | 'source';
|
|
150
155
|
value: string;
|
|
156
|
+
score?: number;
|
|
157
|
+
reason?: string;
|
|
151
158
|
}
|
|
152
159
|
interface AiwgIndexQueryRankedItem {
|
|
153
160
|
item: AiwgFortemiRecord;
|
|
@@ -203,6 +210,83 @@ interface AiwgIndexGraphOptions {
|
|
|
203
210
|
relationshipWeights?: Record<string, number>;
|
|
204
211
|
includeDanglingRelationships?: boolean;
|
|
205
212
|
}
|
|
213
|
+
type AiwgRelationshipDirection = 'in' | 'out' | 'both';
|
|
214
|
+
type AiwgRelationshipSetOperation = 'intersection' | 'union' | 'difference';
|
|
215
|
+
interface AiwgRelationshipTraversalOptions {
|
|
216
|
+
direction?: AiwgRelationshipDirection;
|
|
217
|
+
relationshipType?: string;
|
|
218
|
+
limit?: number;
|
|
219
|
+
}
|
|
220
|
+
interface AiwgRelationshipQueryOptions extends AiwgRelationshipTraversalOptions {
|
|
221
|
+
sourceId?: string;
|
|
222
|
+
targetId?: string;
|
|
223
|
+
type?: string;
|
|
224
|
+
}
|
|
225
|
+
interface AiwgRelationshipEdgeSummary {
|
|
226
|
+
source_id: string;
|
|
227
|
+
target_id: string;
|
|
228
|
+
type: string;
|
|
229
|
+
source_path?: string;
|
|
230
|
+
}
|
|
231
|
+
interface AiwgRelationshipNodeSummary {
|
|
232
|
+
id: string;
|
|
233
|
+
type: AiwgFortemiRecordType;
|
|
234
|
+
title: string;
|
|
235
|
+
}
|
|
236
|
+
interface AiwgRelationshipTraversalResult {
|
|
237
|
+
nodes: AiwgRelationshipNodeSummary[];
|
|
238
|
+
edges: AiwgRelationshipEdgeSummary[];
|
|
239
|
+
complete: boolean;
|
|
240
|
+
scannedParts?: number;
|
|
241
|
+
fetchedParts?: number;
|
|
242
|
+
}
|
|
243
|
+
interface AiwgRelationshipSetOptions extends AiwgRelationshipTraversalOptions {
|
|
244
|
+
op: AiwgRelationshipSetOperation;
|
|
245
|
+
a: string;
|
|
246
|
+
b: string;
|
|
247
|
+
}
|
|
248
|
+
interface AiwgRelationshipSetResult {
|
|
249
|
+
ids: string[];
|
|
250
|
+
op: AiwgRelationshipSetOperation;
|
|
251
|
+
}
|
|
252
|
+
interface AiwgStaticEmbeddingRecord {
|
|
253
|
+
record_id: string;
|
|
254
|
+
embedding: number[];
|
|
255
|
+
embedding_id?: string;
|
|
256
|
+
granularity?: string;
|
|
257
|
+
input_hash: string;
|
|
258
|
+
source_path?: string;
|
|
259
|
+
}
|
|
260
|
+
interface AiwgStaticEmbeddingSet {
|
|
261
|
+
schema_version: 'aiwg.fortemi.embedding.set.v1';
|
|
262
|
+
id: string;
|
|
263
|
+
model: string;
|
|
264
|
+
dimensions: number;
|
|
265
|
+
generated_at: string;
|
|
266
|
+
granularity: 'title-summary' | 'body' | 'chunked-body' | string;
|
|
267
|
+
metric?: 'cosine' | 'dot' | 'euclidean';
|
|
268
|
+
input_hash_algorithm?: string;
|
|
269
|
+
embeddings: AiwgStaticEmbeddingRecord[];
|
|
270
|
+
}
|
|
271
|
+
interface AiwgStaticSemanticQueryOptions {
|
|
272
|
+
limit?: number;
|
|
273
|
+
offset?: number;
|
|
274
|
+
minScore?: number;
|
|
275
|
+
}
|
|
276
|
+
interface AiwgStaticSemanticResult {
|
|
277
|
+
item: AiwgFortemiRecord;
|
|
278
|
+
score: number;
|
|
279
|
+
embedding?: AiwgStaticEmbeddingRecord;
|
|
280
|
+
}
|
|
281
|
+
interface AiwgStaticHybridQueryOptions extends AiwgStaticSemanticQueryOptions, AiwgIndexQueryOptions {
|
|
282
|
+
lexicalWeight?: number;
|
|
283
|
+
semanticWeight?: number;
|
|
284
|
+
}
|
|
285
|
+
interface AiwgStaticDuplicatePair {
|
|
286
|
+
left: AiwgFortemiRecord;
|
|
287
|
+
right: AiwgFortemiRecord;
|
|
288
|
+
score: number;
|
|
289
|
+
}
|
|
206
290
|
interface AiwgReviewInput {
|
|
207
291
|
item_id: string;
|
|
208
292
|
action: AiwgReviewAction;
|
|
@@ -229,8 +313,14 @@ interface AiwgIndexController {
|
|
|
229
313
|
query(query?: string, options?: AiwgIndexQueryOptions): AiwgIndexQueryResult;
|
|
230
314
|
queryChunked(query?: string, options?: AiwgChunkedIndexQueryOptions): Promise<AiwgChunkedIndexQueryResult>;
|
|
231
315
|
getRecord(id: string): Promise<AiwgFortemiRecord>;
|
|
316
|
+
neighbors(id: string, options?: AiwgRelationshipTraversalOptions): Promise<AiwgRelationshipTraversalResult>;
|
|
317
|
+
relationshipQuery(options?: AiwgRelationshipQueryOptions): Promise<AiwgRelationshipTraversalResult>;
|
|
318
|
+
relationshipSet(options: AiwgRelationshipSetOptions): Promise<AiwgRelationshipSetResult>;
|
|
232
319
|
clearChunkCache(): void;
|
|
233
320
|
toCommunityGraph(options?: AiwgIndexGraphOptions): ReturnType<typeof aiwgFortemiIndexToCommunityGraph>;
|
|
321
|
+
toCommunityGraphChunked(options?: AiwgIndexGraphOptions & {
|
|
322
|
+
onProgress?: (progress: AiwgChunkedIndexProgress) => void;
|
|
323
|
+
}): Promise<ReturnType<typeof aiwgFortemiIndexToCommunityGraph>>;
|
|
234
324
|
setReviewDecision(input: AiwgReviewInput): AiwgReviewDecision;
|
|
235
325
|
clearReviewDecision(itemId: string): void;
|
|
236
326
|
createReviewDecisionExport(generatedAt?: string): AiwgReviewDecisionExport;
|
|
@@ -268,6 +358,11 @@ interface AiwgChunkedIndexBuildResult {
|
|
|
268
358
|
}
|
|
269
359
|
declare function buildAiwgChunkedIndex(index: AiwgFortemiIndexExport, options?: AiwgChunkedIndexBuildOptions): AiwgChunkedIndexBuildResult;
|
|
270
360
|
declare function queryAiwgFortemiIndex(index: AiwgFortemiIndexExport, query?: string, options?: AiwgIndexQueryOptions): AiwgIndexQueryResult;
|
|
361
|
+
declare function validateAiwgStaticEmbeddingSet(value: unknown): AiwgChunkedIndexValidationResult;
|
|
362
|
+
declare function assertAiwgStaticEmbeddingSet(value: unknown): AiwgStaticEmbeddingSet;
|
|
363
|
+
declare function queryAiwgSemanticIndex(index: AiwgFortemiIndexExport, embeddingSet: AiwgStaticEmbeddingSet, queryEmbedding: number[], options?: AiwgStaticSemanticQueryOptions): AiwgStaticSemanticResult[];
|
|
364
|
+
declare function queryAiwgHybridIndex(index: AiwgFortemiIndexExport, embeddingSet: AiwgStaticEmbeddingSet, query: string, queryEmbedding: number[], options?: AiwgStaticHybridQueryOptions): AiwgStaticSemanticResult[];
|
|
365
|
+
declare function findAiwgStaticDuplicatePairs(index: AiwgFortemiIndexExport, embeddingSet: AiwgStaticEmbeddingSet, threshold?: number): AiwgStaticDuplicatePair[];
|
|
271
366
|
declare function createAiwgReviewDecisionExport(source: Pick<AiwgFortemiIndexExport, 'schema_version'>, decisions: AiwgReviewDecision[], generatedAt?: string): AiwgReviewDecisionExport;
|
|
272
367
|
declare function createAiwgIndexController(initialIndex?: AiwgFortemiIndexExport): AiwgIndexController;
|
|
273
368
|
declare function aiwgFortemiIndexToCommunityGraph(index: AiwgFortemiIndexExport, options?: AiwgIndexGraphOptions): {
|
|
@@ -286,4 +381,4 @@ declare function aiwgFortemiIndexToCommunityGraph(index: AiwgFortemiIndexExport,
|
|
|
286
381
|
}[];
|
|
287
382
|
};
|
|
288
383
|
|
|
289
|
-
export { AIWG_SCAN_REQUIRED_FIELDS, type AiwgChunkedIndexBuildOptions, type AiwgChunkedIndexBuildResult, type AiwgChunkedIndexDetailLoader, type AiwgChunkedIndexLoadOptions, type AiwgChunkedIndexLoader, type AiwgChunkedIndexProgress, type AiwgChunkedIndexProgressPhase, type AiwgChunkedIndexQueryOptions, type AiwgChunkedIndexQueryResult, type AiwgChunkedIndexValidationResult, type AiwgDetailIdEncoding, type AiwgFortemiChunkDetailRef, type AiwgFortemiChunkManifest, type AiwgFortemiChunkPart, type AiwgFortemiChunkPartRef, type AiwgFortemiIndexExport, type AiwgFortemiProjectedRecord, type AiwgFortemiProvenance, type AiwgFortemiProvenanceEvent, type AiwgFortemiRecord, type AiwgFortemiRecordSource, type AiwgFortemiRecordType, type AiwgFortemiRelationship, type AiwgFortemiSkosConcept, type AiwgFortemiSkosRelation, type AiwgFortemiSkosRelationType, type AiwgIndexController, type AiwgIndexControllerListener, type AiwgIndexControllerSnapshot, type AiwgIndexGraphOptions, type AiwgIndexQueryMatch, type AiwgIndexQueryOptions, type AiwgIndexQueryRankedItem, type AiwgIndexQueryResult, type AiwgIndexQueryWeights, type AiwgIndexValidationResult, type AiwgPrivacyClassification, type AiwgProvenanceConfidence, type AiwgReviewAction, type AiwgReviewDecision, type AiwgReviewDecisionExport, type AiwgReviewInput, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, getAiwgFortemiFacets, queryAiwgFortemiIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport };
|
|
384
|
+
export { AIWG_SCAN_REQUIRED_FIELDS, type AiwgChunkedIndexBuildOptions, type AiwgChunkedIndexBuildResult, type AiwgChunkedIndexDetailLoader, type AiwgChunkedIndexLoadOptions, type AiwgChunkedIndexLoader, type AiwgChunkedIndexProgress, type AiwgChunkedIndexProgressPhase, type AiwgChunkedIndexQueryOptions, type AiwgChunkedIndexQueryResult, type AiwgChunkedIndexValidationResult, type AiwgDetailIdEncoding, type AiwgFortemiChunkDetailRef, type AiwgFortemiChunkManifest, type AiwgFortemiChunkPart, type AiwgFortemiChunkPartRef, type AiwgFortemiIndexExport, type AiwgFortemiKnownRecordType, type AiwgFortemiProjectedRecord, type AiwgFortemiProvenance, type AiwgFortemiProvenanceEvent, type AiwgFortemiRecord, type AiwgFortemiRecordSource, type AiwgFortemiRecordType, type AiwgFortemiRelationship, type AiwgFortemiSkosConcept, type AiwgFortemiSkosRelation, type AiwgFortemiSkosRelationType, type AiwgIndexController, type AiwgIndexControllerListener, type AiwgIndexControllerSnapshot, type AiwgIndexGraphOptions, type AiwgIndexQueryMatch, type AiwgIndexQueryOptions, type AiwgIndexQueryRankedItem, type AiwgIndexQueryResult, type AiwgIndexQueryWeights, type AiwgIndexValidationResult, type AiwgPrivacyClassification, type AiwgProvenanceConfidence, type AiwgRelationshipDirection, type AiwgRelationshipEdgeSummary, type AiwgRelationshipNodeSummary, type AiwgRelationshipQueryOptions, type AiwgRelationshipSetOperation, type AiwgRelationshipSetOptions, type AiwgRelationshipSetResult, type AiwgRelationshipTraversalOptions, type AiwgRelationshipTraversalResult, type AiwgReviewAction, type AiwgReviewDecision, type AiwgReviewDecisionExport, type AiwgReviewInput, type AiwgStaticDuplicatePair, type AiwgStaticEmbeddingRecord, type AiwgStaticEmbeddingSet, type AiwgStaticHybridQueryOptions, type AiwgStaticSemanticQueryOptions, type AiwgStaticSemanticResult, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, assertAiwgStaticEmbeddingSet, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, findAiwgStaticDuplicatePairs, getAiwgFortemiFacets, queryAiwgFortemiIndex, queryAiwgHybridIndex, queryAiwgSemanticIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport, validateAiwgStaticEmbeddingSet };
|
package/dist/aiwg-index.js
CHANGED
|
@@ -25,19 +25,14 @@ var REQUIRED_RECORD_FIELDS = [
|
|
|
25
25
|
"privacy",
|
|
26
26
|
"updated_at"
|
|
27
27
|
];
|
|
28
|
-
var VALID_TYPES = /* @__PURE__ */ new Set([
|
|
29
|
-
"crm.contact",
|
|
30
|
-
"crm.organization",
|
|
31
|
-
"crm.event",
|
|
32
|
-
"crm.interaction",
|
|
33
|
-
"aiwg.artifact",
|
|
34
|
-
"docs.page"
|
|
35
|
-
]);
|
|
36
28
|
var DEFAULT_QUERY_WEIGHTS = {
|
|
37
29
|
title: 4,
|
|
38
30
|
tag: 3,
|
|
39
31
|
concept: 2,
|
|
40
|
-
text: 1
|
|
32
|
+
text: 1,
|
|
33
|
+
facet: 2,
|
|
34
|
+
id: 1,
|
|
35
|
+
source: 0.25
|
|
41
36
|
};
|
|
42
37
|
function hasString(value) {
|
|
43
38
|
return typeof value === "string" && value.length > 0;
|
|
@@ -138,7 +133,7 @@ function validateAiwgFortemiIndexExport(value) {
|
|
|
138
133
|
errors.push("items must be sorted by id: " + previousId + " before " + item.id);
|
|
139
134
|
}
|
|
140
135
|
if (hasString(item.id)) previousId = item.id;
|
|
141
|
-
if (!
|
|
136
|
+
if (!hasString(item.type)) errors.push("items[" + index + "].type must be a non-empty string");
|
|
142
137
|
else counts[item.type] = (counts[item.type] ?? 0) + 1;
|
|
143
138
|
if (!hasString(item.source?.path)) errors.push("items[" + index + "].source.path is required");
|
|
144
139
|
if (!hasString(item.source?.repo_relative_path)) errors.push("items[" + index + "].source.repo_relative_path is required");
|
|
@@ -233,7 +228,7 @@ function validateProjectedRecords(items) {
|
|
|
233
228
|
errors.push("items must be sorted by id: " + previousId + " before " + item.id);
|
|
234
229
|
}
|
|
235
230
|
if (hasString(item.id)) previousId = item.id;
|
|
236
|
-
if (!
|
|
231
|
+
if (!hasString(item.type)) errors.push("items[" + index + "].type must be a non-empty string");
|
|
237
232
|
if (!hasString(item.title)) errors.push("items[" + index + "].title is required");
|
|
238
233
|
if (typeof item.text !== "string") errors.push("items[" + index + "].text is required");
|
|
239
234
|
if (!item.facets || typeof item.facets !== "object" || Array.isArray(item.facets)) {
|
|
@@ -398,8 +393,99 @@ function queryMatches(item, q) {
|
|
|
398
393
|
}
|
|
399
394
|
return matches;
|
|
400
395
|
}
|
|
396
|
+
var DISCOVERY_STOPWORDS = /* @__PURE__ */ new Set([
|
|
397
|
+
"a",
|
|
398
|
+
"an",
|
|
399
|
+
"and",
|
|
400
|
+
"are",
|
|
401
|
+
"as",
|
|
402
|
+
"for",
|
|
403
|
+
"from",
|
|
404
|
+
"how",
|
|
405
|
+
"i",
|
|
406
|
+
"in",
|
|
407
|
+
"is",
|
|
408
|
+
"me",
|
|
409
|
+
"of",
|
|
410
|
+
"on",
|
|
411
|
+
"or",
|
|
412
|
+
"please",
|
|
413
|
+
"the",
|
|
414
|
+
"to",
|
|
415
|
+
"use",
|
|
416
|
+
"with"
|
|
417
|
+
]);
|
|
418
|
+
function normalizeDiscoveryText(value) {
|
|
419
|
+
return value.toLowerCase().replace(/[_/]+/g, " ").replace(/[^a-z0-9.-]+/g, " ").trim();
|
|
420
|
+
}
|
|
421
|
+
function canonicalDiscoveryName(value) {
|
|
422
|
+
return normalizeDiscoveryText(value).replace(/[\s.-]+/g, "");
|
|
423
|
+
}
|
|
424
|
+
function discoveryTokens(value) {
|
|
425
|
+
return normalizeDiscoveryText(value).split(/\s+/).filter((token) => token.length > 1 && !DISCOVERY_STOPWORDS.has(token));
|
|
426
|
+
}
|
|
427
|
+
function facetValues(item, names) {
|
|
428
|
+
return names.flatMap((name) => item.facets[name] ?? []);
|
|
429
|
+
}
|
|
430
|
+
function addDiscoveryMatch(matches, match) {
|
|
431
|
+
if (!matches.some((existing) => existing.field === match.field && existing.value === match.value && existing.reason === match.reason)) {
|
|
432
|
+
matches.push(match);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function tokenOverlapScore(tokens, value) {
|
|
436
|
+
if (tokens.length === 0 || !value) return 0;
|
|
437
|
+
const normalized = normalizeDiscoveryText(value);
|
|
438
|
+
const hits = tokens.filter((token) => normalized.includes(token)).length;
|
|
439
|
+
return hits / tokens.length;
|
|
440
|
+
}
|
|
441
|
+
function discoveryMatches(item, query) {
|
|
442
|
+
if (!query) return [];
|
|
443
|
+
const matches = [];
|
|
444
|
+
const tokens = discoveryTokens(query);
|
|
445
|
+
const canonicalQuery = canonicalDiscoveryName(query);
|
|
446
|
+
const idParts = item.id.split(/[:/]/);
|
|
447
|
+
const names = [
|
|
448
|
+
item.id,
|
|
449
|
+
item.title,
|
|
450
|
+
...idParts,
|
|
451
|
+
...facetValues(item, ["name", "canonical_name", "command", "skill", "agent", "rule"])
|
|
452
|
+
].filter(Boolean);
|
|
453
|
+
const triggers = facetValues(item, ["trigger", "triggers", "trigger_phrase", "trigger_phrases"]);
|
|
454
|
+
const capabilities = [
|
|
455
|
+
...facetValues(item, ["capability", "capabilities", "summary", "description"]),
|
|
456
|
+
...item.concepts,
|
|
457
|
+
...item.tags
|
|
458
|
+
];
|
|
459
|
+
const sourceValues = [item.source?.path, item.source?.repo_relative_path, item.source?.locator].filter(Boolean);
|
|
460
|
+
for (const name of names) {
|
|
461
|
+
const canonicalName = canonicalDiscoveryName(name);
|
|
462
|
+
if (!canonicalName) continue;
|
|
463
|
+
if (canonicalName === canonicalQuery) {
|
|
464
|
+
addDiscoveryMatch(matches, { field: "id", value: name, score: 80, reason: "exact canonical name" });
|
|
465
|
+
} else if (canonicalName.includes(canonicalQuery) || canonicalQuery.includes(canonicalName)) {
|
|
466
|
+
addDiscoveryMatch(matches, { field: "id", value: name, score: 48, reason: "near canonical name" });
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const titleOverlap = tokenOverlapScore(tokens, item.title);
|
|
470
|
+
if (titleOverlap > 0) addDiscoveryMatch(matches, { field: "title", value: item.title, score: 18 * titleOverlap, reason: "title token overlap" });
|
|
471
|
+
for (const trigger of triggers) {
|
|
472
|
+
const overlap = tokenOverlapScore(tokens, trigger);
|
|
473
|
+
if (overlap > 0) addDiscoveryMatch(matches, { field: "facet", value: trigger, score: 34 * overlap, reason: "trigger phrase" });
|
|
474
|
+
}
|
|
475
|
+
for (const capability of capabilities) {
|
|
476
|
+
const overlap = tokenOverlapScore(tokens, capability);
|
|
477
|
+
if (overlap > 0) addDiscoveryMatch(matches, { field: "concept", value: capability, score: 22 * overlap, reason: "capability overlap" });
|
|
478
|
+
}
|
|
479
|
+
const textOverlap = tokenOverlapScore(tokens, item.text);
|
|
480
|
+
if (textOverlap > 0) addDiscoveryMatch(matches, { field: "text", value: item.text, score: 8 * textOverlap, reason: "body token overlap" });
|
|
481
|
+
for (const source of sourceValues) {
|
|
482
|
+
const overlap = tokenOverlapScore(tokens, source);
|
|
483
|
+
if (overlap > 0) addDiscoveryMatch(matches, { field: "source", value: source, score: 2 * overlap, reason: "path overlap" });
|
|
484
|
+
}
|
|
485
|
+
return matches;
|
|
486
|
+
}
|
|
401
487
|
function rankMatches(matches, weights) {
|
|
402
|
-
return matches.reduce((total, match) => total + weights[match.field], 0);
|
|
488
|
+
return matches.reduce((total, match) => total + (match.score ?? weights[match.field]), 0);
|
|
403
489
|
}
|
|
404
490
|
function clipSnippet(value, q, maxLength) {
|
|
405
491
|
const normalizedLength = Math.max(20, maxLength);
|
|
@@ -423,7 +509,12 @@ function createSnippet(item, matches, q, maxLength) {
|
|
|
423
509
|
}
|
|
424
510
|
function createRankedEntries(items, q, options, ordinalBase = 0) {
|
|
425
511
|
const weights = { ...DEFAULT_QUERY_WEIGHTS, ...options.weights };
|
|
426
|
-
|
|
512
|
+
const profile = options.searchProfile ?? "default";
|
|
513
|
+
return items.map((item, ordinal) => ({
|
|
514
|
+
item,
|
|
515
|
+
ordinal: ordinalBase + ordinal,
|
|
516
|
+
matches: profile === "aiwg-discovery" ? discoveryMatches(item, q) : queryMatches(item, q)
|
|
517
|
+
})).filter(({ item, matches }) => {
|
|
427
518
|
if (q && matches.length === 0) return false;
|
|
428
519
|
if (options.types && !options.types.includes(item.type)) return false;
|
|
429
520
|
if (options.privacy && !options.privacy.includes(item.privacy.classification)) return false;
|
|
@@ -470,7 +561,106 @@ function createQueryResultFromRankedEntries(entries, query, options) {
|
|
|
470
561
|
}
|
|
471
562
|
function queryAiwgFortemiIndex(index, query = "", options = {}) {
|
|
472
563
|
const q = query.trim().toLowerCase();
|
|
473
|
-
|
|
564
|
+
const entries = createRankedEntries(index.items, q, options);
|
|
565
|
+
if (entries.length === 0 && q && options.searchProfile === "aiwg-discovery") {
|
|
566
|
+
const relaxed = discoveryTokens(q).join(" ");
|
|
567
|
+
return createQueryResultFromRankedEntries(createRankedEntries(index.items, relaxed, options), relaxed, options);
|
|
568
|
+
}
|
|
569
|
+
return createQueryResultFromRankedEntries(entries, q, options);
|
|
570
|
+
}
|
|
571
|
+
function cosineSimilarity(left, right) {
|
|
572
|
+
if (left.length !== right.length || left.length === 0) return 0;
|
|
573
|
+
let dot = 0;
|
|
574
|
+
let leftMag = 0;
|
|
575
|
+
let rightMag = 0;
|
|
576
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
577
|
+
const l = left[i];
|
|
578
|
+
const r = right[i];
|
|
579
|
+
dot += l * r;
|
|
580
|
+
leftMag += l * l;
|
|
581
|
+
rightMag += r * r;
|
|
582
|
+
}
|
|
583
|
+
if (leftMag === 0 || rightMag === 0) return 0;
|
|
584
|
+
return dot / (Math.sqrt(leftMag) * Math.sqrt(rightMag));
|
|
585
|
+
}
|
|
586
|
+
function validateAiwgStaticEmbeddingSet(value) {
|
|
587
|
+
const errors = [];
|
|
588
|
+
const data = value;
|
|
589
|
+
if (data?.schema_version !== "aiwg.fortemi.embedding.set.v1") errors.push("schema_version must be aiwg.fortemi.embedding.set.v1");
|
|
590
|
+
if (!hasString(data?.id)) errors.push("id is required");
|
|
591
|
+
if (!hasString(data?.model)) errors.push("model is required");
|
|
592
|
+
if (!hasPositiveInteger(data?.dimensions)) errors.push("dimensions must be a positive integer");
|
|
593
|
+
if (!hasString(data?.generated_at)) errors.push("generated_at is required");
|
|
594
|
+
if (!hasString(data?.granularity)) errors.push("granularity is required");
|
|
595
|
+
if (!Array.isArray(data?.embeddings)) errors.push("embeddings must be an array");
|
|
596
|
+
for (const [index, embedding] of (data.embeddings ?? []).entries()) {
|
|
597
|
+
if (!hasString(embedding.record_id)) errors.push("embeddings[" + index + "].record_id is required");
|
|
598
|
+
if (!hasString(embedding.input_hash)) errors.push("embeddings[" + index + "].input_hash is required");
|
|
599
|
+
if (!Array.isArray(embedding.embedding)) errors.push("embeddings[" + index + "].embedding must be an array");
|
|
600
|
+
else if (hasPositiveInteger(data?.dimensions) && embedding.embedding.length !== data.dimensions) {
|
|
601
|
+
errors.push("embeddings[" + index + "].embedding length must match dimensions");
|
|
602
|
+
} else if (!embedding.embedding.every((number) => typeof number === "number" && Number.isFinite(number))) {
|
|
603
|
+
errors.push("embeddings[" + index + "].embedding must contain finite numbers");
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return { valid: errors.length === 0, errors };
|
|
607
|
+
}
|
|
608
|
+
function assertAiwgStaticEmbeddingSet(value) {
|
|
609
|
+
const result = validateAiwgStaticEmbeddingSet(value);
|
|
610
|
+
if (!result.valid) throw new Error("Invalid AIWG Fortemi embedding set:\n" + result.errors.join("\n"));
|
|
611
|
+
return value;
|
|
612
|
+
}
|
|
613
|
+
function queryAiwgSemanticIndex(index, embeddingSet, queryEmbedding, options = {}) {
|
|
614
|
+
assertAiwgStaticEmbeddingSet(embeddingSet);
|
|
615
|
+
if (queryEmbedding.length !== embeddingSet.dimensions) throw new Error("query embedding length must match embedding set dimensions");
|
|
616
|
+
const byId = new Map(index.items.map((item) => [item.id, item]));
|
|
617
|
+
const offset = options.offset ?? 0;
|
|
618
|
+
const limit = options.limit ?? 20;
|
|
619
|
+
return embeddingSet.embeddings.map((embedding) => {
|
|
620
|
+
const item = byId.get(embedding.record_id);
|
|
621
|
+
if (!item) return null;
|
|
622
|
+
return { item, embedding, score: cosineSimilarity(queryEmbedding, embedding.embedding) };
|
|
623
|
+
}).filter((result) => result !== null && result.score >= (options.minScore ?? -1)).sort((left, right) => right.score - left.score || left.item.id.localeCompare(right.item.id)).slice(offset, offset + limit);
|
|
624
|
+
}
|
|
625
|
+
function queryAiwgHybridIndex(index, embeddingSet, query, queryEmbedding, options = {}) {
|
|
626
|
+
const lexical = queryAiwgFortemiIndex(index, query, { ...options, rank: true });
|
|
627
|
+
const semantic = queryAiwgSemanticIndex(index, embeddingSet, queryEmbedding, { limit: index.items.length });
|
|
628
|
+
const lexicalWeight = options.lexicalWeight ?? 0.5;
|
|
629
|
+
const semanticWeight = options.semanticWeight ?? 0.5;
|
|
630
|
+
const lexicalScores = new Map(lexical.rankedItems?.map((entry) => [entry.item.id, entry.rank]) ?? []);
|
|
631
|
+
const maxLexical = Math.max(1, ...lexicalScores.values());
|
|
632
|
+
const embeddingById = new Map(semantic.flatMap((entry) => entry.embedding ? [[entry.item.id, entry.embedding]] : []));
|
|
633
|
+
const semanticScores = new Map(semantic.map((entry) => [entry.item.id, entry.score]));
|
|
634
|
+
const ids = /* @__PURE__ */ new Set([...lexicalScores.keys(), ...semanticScores.keys()]);
|
|
635
|
+
const offset = options.offset ?? 0;
|
|
636
|
+
const limit = options.limit ?? 20;
|
|
637
|
+
return [...ids].map((id) => {
|
|
638
|
+
const item = index.items.find((candidate) => candidate.id === id);
|
|
639
|
+
const embedding = embeddingById.get(id);
|
|
640
|
+
if (!item) return null;
|
|
641
|
+
return {
|
|
642
|
+
item,
|
|
643
|
+
...embedding ? { embedding } : {},
|
|
644
|
+
score: (lexicalScores.get(id) ?? 0) / maxLexical * lexicalWeight + (semanticScores.get(id) ?? 0) * semanticWeight
|
|
645
|
+
};
|
|
646
|
+
}).filter((result) => result !== null && result.score >= (options.minScore ?? -1)).sort((left, right) => right.score - left.score || left.item.id.localeCompare(right.item.id)).slice(offset, offset + limit);
|
|
647
|
+
}
|
|
648
|
+
function findAiwgStaticDuplicatePairs(index, embeddingSet, threshold = 0.9) {
|
|
649
|
+
assertAiwgStaticEmbeddingSet(embeddingSet);
|
|
650
|
+
const byId = new Map(index.items.map((item) => [item.id, item]));
|
|
651
|
+
const pairs = [];
|
|
652
|
+
for (let leftIndex = 0; leftIndex < embeddingSet.embeddings.length; leftIndex += 1) {
|
|
653
|
+
for (let rightIndex = leftIndex + 1; rightIndex < embeddingSet.embeddings.length; rightIndex += 1) {
|
|
654
|
+
const leftEmbedding = embeddingSet.embeddings[leftIndex];
|
|
655
|
+
const rightEmbedding = embeddingSet.embeddings[rightIndex];
|
|
656
|
+
const left = byId.get(leftEmbedding.record_id);
|
|
657
|
+
const right = byId.get(rightEmbedding.record_id);
|
|
658
|
+
if (!left || !right) continue;
|
|
659
|
+
const score = cosineSimilarity(leftEmbedding.embedding, rightEmbedding.embedding);
|
|
660
|
+
if (score >= threshold) pairs.push({ left, right, score });
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return pairs.sort((left, right) => right.score - left.score || left.left.id.localeCompare(right.left.id));
|
|
474
664
|
}
|
|
475
665
|
function chunkPartCacheKey(part) {
|
|
476
666
|
return `${part.offset}:${part.href}`;
|
|
@@ -569,6 +759,104 @@ async function getChunkRecord(runtime, id) {
|
|
|
569
759
|
}
|
|
570
760
|
return record;
|
|
571
761
|
}
|
|
762
|
+
function relationshipTypeFilter(options) {
|
|
763
|
+
return options?.relationshipType ?? options?.type;
|
|
764
|
+
}
|
|
765
|
+
function edgeFromRelationship(sourceId, relationship) {
|
|
766
|
+
return {
|
|
767
|
+
source_id: sourceId,
|
|
768
|
+
target_id: relationship.target_id,
|
|
769
|
+
type: relationship.type,
|
|
770
|
+
...relationship.source_path ? { source_path: relationship.source_path } : {}
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
function relationshipMatches(edge, options = {}) {
|
|
774
|
+
const type = relationshipTypeFilter(options);
|
|
775
|
+
const direction = options.direction ?? "both";
|
|
776
|
+
if (type && edge.type !== type) return false;
|
|
777
|
+
if (options.sourceId && edge.source_id !== options.sourceId) return false;
|
|
778
|
+
if (options.targetId && edge.target_id !== options.targetId) return false;
|
|
779
|
+
if (direction === "out" && options.targetId && edge.target_id !== options.targetId) return false;
|
|
780
|
+
if (direction === "in" && options.sourceId && edge.source_id !== options.sourceId) return false;
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
function nodeSummary(item) {
|
|
784
|
+
return { id: item.id, type: item.type, title: item.title };
|
|
785
|
+
}
|
|
786
|
+
function addNode(nodes, item) {
|
|
787
|
+
if (item) nodes.set(item.id, nodeSummary(item));
|
|
788
|
+
}
|
|
789
|
+
function relationshipResultFromRecords(records, options = {}) {
|
|
790
|
+
const byId = new Map(records.map((record) => [record.id, record]));
|
|
791
|
+
const edges = [];
|
|
792
|
+
for (const record of records) {
|
|
793
|
+
for (const relationship of record.relationships ?? []) {
|
|
794
|
+
const edge = edgeFromRelationship(record.id, relationship);
|
|
795
|
+
if (!relationshipMatches(edge, options)) continue;
|
|
796
|
+
edges.push(edge);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
const limitedEdges = (options.limit ? edges.slice(0, options.limit) : edges).sort((left, right) => left.source_id.localeCompare(right.source_id) || left.target_id.localeCompare(right.target_id) || left.type.localeCompare(right.type));
|
|
800
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
801
|
+
for (const edge of limitedEdges) {
|
|
802
|
+
addNode(nodes, byId.get(edge.source_id));
|
|
803
|
+
addNode(nodes, byId.get(edge.target_id));
|
|
804
|
+
}
|
|
805
|
+
return {
|
|
806
|
+
nodes: [...nodes.values()].sort((left, right) => left.id.localeCompare(right.id)),
|
|
807
|
+
edges: limitedEdges,
|
|
808
|
+
complete: true
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
function neighborQueryOptions(id, options = {}) {
|
|
812
|
+
const direction = options.direction ?? "both";
|
|
813
|
+
return {
|
|
814
|
+
...options,
|
|
815
|
+
...direction === "out" ? { sourceId: id } : {},
|
|
816
|
+
...direction === "in" ? { targetId: id } : {}
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
function filterNeighborResult(id, result, options = {}) {
|
|
820
|
+
const direction = options.direction ?? "both";
|
|
821
|
+
const edges = result.edges.filter((edge) => {
|
|
822
|
+
if (direction === "out") return edge.source_id === id;
|
|
823
|
+
if (direction === "in") return edge.target_id === id;
|
|
824
|
+
return edge.source_id === id || edge.target_id === id;
|
|
825
|
+
});
|
|
826
|
+
const ids = /* @__PURE__ */ new Set();
|
|
827
|
+
for (const edge of edges) {
|
|
828
|
+
ids.add(edge.source_id);
|
|
829
|
+
ids.add(edge.target_id);
|
|
830
|
+
}
|
|
831
|
+
return {
|
|
832
|
+
...result,
|
|
833
|
+
edges,
|
|
834
|
+
nodes: result.nodes.filter((node) => ids.has(node.id))
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
async function recordsFromChunkedRuntime(runtime, onProgress) {
|
|
838
|
+
let scannedParts = 0;
|
|
839
|
+
let fetchedParts = 0;
|
|
840
|
+
const records = [];
|
|
841
|
+
for (const partRef of runtime.manifest.parts) {
|
|
842
|
+
const loaded = await loadChunkPart(runtime, partRef);
|
|
843
|
+
if (loaded.fetched) fetchedParts += 1;
|
|
844
|
+
scannedParts += 1;
|
|
845
|
+
onProgress?.({ phase: "part", done: scannedParts, total: runtime.manifest.parts.length, href: partRef.href });
|
|
846
|
+
for (const item of loaded.part.items) {
|
|
847
|
+
records.push(item.relationships ? item : await getChunkRecord(runtime, item.id));
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return { records, scannedParts, fetchedParts };
|
|
851
|
+
}
|
|
852
|
+
async function relationshipResultFromChunkedRuntime(runtime, options = {}) {
|
|
853
|
+
const loaded = await recordsFromChunkedRuntime(runtime);
|
|
854
|
+
return {
|
|
855
|
+
...relationshipResultFromRecords(loaded.records, options),
|
|
856
|
+
scannedParts: loaded.scannedParts,
|
|
857
|
+
fetchedParts: loaded.fetchedParts
|
|
858
|
+
};
|
|
859
|
+
}
|
|
572
860
|
async function queryChunkedAiwgFortemiIndex(runtime, query = "", options = {}) {
|
|
573
861
|
const q = query.trim().toLowerCase();
|
|
574
862
|
let scannedParts = 0;
|
|
@@ -749,6 +1037,39 @@ function createAiwgIndexController(initialIndex) {
|
|
|
749
1037
|
if (!found) throw new Error("Record not found: " + id);
|
|
750
1038
|
return found;
|
|
751
1039
|
},
|
|
1040
|
+
async neighbors(id, options) {
|
|
1041
|
+
try {
|
|
1042
|
+
const queryOptions = neighborQueryOptions(id, options);
|
|
1043
|
+
const result = chunked ? await relationshipResultFromChunkedRuntime(chunked, queryOptions) : relationshipResultFromRecords(requireIndex().items, queryOptions);
|
|
1044
|
+
return filterNeighborResult(id, result, options);
|
|
1045
|
+
} catch (err) {
|
|
1046
|
+
error = err instanceof Error ? err : new Error(String(err));
|
|
1047
|
+
notify();
|
|
1048
|
+
throw error;
|
|
1049
|
+
}
|
|
1050
|
+
},
|
|
1051
|
+
async relationshipQuery(options) {
|
|
1052
|
+
try {
|
|
1053
|
+
return chunked ? await relationshipResultFromChunkedRuntime(chunked, options) : relationshipResultFromRecords(requireIndex().items, options);
|
|
1054
|
+
} catch (err) {
|
|
1055
|
+
error = err instanceof Error ? err : new Error(String(err));
|
|
1056
|
+
notify();
|
|
1057
|
+
throw error;
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
async relationshipSet(options) {
|
|
1061
|
+
const [left, right] = await Promise.all([
|
|
1062
|
+
this.neighbors(options.a, options),
|
|
1063
|
+
this.neighbors(options.b, options)
|
|
1064
|
+
]);
|
|
1065
|
+
const leftIds = new Set(left.nodes.map((node) => node.id).filter((id) => id !== options.a));
|
|
1066
|
+
const rightIds = new Set(right.nodes.map((node) => node.id).filter((id) => id !== options.b));
|
|
1067
|
+
let ids;
|
|
1068
|
+
if (options.op === "intersection") ids = [...leftIds].filter((id) => rightIds.has(id));
|
|
1069
|
+
else if (options.op === "difference") ids = [...leftIds].filter((id) => !rightIds.has(id));
|
|
1070
|
+
else ids = [.../* @__PURE__ */ new Set([...leftIds, ...rightIds])];
|
|
1071
|
+
return { op: options.op, ids: ids.sort() };
|
|
1072
|
+
},
|
|
752
1073
|
clearChunkCache() {
|
|
753
1074
|
chunked?.partCache.clear();
|
|
754
1075
|
chunked?.detailCache.clear();
|
|
@@ -759,6 +1080,15 @@ function createAiwgIndexController(initialIndex) {
|
|
|
759
1080
|
toCommunityGraph(options) {
|
|
760
1081
|
return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
|
|
761
1082
|
},
|
|
1083
|
+
async toCommunityGraphChunked(options) {
|
|
1084
|
+
if (!chunked) return aiwgFortemiIndexToCommunityGraph(requireIndex(), options);
|
|
1085
|
+
const loaded = await recordsFromChunkedRuntime(chunked, options?.onProgress);
|
|
1086
|
+
return aiwgFortemiIndexToCommunityGraph({
|
|
1087
|
+
generated_at: chunked.manifest.generated_at,
|
|
1088
|
+
source: chunked.manifest.source,
|
|
1089
|
+
items: loaded.records
|
|
1090
|
+
}, options);
|
|
1091
|
+
},
|
|
762
1092
|
setReviewDecision(input) {
|
|
763
1093
|
const decision = {
|
|
764
1094
|
...input,
|
|
@@ -834,6 +1164,6 @@ function communityIdsFor(item, options) {
|
|
|
834
1164
|
return [`type:${item.type}`];
|
|
835
1165
|
}
|
|
836
1166
|
|
|
837
|
-
export { AIWG_SCAN_REQUIRED_FIELDS, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, getAiwgFortemiFacets, queryAiwgFortemiIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport };
|
|
1167
|
+
export { AIWG_SCAN_REQUIRED_FIELDS, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, assertAiwgStaticEmbeddingSet, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, findAiwgStaticDuplicatePairs, getAiwgFortemiFacets, queryAiwgFortemiIndex, queryAiwgHybridIndex, queryAiwgSemanticIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport, validateAiwgStaticEmbeddingSet };
|
|
838
1168
|
//# sourceMappingURL=aiwg-index.js.map
|
|
839
1169
|
//# sourceMappingURL=aiwg-index.js.map
|