@zabaca/lattice 1.0.3 → 1.0.5
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/main.js +72 -19
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -711,7 +711,14 @@ class VoyageEmbeddingProvider {
|
|
|
711
711
|
const embeddings = await this.generateEmbeddings([text]);
|
|
712
712
|
return embeddings[0];
|
|
713
713
|
}
|
|
714
|
+
async generateQueryEmbedding(text) {
|
|
715
|
+
const embeddings = await this.generateEmbeddingsWithType([text], "query");
|
|
716
|
+
return embeddings[0];
|
|
717
|
+
}
|
|
714
718
|
async generateEmbeddings(texts) {
|
|
719
|
+
return this.generateEmbeddingsWithType(texts, this.inputType);
|
|
720
|
+
}
|
|
721
|
+
async generateEmbeddingsWithType(texts, inputType) {
|
|
715
722
|
if (!texts || texts.length === 0) {
|
|
716
723
|
return [];
|
|
717
724
|
}
|
|
@@ -726,7 +733,7 @@ class VoyageEmbeddingProvider {
|
|
|
726
733
|
model: this.model,
|
|
727
734
|
input: texts,
|
|
728
735
|
output_dimension: this.dimensions,
|
|
729
|
-
input_type:
|
|
736
|
+
input_type: inputType
|
|
730
737
|
})
|
|
731
738
|
});
|
|
732
739
|
if (!response.ok) {
|
|
@@ -813,6 +820,15 @@ class EmbeddingService {
|
|
|
813
820
|
}
|
|
814
821
|
return this.provider.generateEmbedding(text);
|
|
815
822
|
}
|
|
823
|
+
async generateQueryEmbedding(text) {
|
|
824
|
+
if (!text || text.trim().length === 0) {
|
|
825
|
+
throw new Error("Cannot generate embedding for empty text");
|
|
826
|
+
}
|
|
827
|
+
if (this.provider.generateQueryEmbedding) {
|
|
828
|
+
return this.provider.generateQueryEmbedding(text);
|
|
829
|
+
}
|
|
830
|
+
return this.provider.generateEmbedding(text);
|
|
831
|
+
}
|
|
816
832
|
async generateEmbeddings(texts) {
|
|
817
833
|
const validTexts = texts.filter((t) => t && t.trim().length > 0);
|
|
818
834
|
if (validTexts.length === 0) {
|
|
@@ -832,7 +848,6 @@ EmbeddingService = __legacyDecorateClassTS([
|
|
|
832
848
|
], EmbeddingService);
|
|
833
849
|
|
|
834
850
|
// src/graph/graph.service.ts
|
|
835
|
-
import { existsSync as existsSync3, unlinkSync } from "fs";
|
|
836
851
|
import { DuckDBInstance } from "@duckdb/node-api";
|
|
837
852
|
import { Injectable as Injectable6, Logger as Logger3 } from "@nestjs/common";
|
|
838
853
|
import { ConfigService as ConfigService2 } from "@nestjs/config";
|
|
@@ -845,11 +860,35 @@ class GraphService {
|
|
|
845
860
|
connecting = null;
|
|
846
861
|
vectorIndexes = new Set;
|
|
847
862
|
embeddingDimensions;
|
|
863
|
+
signalHandlersRegistered = false;
|
|
848
864
|
constructor(configService) {
|
|
849
865
|
this.configService = configService;
|
|
850
866
|
ensureLatticeHome();
|
|
851
867
|
this.dbPath = getDatabasePath();
|
|
852
868
|
this.embeddingDimensions = this.configService.get("EMBEDDING_DIMENSIONS") || 512;
|
|
869
|
+
this.registerSignalHandlers();
|
|
870
|
+
}
|
|
871
|
+
registerSignalHandlers() {
|
|
872
|
+
if (this.signalHandlersRegistered)
|
|
873
|
+
return;
|
|
874
|
+
this.signalHandlersRegistered = true;
|
|
875
|
+
const gracefulShutdown = async (signal) => {
|
|
876
|
+
this.logger.log(`Received ${signal}, checkpointing before exit...`);
|
|
877
|
+
try {
|
|
878
|
+
await this.checkpoint();
|
|
879
|
+
await this.disconnect();
|
|
880
|
+
} catch (error) {
|
|
881
|
+
this.logger.error(`Error during graceful shutdown: ${error instanceof Error ? error.message : String(error)}`);
|
|
882
|
+
}
|
|
883
|
+
process.exit(0);
|
|
884
|
+
};
|
|
885
|
+
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
886
|
+
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
887
|
+
process.on("beforeExit", async () => {
|
|
888
|
+
if (this.connection) {
|
|
889
|
+
await this.checkpoint();
|
|
890
|
+
}
|
|
891
|
+
});
|
|
853
892
|
}
|
|
854
893
|
async onModuleDestroy() {
|
|
855
894
|
await this.disconnect();
|
|
@@ -875,12 +914,7 @@ class GraphService {
|
|
|
875
914
|
}
|
|
876
915
|
async connect() {
|
|
877
916
|
try {
|
|
878
|
-
|
|
879
|
-
if (existsSync3(walPath)) {
|
|
880
|
-
this.logger.warn(`Removing WAL file to prevent HNSW index replay failure`);
|
|
881
|
-
unlinkSync(walPath);
|
|
882
|
-
}
|
|
883
|
-
this.instance = await DuckDBInstance.create(this.dbPath, {
|
|
917
|
+
this.instance = await DuckDBInstance.create(":memory:", {
|
|
884
918
|
allow_unsigned_extensions: "true"
|
|
885
919
|
});
|
|
886
920
|
this.connection = await this.instance.connect();
|
|
@@ -894,8 +928,10 @@ class GraphService {
|
|
|
894
928
|
} catch (e) {
|
|
895
929
|
this.logger.warn(`DuckPGQ extension not available: ${e instanceof Error ? e.message : String(e)}`);
|
|
896
930
|
}
|
|
931
|
+
await this.connection.run(`ATTACH '${this.dbPath}' AS lattice (READ_WRITE);`);
|
|
932
|
+
await this.connection.run("USE lattice;");
|
|
897
933
|
await this.initializeSchema();
|
|
898
|
-
this.logger.log(`Connected to DuckDB at ${this.dbPath}`);
|
|
934
|
+
this.logger.log(`Connected to DuckDB (in-memory + ATTACH) at ${this.dbPath}`);
|
|
899
935
|
} catch (error) {
|
|
900
936
|
this.connection = null;
|
|
901
937
|
this.instance = null;
|
|
@@ -905,11 +941,7 @@ class GraphService {
|
|
|
905
941
|
}
|
|
906
942
|
async disconnect() {
|
|
907
943
|
if (this.connection) {
|
|
908
|
-
|
|
909
|
-
await this.connection.run("CHECKPOINT;");
|
|
910
|
-
} catch {
|
|
911
|
-
this.logger.debug("Checkpoint failed during disconnect");
|
|
912
|
-
}
|
|
944
|
+
await this.checkpoint();
|
|
913
945
|
this.connection.closeSync();
|
|
914
946
|
this.connection = null;
|
|
915
947
|
this.logger.log("Disconnected from DuckDB");
|
|
@@ -918,6 +950,17 @@ class GraphService {
|
|
|
918
950
|
this.instance = null;
|
|
919
951
|
}
|
|
920
952
|
}
|
|
953
|
+
async checkpoint() {
|
|
954
|
+
if (!this.connection) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
try {
|
|
958
|
+
await this.connection.run("CHECKPOINT;");
|
|
959
|
+
this.logger.debug("Checkpoint completed");
|
|
960
|
+
} catch (error) {
|
|
961
|
+
this.logger.warn(`Checkpoint failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
921
964
|
async initializeSchema() {
|
|
922
965
|
if (!this.connection) {
|
|
923
966
|
throw new Error("Cannot initialize schema: not connected");
|
|
@@ -1207,7 +1250,7 @@ class SearchCommand extends CommandRunner3 {
|
|
|
1207
1250
|
const query = inputs[0];
|
|
1208
1251
|
const limit = Math.min(parseInt(options.limit || "20", 10), 100);
|
|
1209
1252
|
try {
|
|
1210
|
-
const queryEmbedding = await this.embeddingService.
|
|
1253
|
+
const queryEmbedding = await this.embeddingService.generateQueryEmbedding(query);
|
|
1211
1254
|
let results;
|
|
1212
1255
|
if (options.label) {
|
|
1213
1256
|
const labelResults = await this.graphService.vectorSearch(options.label, queryEmbedding, limit);
|
|
@@ -1384,7 +1427,7 @@ import { Command as Command4, CommandRunner as CommandRunner4, Option as Option3
|
|
|
1384
1427
|
|
|
1385
1428
|
// src/sync/manifest.service.ts
|
|
1386
1429
|
import { createHash as createHash2 } from "crypto";
|
|
1387
|
-
import { existsSync as
|
|
1430
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1388
1431
|
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
1389
1432
|
import { Injectable as Injectable8 } from "@nestjs/common";
|
|
1390
1433
|
|
|
@@ -1412,7 +1455,7 @@ class ManifestService {
|
|
|
1412
1455
|
}
|
|
1413
1456
|
async load() {
|
|
1414
1457
|
try {
|
|
1415
|
-
if (
|
|
1458
|
+
if (existsSync3(this.manifestPath)) {
|
|
1416
1459
|
const content = await readFile3(this.manifestPath, "utf-8");
|
|
1417
1460
|
this.manifest = SyncManifestSchema.parse(JSON.parse(content));
|
|
1418
1461
|
} else {
|
|
@@ -1898,7 +1941,7 @@ CascadeService = __legacyDecorateClassTS([
|
|
|
1898
1941
|
], CascadeService);
|
|
1899
1942
|
|
|
1900
1943
|
// src/sync/path-resolver.service.ts
|
|
1901
|
-
import { existsSync as
|
|
1944
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1902
1945
|
import { isAbsolute, resolve as resolve2 } from "path";
|
|
1903
1946
|
import { Injectable as Injectable10 } from "@nestjs/common";
|
|
1904
1947
|
class PathResolverService {
|
|
@@ -1920,7 +1963,7 @@ class PathResolverService {
|
|
|
1920
1963
|
if (requireInDocs && !this.isUnderDocs(resolvedPath)) {
|
|
1921
1964
|
throw new Error(`Path "${userPath}" resolves to "${resolvedPath}" which is outside the docs directory (${this.docsPath})`);
|
|
1922
1965
|
}
|
|
1923
|
-
if (requireExists && !
|
|
1966
|
+
if (requireExists && !existsSync4(resolvedPath)) {
|
|
1924
1967
|
throw new Error(`Path "${userPath}" does not exist (resolved to: ${resolvedPath})`);
|
|
1925
1968
|
}
|
|
1926
1969
|
return resolvedPath;
|
|
@@ -2048,10 +2091,13 @@ class SyncService {
|
|
|
2048
2091
|
}
|
|
2049
2092
|
if (!options.dryRun) {
|
|
2050
2093
|
result.entityEmbeddingsGenerated = await this.syncEntities(uniqueEntities, options);
|
|
2094
|
+
await this.graph.checkpoint();
|
|
2051
2095
|
if (options.verbose) {
|
|
2052
2096
|
this.logger.log(`Synced ${uniqueEntities.size} entities, generated ${result.entityEmbeddingsGenerated} embeddings`);
|
|
2053
2097
|
}
|
|
2054
2098
|
}
|
|
2099
|
+
const CHECKPOINT_BATCH_SIZE = 10;
|
|
2100
|
+
let processedCount = 0;
|
|
2055
2101
|
for (const change of changes) {
|
|
2056
2102
|
try {
|
|
2057
2103
|
const doc = docsByPath.get(change.path);
|
|
@@ -2074,12 +2120,19 @@ class SyncService {
|
|
|
2074
2120
|
if (change.embeddingGenerated) {
|
|
2075
2121
|
result.embeddingsGenerated++;
|
|
2076
2122
|
}
|
|
2123
|
+
processedCount++;
|
|
2124
|
+
if (!options.dryRun && processedCount % CHECKPOINT_BATCH_SIZE === 0) {
|
|
2125
|
+
await this.graph.checkpoint();
|
|
2126
|
+
}
|
|
2077
2127
|
} catch (error) {
|
|
2078
2128
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2079
2129
|
result.errors.push({ path: change.path, error: errorMessage });
|
|
2080
2130
|
this.logger.warn(`Error processing ${change.path}: ${errorMessage}`);
|
|
2081
2131
|
}
|
|
2082
2132
|
}
|
|
2133
|
+
if (!options.dryRun && processedCount > 0) {
|
|
2134
|
+
await this.graph.checkpoint();
|
|
2135
|
+
}
|
|
2083
2136
|
if (!options.dryRun) {
|
|
2084
2137
|
await this.manifest.save();
|
|
2085
2138
|
}
|