@remit/search-service 0.0.1

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.
Files changed (39) hide show
  1. package/package.json +66 -0
  2. package/src/anchor.test.ts +164 -0
  3. package/src/anchor.ts +127 -0
  4. package/src/backends/bedrock.test.ts +148 -0
  5. package/src/backends/bedrock.ts +105 -0
  6. package/src/backends/memory.test.ts +168 -0
  7. package/src/backends/memory.ts +152 -0
  8. package/src/backends/pgvector.integ.test.ts +174 -0
  9. package/src/backends/pgvector.ts +306 -0
  10. package/src/backends/runtime-import.ts +16 -0
  11. package/src/backends/s3-vectors.test.ts +929 -0
  12. package/src/backends/s3-vectors.ts +383 -0
  13. package/src/backends/sqlite-vec.integ.test.ts +144 -0
  14. package/src/backends/sqlite-vec.ts +250 -0
  15. package/src/bedrock.ts +4 -0
  16. package/src/chunking/chunker.test.ts +79 -0
  17. package/src/chunking/chunker.ts +56 -0
  18. package/src/chunking/entities.test.ts +82 -0
  19. package/src/chunking/entities.ts +74 -0
  20. package/src/chunking/entropy.test.ts +98 -0
  21. package/src/chunking/entropy.ts +161 -0
  22. package/src/chunking/keys.ts +22 -0
  23. package/src/chunking/structured.test.ts +120 -0
  24. package/src/chunking/structured.ts +79 -0
  25. package/src/content-hash.test.ts +27 -0
  26. package/src/content-hash.ts +10 -0
  27. package/src/embeddings.test.ts +28 -0
  28. package/src/embeddings.ts +149 -0
  29. package/src/from-env.test.ts +62 -0
  30. package/src/from-env.ts +130 -0
  31. package/src/index.ts +71 -0
  32. package/src/pgvector.ts +4 -0
  33. package/src/s3-vectors.ts +5 -0
  34. package/src/search.test.ts +772 -0
  35. package/src/search.ts +395 -0
  36. package/src/semantic-search.integ.test.ts +130 -0
  37. package/src/sqlite-vec.ts +4 -0
  38. package/src/types.ts +155 -0
  39. package/tsconfig.json +8 -0
@@ -0,0 +1,130 @@
1
+ import type { DataType } from "@huggingface/transformers";
2
+ import { BedrockEmbeddingService } from "./backends/bedrock.js";
3
+ import type { VectorStoreService } from "./backends/memory.js";
4
+ import { createMemoryVectorStore } from "./backends/memory.js";
5
+ import { createPgVectorStore } from "./backends/pgvector.js";
6
+ import { createS3VectorsBackend } from "./backends/s3-vectors.js";
7
+ import { createSqliteVectorStore } from "./backends/sqlite-vec.js";
8
+ import {
9
+ createDeterministicEmbeddingService,
10
+ createLocalEmbeddingService,
11
+ type EmbeddingService,
12
+ } from "./embeddings.js";
13
+
14
+ const parseDimensions = (): number | undefined => {
15
+ const raw = process.env.SEARCH_EMBEDDING_DIMENSIONS;
16
+ if (!raw) return undefined;
17
+ const parsed = Number(raw);
18
+ if (!Number.isInteger(parsed) || parsed <= 0) {
19
+ throw new Error(
20
+ `SEARCH_EMBEDDING_DIMENSIONS must be a positive integer, got: ${raw}`,
21
+ );
22
+ }
23
+ return parsed;
24
+ };
25
+
26
+ const DTYPES: readonly DataType[] = [
27
+ "auto",
28
+ "fp32",
29
+ "fp16",
30
+ "q8",
31
+ "int8",
32
+ "uint8",
33
+ "q4",
34
+ "bnb4",
35
+ "q4f16",
36
+ "q2",
37
+ "q2f16",
38
+ "q1",
39
+ "q1f16",
40
+ ];
41
+
42
+ const parseDtype = (): DataType | undefined => {
43
+ const raw = process.env.SEARCH_EMBEDDING_DTYPE;
44
+ if (!raw) return undefined;
45
+ if (!DTYPES.includes(raw as DataType)) {
46
+ throw new Error(
47
+ `SEARCH_EMBEDDING_DTYPE must be one of ${DTYPES.join(", ")}, got: ${raw}`,
48
+ );
49
+ }
50
+ return raw as DataType;
51
+ };
52
+
53
+ /**
54
+ * Select a vector store from the environment, shared by every process that
55
+ * composes a SearchService (the API, the search-index worker, the local
56
+ * indexing shim) so the selection rule lives in one place:
57
+ *
58
+ * - `DATA_BACKEND=postgres` + `PG_CONNECTION_URL` set → pgvector (Postgres parity).
59
+ * - `LOCAL_VECTORDB_PATH` set → persistent sqlite-vec (local dev).
60
+ * - `S3_VECTORS_BUCKET_NAME` + `S3_VECTORS_INDEX_NAME` set → S3 Vectors (prod).
61
+ * - otherwise → in-memory store (unit tests / default).
62
+ *
63
+ * `dimensions` should be the embedding service's dimension count. When a
64
+ * dimension-typed store is selected (sqlite-vec's vec0 table, pgvector's
65
+ * `VECTOR(n)` column), it is created with that dimension so the store and
66
+ * embedder always agree instead of failing confusingly at insert time (e.g. a
67
+ * 64-dim deterministic embedder writing into a 384-wide column).
68
+ */
69
+ export const buildVectorStoreFromEnv = (
70
+ dimensions?: number,
71
+ ): VectorStoreService => {
72
+ const pgConnectionUrl = process.env.PG_CONNECTION_URL;
73
+ if (process.env.DATA_BACKEND === "postgres" && pgConnectionUrl) {
74
+ return createPgVectorStore({
75
+ connectionString: pgConnectionUrl,
76
+ dimensions,
77
+ });
78
+ }
79
+ const localPath = process.env.LOCAL_VECTORDB_PATH;
80
+ if (localPath) {
81
+ return createSqliteVectorStore({ path: localPath, dimensions });
82
+ }
83
+ const bucket = process.env.S3_VECTORS_BUCKET_NAME;
84
+ const indexName = process.env.S3_VECTORS_INDEX_NAME;
85
+ if (bucket && indexName) {
86
+ return createS3VectorsBackend({
87
+ vectorBucketName: bucket,
88
+ indexName,
89
+ region: process.env.AWS_REGION,
90
+ });
91
+ }
92
+ return createMemoryVectorStore();
93
+ };
94
+
95
+ /**
96
+ * Select an embedder from the environment, mirroring `buildVectorStoreFromEnv`:
97
+ *
98
+ * - `SEARCH_EMBEDDING_PROVIDER=local` → Transformers.js model (local dev). The
99
+ * model is `SEARCH_EMBEDDING_MODEL_ID` (default MiniLM); the Postgres-parity
100
+ * stack points it at a multilingual MiniLM so the ~50% non-English mail corpus
101
+ * embeds well. Both models are 384-dim, so the pgvector column is stable.
102
+ * - `SEARCH_EMBEDDING_PROVIDER=bedrock` → Bedrock Titan (prod).
103
+ * - otherwise → deterministic bag-of-words embedder (unit tests / default).
104
+ *
105
+ * `SEARCH_EMBEDDING_DIMENSIONS`, when set, pins the dimension count for the local
106
+ * and deterministic embedders so the store's vector column and the embedder
107
+ * agree regardless of which embedder a given process runs.
108
+ *
109
+ * `SEARCH_EMBEDDING_DTYPE`, when set, selects the ONNX weight precision the local
110
+ * model loads (`q8` → int8-quantized `model_quantized.onnx`); unset defaults to
111
+ * `fp32`. The search-index-worker container sets `q8` and bakes the matching file.
112
+ */
113
+ export const buildEmbeddingServiceFromEnv = (): EmbeddingService => {
114
+ const provider = process.env.SEARCH_EMBEDDING_PROVIDER;
115
+ const dimensions = parseDimensions();
116
+ if (provider === "local") {
117
+ return createLocalEmbeddingService({
118
+ modelId: process.env.SEARCH_EMBEDDING_MODEL_ID,
119
+ dimensions,
120
+ dtype: parseDtype(),
121
+ });
122
+ }
123
+ if (provider === "bedrock") {
124
+ return new BedrockEmbeddingService({
125
+ region: process.env.AWS_REGION,
126
+ modelId: process.env.SEARCH_EMBEDDING_MODEL_ID,
127
+ });
128
+ }
129
+ return createDeterministicEmbeddingService({ dimensions });
130
+ };
package/src/index.ts ADDED
@@ -0,0 +1,71 @@
1
+ export {
2
+ type AnchorBuildDeps,
3
+ type AnchorBuildParams,
4
+ type AnchorPayload,
5
+ buildAnchorSourceText,
6
+ buildMessageAnchor,
7
+ poolChunkVectors,
8
+ } from "./anchor.js";
9
+ export {
10
+ createMemoryVectorStore,
11
+ MemoryVectorStore,
12
+ type VectorStoreService,
13
+ } from "./backends/memory.js";
14
+ export {
15
+ type ChunkInput,
16
+ createEmailChunker,
17
+ type EmailChunker,
18
+ } from "./chunking/chunker.js";
19
+ export {
20
+ buildEntityChunks,
21
+ type ExtractedEntities,
22
+ extractEntities,
23
+ } from "./chunking/entities.js";
24
+ export {
25
+ buildBodyChunks,
26
+ shannonEntropy,
27
+ stripBoilerplate,
28
+ } from "./chunking/entropy.js";
29
+ export {
30
+ buildStructuredChunks,
31
+ extractAttachmentFileTypes,
32
+ } from "./chunking/structured.js";
33
+ export { computeContentHash } from "./content-hash.js";
34
+ export {
35
+ createDeterministicEmbeddingService,
36
+ createLocalEmbeddingService,
37
+ type DeterministicEmbeddingConfig,
38
+ DeterministicEmbeddingService,
39
+ type EmbeddingService,
40
+ type LocalEmbeddingConfig,
41
+ LocalEmbeddingService,
42
+ } from "./embeddings.js";
43
+ export {
44
+ createSearchService,
45
+ DefaultSearchService,
46
+ literalMatchScore,
47
+ rerank,
48
+ type SearchService,
49
+ type SearchServiceConfig,
50
+ tokenizeQuery,
51
+ type UpsertOptions,
52
+ type UpsertResult,
53
+ } from "./search.js";
54
+ export type {
55
+ AttachmentChunkInput,
56
+ Chunk,
57
+ ChunkMetadata,
58
+ ChunkType,
59
+ EnvelopeChunkAddress,
60
+ EnvelopeChunkInput,
61
+ IndexEmailParams,
62
+ ParsedBodyForChunking,
63
+ SearchIndexMessage,
64
+ SearchParams,
65
+ SearchResult,
66
+ VectorMatch,
67
+ VectorQuery,
68
+ VectorQueryFilter,
69
+ VectorRecord,
70
+ } from "./types.js";
71
+ export { searchIndexMessageSchema } from "./types.js";
@@ -0,0 +1,4 @@
1
+ export {
2
+ createPgVectorStore,
3
+ type PgVectorStoreConfig,
4
+ } from "./backends/pgvector.js";
@@ -0,0 +1,5 @@
1
+ export {
2
+ createS3VectorsBackend,
3
+ S3VectorsBackend,
4
+ type S3VectorsBackendConfig,
5
+ } from "./backends/s3-vectors.js";