@fortemi/core 2026.7.1 → 2026.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/dist/aiwg-index.d.ts +28 -1
- package/dist/aiwg-index.js +59 -2
- package/dist/aiwg-index.js.map +1 -1
- package/dist/index.d.ts +21 -2
- package/dist/index.js +186 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -227,17 +227,31 @@ scan projection.
|
|
|
227
227
|
Static semantic search uses an optional sidecar contract:
|
|
228
228
|
|
|
229
229
|
```ts
|
|
230
|
-
import { queryAiwgHybridIndex } from '@fortemi/core/aiwg-index'
|
|
230
|
+
import { buildAiwgStaticEmbeddingSet, queryAiwgHybridIndex } from '@fortemi/core/aiwg-index'
|
|
231
231
|
|
|
232
232
|
const embeddingSet = await fetch('/search/aiwg-index/embeddings.json').then((res) => res.json())
|
|
233
233
|
const queryEmbedding = await hostEmbed('workspace health check')
|
|
234
234
|
const semanticResults = queryAiwgHybridIndex(index, embeddingSet, 'health check', queryEmbedding)
|
|
235
|
+
|
|
236
|
+
// Node/CLI generation path. Supply any Node-safe model backend; @fortemi/core
|
|
237
|
+
// only writes the shared embedding-set graph format and does not require DOM or WebGL.
|
|
238
|
+
const cliEmbeddingSet = await buildAiwgStaticEmbeddingSet(index, {
|
|
239
|
+
id: 'aiwg-cli-embeddings',
|
|
240
|
+
backend: {
|
|
241
|
+
model: 'local-node-embedder',
|
|
242
|
+
dimensions: 384,
|
|
243
|
+
embed: async (input) => nodeEmbed(input),
|
|
244
|
+
},
|
|
245
|
+
})
|
|
235
246
|
```
|
|
236
247
|
|
|
237
248
|
`aiwg.fortemi.embedding.set.v1` records the model, dimensions, granularity
|
|
238
249
|
(`title-summary`, `body`, `chunked-body`, or a project value), source record IDs,
|
|
239
250
|
and per-vector input hashes. Hosts provide query embeddings; `@fortemi/core` does
|
|
240
|
-
not add a model runtime dependency for static AIWG search.
|
|
251
|
+
not add a model runtime dependency for static AIWG search. The builder uses the
|
|
252
|
+
same record text projection as static search, including attachment
|
|
253
|
+
`extracted_text`, and records only attachment metadata references, never raw blob
|
|
254
|
+
bytes.
|
|
241
255
|
|
|
242
256
|
## What You Get
|
|
243
257
|
|
package/dist/aiwg-index.d.ts
CHANGED
|
@@ -94,6 +94,17 @@ interface AiwgFortemiRecordEmbedding {
|
|
|
94
94
|
source_path?: string;
|
|
95
95
|
metadata?: Record<string, unknown>;
|
|
96
96
|
}
|
|
97
|
+
interface AiwgFortemiAttachmentReference {
|
|
98
|
+
id: string;
|
|
99
|
+
path: string;
|
|
100
|
+
mime: string | null;
|
|
101
|
+
checksum: string;
|
|
102
|
+
bytes: number;
|
|
103
|
+
}
|
|
104
|
+
interface AiwgFortemiBinarySource {
|
|
105
|
+
extracted_text: string;
|
|
106
|
+
attachment: AiwgFortemiAttachmentReference;
|
|
107
|
+
}
|
|
97
108
|
interface AiwgFortemiRecord {
|
|
98
109
|
schema_version: AiwgFortemiRecordSchemaVersion;
|
|
99
110
|
id: string;
|
|
@@ -108,6 +119,7 @@ interface AiwgFortemiRecord {
|
|
|
108
119
|
provenance: AiwgFortemiProvenance[];
|
|
109
120
|
search?: AiwgFortemiSearchProjection;
|
|
110
121
|
chunks?: AiwgFortemiChunk[];
|
|
122
|
+
binary_sources?: AiwgFortemiBinarySource[];
|
|
111
123
|
embeddings?: AiwgFortemiRecordEmbedding[];
|
|
112
124
|
compatibility?: Record<string, unknown>;
|
|
113
125
|
/** Optional rich SKOS metadata for static consumers that need labels/definitions without opening a shard. */
|
|
@@ -321,6 +333,20 @@ interface AiwgStaticEmbeddingSet {
|
|
|
321
333
|
input_hash_algorithm?: string;
|
|
322
334
|
embeddings: AiwgStaticEmbeddingRecord[];
|
|
323
335
|
}
|
|
336
|
+
interface AiwgHeadlessEmbeddingBackend {
|
|
337
|
+
model: string;
|
|
338
|
+
dimensions: number;
|
|
339
|
+
embed(input: string, record: AiwgFortemiRecord): number[] | Promise<number[]>;
|
|
340
|
+
}
|
|
341
|
+
interface BuildAiwgStaticEmbeddingSetOptions {
|
|
342
|
+
id: string;
|
|
343
|
+
backend: AiwgHeadlessEmbeddingBackend;
|
|
344
|
+
records?: AiwgFortemiRecord[];
|
|
345
|
+
generatedAt?: string | Date;
|
|
346
|
+
granularity?: AiwgStaticEmbeddingSet['granularity'];
|
|
347
|
+
metric?: AiwgStaticEmbeddingSet['metric'];
|
|
348
|
+
textForRecord?: (record: AiwgFortemiRecord) => string;
|
|
349
|
+
}
|
|
324
350
|
interface AiwgStaticSemanticQueryOptions {
|
|
325
351
|
limit?: number;
|
|
326
352
|
offset?: number;
|
|
@@ -390,6 +416,7 @@ declare function encodeAiwgDetailId(id: string, encoding?: AiwgDetailIdEncoding)
|
|
|
390
416
|
declare function aiwgDetailHrefForId(detail: AiwgFortemiChunkDetailRef, id: string): string;
|
|
391
417
|
declare function createAiwgFetchDetailLoader(baseUrl?: string | URL): AiwgChunkedIndexDetailLoader;
|
|
392
418
|
declare function getAiwgFortemiFacets(items: AiwgFortemiRecord[]): Record<string, Record<string, number>>;
|
|
419
|
+
declare function buildAiwgStaticEmbeddingSet(index: AiwgFortemiIndexExport, options: BuildAiwgStaticEmbeddingSetOptions): Promise<AiwgStaticEmbeddingSet>;
|
|
393
420
|
interface AiwgChunkedIndexBuildOptions {
|
|
394
421
|
partSize?: number;
|
|
395
422
|
projection?: Array<keyof AiwgFortemiRecord>;
|
|
@@ -434,4 +461,4 @@ declare function aiwgFortemiIndexToCommunityGraph(index: AiwgFortemiIndexExport,
|
|
|
434
461
|
}[];
|
|
435
462
|
};
|
|
436
463
|
|
|
437
|
-
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 AiwgFortemiChunk, type AiwgFortemiChunkDetailRef, type AiwgFortemiChunkManifest, type AiwgFortemiChunkPart, type AiwgFortemiChunkPartRef, type AiwgFortemiIndexExport, type AiwgFortemiIndexExportSchemaVersion, type AiwgFortemiKnownRecordType, type AiwgFortemiProjectedRecord, type AiwgFortemiProvenance, type AiwgFortemiProvenanceEvent, type AiwgFortemiRecord, type AiwgFortemiRecordEmbedding, type AiwgFortemiRecordSchemaVersion, type AiwgFortemiRecordSource, type AiwgFortemiRecordType, type AiwgFortemiRelationship, type AiwgFortemiRelationshipDirection, type AiwgFortemiSearchProjection, 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 };
|
|
464
|
+
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 AiwgFortemiAttachmentReference, type AiwgFortemiBinarySource, type AiwgFortemiChunk, type AiwgFortemiChunkDetailRef, type AiwgFortemiChunkManifest, type AiwgFortemiChunkPart, type AiwgFortemiChunkPartRef, type AiwgFortemiIndexExport, type AiwgFortemiIndexExportSchemaVersion, type AiwgFortemiKnownRecordType, type AiwgFortemiProjectedRecord, type AiwgFortemiProvenance, type AiwgFortemiProvenanceEvent, type AiwgFortemiRecord, type AiwgFortemiRecordEmbedding, type AiwgFortemiRecordSchemaVersion, type AiwgFortemiRecordSource, type AiwgFortemiRecordType, type AiwgFortemiRelationship, type AiwgFortemiRelationshipDirection, type AiwgFortemiSearchProjection, type AiwgFortemiSkosConcept, type AiwgFortemiSkosRelation, type AiwgFortemiSkosRelationType, type AiwgHeadlessEmbeddingBackend, 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, type BuildAiwgStaticEmbeddingSetOptions, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, assertAiwgStaticEmbeddingSet, buildAiwgChunkedIndex, buildAiwgStaticEmbeddingSet, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, findAiwgStaticDuplicatePairs, getAiwgFortemiFacets, queryAiwgFortemiIndex, queryAiwgHybridIndex, queryAiwgSemanticIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport, validateAiwgStaticEmbeddingSet };
|
package/dist/aiwg-index.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
2
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
3
|
+
|
|
4
|
+
// src/hash.ts
|
|
5
|
+
function computeHash(data) {
|
|
6
|
+
const digest = sha256(data);
|
|
7
|
+
return `sha256:${bytesToHex(digest)}`;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
// src/aiwg-index.ts
|
|
2
11
|
var AIWG_SCAN_REQUIRED_FIELDS = [
|
|
3
12
|
"schema_version",
|
|
@@ -392,7 +401,55 @@ function recordTitle(item) {
|
|
|
392
401
|
return item.title ?? item.search?.title ?? item.search?.name ?? item.id;
|
|
393
402
|
}
|
|
394
403
|
function recordText(item) {
|
|
395
|
-
|
|
404
|
+
const base = item.text ?? item.search?.body ?? item.search?.summary ?? item.chunks?.map((chunk) => chunk.text ?? chunk.body ?? chunk.summary ?? "").filter(Boolean).join("\n") ?? "";
|
|
405
|
+
const extractedText = "binary_sources" in item ? item.binary_sources?.map((source) => source.extracted_text).filter(Boolean).join("\n") ?? "" : "";
|
|
406
|
+
return [base, extractedText].filter(Boolean).join("\n");
|
|
407
|
+
}
|
|
408
|
+
function defaultEmbeddingInput(record, granularity) {
|
|
409
|
+
const title = recordTitle(record);
|
|
410
|
+
const text = recordText(record);
|
|
411
|
+
if (granularity === "title-summary") {
|
|
412
|
+
const extractedText = record.binary_sources?.map((source) => source.extracted_text).filter(Boolean).join("\n") ?? "";
|
|
413
|
+
return [title, record.search?.summary ?? "", extractedText].filter(Boolean).join("\n");
|
|
414
|
+
}
|
|
415
|
+
return [title, text].filter(Boolean).join("\n");
|
|
416
|
+
}
|
|
417
|
+
function generatedAtString(value) {
|
|
418
|
+
if (value instanceof Date) return value.toISOString();
|
|
419
|
+
return value ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
420
|
+
}
|
|
421
|
+
async function buildAiwgStaticEmbeddingSet(index, options) {
|
|
422
|
+
assertAiwgFortemiIndexExport(index);
|
|
423
|
+
const granularity = options.granularity ?? "body";
|
|
424
|
+
const records = options.records ?? index.items;
|
|
425
|
+
const embeddings = [];
|
|
426
|
+
for (const record of records) {
|
|
427
|
+
const input = options.textForRecord?.(record) ?? defaultEmbeddingInput(record, granularity);
|
|
428
|
+
const embedding = await options.backend.embed(input, record);
|
|
429
|
+
if (embedding.length !== options.backend.dimensions) {
|
|
430
|
+
throw new Error(`Embedding for ${record.id} has ${embedding.length} dimensions; expected ${options.backend.dimensions}`);
|
|
431
|
+
}
|
|
432
|
+
embeddings.push({
|
|
433
|
+
record_id: record.id,
|
|
434
|
+
embedding,
|
|
435
|
+
granularity,
|
|
436
|
+
input_hash: computeHash(new TextEncoder().encode(input)),
|
|
437
|
+
source_path: record.source.path
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
const embeddingSet = {
|
|
441
|
+
schema_version: "aiwg.fortemi.embedding.set.v1",
|
|
442
|
+
id: options.id,
|
|
443
|
+
model: options.backend.model,
|
|
444
|
+
dimensions: options.backend.dimensions,
|
|
445
|
+
generated_at: generatedAtString(options.generatedAt),
|
|
446
|
+
granularity,
|
|
447
|
+
...options.metric ? { metric: options.metric } : {},
|
|
448
|
+
input_hash_algorithm: "sha256",
|
|
449
|
+
embeddings
|
|
450
|
+
};
|
|
451
|
+
assertAiwgStaticEmbeddingSet(embeddingSet);
|
|
452
|
+
return embeddingSet;
|
|
396
453
|
}
|
|
397
454
|
function recordSearchValues(item) {
|
|
398
455
|
const search = item.search;
|
|
@@ -1285,6 +1342,6 @@ function communityIdsFor(item, options) {
|
|
|
1285
1342
|
return [`type:${item.type}`];
|
|
1286
1343
|
}
|
|
1287
1344
|
|
|
1288
|
-
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 };
|
|
1345
|
+
export { AIWG_SCAN_REQUIRED_FIELDS, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, assertAiwgStaticEmbeddingSet, buildAiwgChunkedIndex, buildAiwgStaticEmbeddingSet, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, findAiwgStaticDuplicatePairs, getAiwgFortemiFacets, queryAiwgFortemiIndex, queryAiwgHybridIndex, queryAiwgSemanticIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport, validateAiwgStaticEmbeddingSet };
|
|
1289
1346
|
//# sourceMappingURL=aiwg-index.js.map
|
|
1290
1347
|
//# sourceMappingURL=aiwg-index.js.map
|