@gmickel/gno 1.18.0 → 1.19.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.
Files changed (129) hide show
  1. package/README.md +5 -3
  2. package/assets/skill/SKILL.md +27 -0
  3. package/package.json +2 -1
  4. package/spec/AGENTS.md +83 -0
  5. package/spec/CLAUDE.md +83 -0
  6. package/spec/bench-fixture.schema.json +137 -0
  7. package/spec/cli.md +2894 -0
  8. package/spec/db/schema.sql +442 -0
  9. package/spec/evals-agentic.md +510 -0
  10. package/spec/evals.md +1106 -0
  11. package/spec/mcp.md +2229 -0
  12. package/spec/output-schemas/activation-verification.schema.json +515 -0
  13. package/spec/output-schemas/ask.schema.json +366 -0
  14. package/spec/output-schemas/backlinks.schema.json +131 -0
  15. package/spec/output-schemas/bench-result.schema.json +120 -0
  16. package/spec/output-schemas/capture-receipt.schema.json +143 -0
  17. package/spec/output-schemas/collection-list.schema.json +45 -0
  18. package/spec/output-schemas/context-capsule-v1.schema.json +691 -0
  19. package/spec/output-schemas/context-capsule-verification.schema.json +1338 -0
  20. package/spec/output-schemas/context-list.schema.json +21 -0
  21. package/spec/output-schemas/doctor.schema.json +313 -0
  22. package/spec/output-schemas/error.schema.json +30 -0
  23. package/spec/output-schemas/expansion.schema.json +37 -0
  24. package/spec/output-schemas/get.schema.json +140 -0
  25. package/spec/output-schemas/graph-query.schema.json +99 -0
  26. package/spec/output-schemas/graph.schema.json +371 -0
  27. package/spec/output-schemas/links-list.schema.json +186 -0
  28. package/spec/output-schemas/mcp-add-collection-result.schema.json +23 -0
  29. package/spec/output-schemas/mcp-capture-result.schema.json +152 -0
  30. package/spec/output-schemas/mcp-http-error.schema.json +30 -0
  31. package/spec/output-schemas/mcp-job-list.schema.json +58 -0
  32. package/spec/output-schemas/mcp-job-status.schema.json +224 -0
  33. package/spec/output-schemas/mcp-remove-result.schema.json +39 -0
  34. package/spec/output-schemas/mcp-sync-result.schema.json +41 -0
  35. package/spec/output-schemas/mcp-tag-result.schema.json +33 -0
  36. package/spec/output-schemas/models-list.schema.json +93 -0
  37. package/spec/output-schemas/multi-get.schema.json +103 -0
  38. package/spec/output-schemas/process-status.schema.json +119 -0
  39. package/spec/output-schemas/query-diagnose.schema.json +123 -0
  40. package/spec/output-schemas/resident-status.schema.json +154 -0
  41. package/spec/output-schemas/retrieval-trace-common.schema.json +492 -0
  42. package/spec/output-schemas/retrieval-trace-delete.schema.json +16 -0
  43. package/spec/output-schemas/retrieval-trace-export.schema.json +61 -0
  44. package/spec/output-schemas/retrieval-trace-filters.schema.json +139 -0
  45. package/spec/output-schemas/retrieval-trace-judgment.schema.json +15 -0
  46. package/spec/output-schemas/retrieval-trace-list.schema.json +18 -0
  47. package/spec/output-schemas/retrieval-trace-payloads.schema.json +178 -0
  48. package/spec/output-schemas/retrieval-trace-purge.schema.json +31 -0
  49. package/spec/output-schemas/retrieval-trace-qrels.schema.json +303 -0
  50. package/spec/output-schemas/retrieval-trace-replay.schema.json +286 -0
  51. package/spec/output-schemas/retrieval-trace-show.schema.json +69 -0
  52. package/spec/output-schemas/retrieval-trace-summary.schema.json +65 -0
  53. package/spec/output-schemas/search-result.schema.json +154 -0
  54. package/spec/output-schemas/search-results.schema.json +338 -0
  55. package/spec/output-schemas/similar.schema.json +84 -0
  56. package/spec/output-schemas/status.schema.json +676 -0
  57. package/spec/output-schemas/tags-list.schema.json +48 -0
  58. package/src/app/context-runtime-types.ts +3 -0
  59. package/src/app/context-runtime.ts +15 -1
  60. package/src/cli/commands/ask.ts +106 -36
  61. package/src/cli/commands/context-build.ts +56 -9
  62. package/src/cli/commands/get.ts +64 -3
  63. package/src/cli/commands/query.ts +62 -23
  64. package/src/cli/commands/replay.ts +140 -0
  65. package/src/cli/commands/search.ts +48 -3
  66. package/src/cli/commands/shared.ts +3 -1
  67. package/src/cli/commands/trace.ts +200 -0
  68. package/src/cli/commands/vsearch.ts +75 -53
  69. package/src/cli/program.ts +255 -0
  70. package/src/config/index.ts +9 -0
  71. package/src/config/retrieval-traces.ts +56 -0
  72. package/src/config/types.ts +4 -0
  73. package/src/core/context-compiler.ts +11 -4
  74. package/src/core/retrieval-qrels.ts +405 -0
  75. package/src/core/retrieval-replay-candidate.ts +368 -0
  76. package/src/core/retrieval-replay-types.ts +109 -0
  77. package/src/core/retrieval-replay-validation.ts +89 -0
  78. package/src/core/retrieval-replay.ts +441 -0
  79. package/src/core/retrieval-trace-evidence-origin.ts +175 -0
  80. package/src/core/retrieval-trace-export.ts +113 -0
  81. package/src/core/retrieval-trace-filter-normalization.ts +27 -0
  82. package/src/core/retrieval-trace-filters.ts +19 -0
  83. package/src/core/retrieval-trace-management-helpers.ts +247 -0
  84. package/src/core/retrieval-trace-management-types.ts +132 -0
  85. package/src/core/retrieval-trace-management.ts +422 -0
  86. package/src/core/retrieval-trace-request.ts +141 -0
  87. package/src/core/retrieval-trace-session.ts +494 -0
  88. package/src/core/retrieval-trace.ts +472 -0
  89. package/src/mcp/tools/context.ts +59 -8
  90. package/src/mcp/tools/get.ts +35 -1
  91. package/src/mcp/tools/index.ts +74 -0
  92. package/src/mcp/tools/query.ts +95 -64
  93. package/src/mcp/tools/search.ts +36 -13
  94. package/src/mcp/tools/trace.ts +143 -0
  95. package/src/mcp/tools/vsearch.ts +71 -38
  96. package/src/pipeline/answer.ts +167 -26
  97. package/src/pipeline/graph-retrieval.ts +15 -1
  98. package/src/pipeline/hybrid.ts +151 -43
  99. package/src/pipeline/search.ts +36 -3
  100. package/src/pipeline/trace-metadata.ts +47 -0
  101. package/src/pipeline/types.ts +43 -0
  102. package/src/pipeline/vsearch.ts +101 -38
  103. package/src/sdk/client.ts +380 -71
  104. package/src/sdk/documents.ts +48 -1
  105. package/src/sdk/index.ts +17 -0
  106. package/src/sdk/types.ts +28 -0
  107. package/src/serve/context-capsule.ts +67 -8
  108. package/src/serve/public/app.tsx +12 -1
  109. package/src/serve/public/globals.built.css +1 -1
  110. package/src/serve/public/lib/workspace-tabs.ts +2 -0
  111. package/src/serve/public/pages/Dashboard.tsx +10 -0
  112. package/src/serve/public/pages/TraceHistory.tsx +478 -0
  113. package/src/serve/public/pages/trace-history-detail.tsx +224 -0
  114. package/src/serve/retrieval-trace.ts +28 -0
  115. package/src/serve/routes/api.ts +366 -72
  116. package/src/serve/routes/traces.ts +156 -0
  117. package/src/serve/server.ts +87 -2
  118. package/src/store/index.ts +31 -0
  119. package/src/store/migrations/014-retrieval-traces.ts +303 -0
  120. package/src/store/migrations/index.ts +2 -0
  121. package/src/store/retrieval-trace-codec.ts +384 -0
  122. package/src/store/sqlite/adapter.ts +153 -1
  123. package/src/store/sqlite/retrieval-trace-management-store.ts +341 -0
  124. package/src/store/sqlite/retrieval-trace-retention.ts +349 -0
  125. package/src/store/sqlite/retrieval-trace-rows.ts +267 -0
  126. package/src/store/sqlite/retrieval-trace-store.ts +515 -0
  127. package/src/store/types.ts +297 -0
  128. package/src/store/vector/sqlite-vec.ts +76 -1
  129. package/src/store/vector/types.ts +1 -1
@@ -346,6 +346,8 @@ export interface FtsSearchOptions {
346
346
  limit?: number;
347
347
  /** Filter by collection */
348
348
  collection?: string;
349
+ /** Internal exact relative-path boundary applied before ranking and LIMIT. */
350
+ relPathPrefix?: string;
349
351
  /**
350
352
  * Language hint (reserved for future use).
351
353
  * Note: FTS5 snowball tokenizer is language-aware at index time,
@@ -816,6 +818,220 @@ export interface ActivationIndexSnapshot {
816
818
  documents: ActivationIndexDocument[];
817
819
  }
818
820
 
821
+ // ─────────────────────────────────────────────────────────────────────────────
822
+ // Private Retrieval Trace Receipts
823
+ // ─────────────────────────────────────────────────────────────────────────────
824
+
825
+ export type RetrievalTraceRedactionMode = "metadata" | "replay";
826
+ export type RetrievalTraceTerminalStatus =
827
+ | "completed"
828
+ | "partial"
829
+ | "failed"
830
+ | "cancelled";
831
+ export type RetrievalTraceStatus = "open" | RetrievalTraceTerminalStatus;
832
+ export type RetrievalTraceJudgmentLabel =
833
+ | "relevant"
834
+ | "irrelevant"
835
+ | "missing_expected";
836
+ export type RetrievalTraceJudgmentTargetKind =
837
+ | "document"
838
+ | "chunk"
839
+ | "span"
840
+ | "query";
841
+ export type RetrievalTraceAppendResult = "inserted" | "duplicate";
842
+ export type RetrievalTraceRunKind = "retrieval" | "context" | "get";
843
+ export type RetrievalTraceEventKind =
844
+ | "query"
845
+ | "retrieval"
846
+ | "context"
847
+ | "get"
848
+ | "open"
849
+ | "cite"
850
+ | "pin"
851
+ | "capability"
852
+ | "complete";
853
+ export type RetrievalTraceExportFormat = "agentic-receipt" | "qrels";
854
+
855
+ export interface RetrievalTraceFingerprints {
856
+ pipeline: string;
857
+ model: string;
858
+ config: string;
859
+ index: string;
860
+ }
861
+
862
+ /** Already-redacted trace header persisted by StorePort implementations. */
863
+ export interface RetrievalTraceInput {
864
+ traceId: string;
865
+ schemaVersion: "1.0";
866
+ redactionMode: RetrievalTraceRedactionMode;
867
+ replayCapable: boolean;
868
+ queryText: string | null;
869
+ queryDigest: string | null;
870
+ queryShape: {
871
+ characters: number;
872
+ terms: number;
873
+ };
874
+ goalText: string | null;
875
+ goalDigest: string | null;
876
+ goalShape: {
877
+ characters: number;
878
+ terms: number;
879
+ };
880
+ filters: Record<string, unknown>;
881
+ fingerprints: RetrievalTraceFingerprints;
882
+ status: "open";
883
+ createdAtMs: number;
884
+ updatedAtMs: number;
885
+ expiresAtMs: number;
886
+ }
887
+
888
+ export type RetrievalTraceRow = Omit<
889
+ RetrievalTraceInput,
890
+ "status" | "updatedAtMs"
891
+ > & {
892
+ status: RetrievalTraceStatus;
893
+ updatedAtMs: number;
894
+ byteSize: number;
895
+ /** Digest of immutable creation fields; terminal status/time are excluded. */
896
+ creationDigest: string;
897
+ };
898
+
899
+ export interface RetrievalTraceRunInput {
900
+ runId: string;
901
+ traceId: string;
902
+ idempotencyKey: string;
903
+ kind: RetrievalTraceRunKind;
904
+ payload: Record<string, unknown>;
905
+ createdAtMs: number;
906
+ }
907
+
908
+ export type RetrievalTraceRunRow = RetrievalTraceRunInput & {
909
+ payloadBytes: number;
910
+ canonicalDigest: string;
911
+ };
912
+
913
+ export interface RetrievalTraceEventInput {
914
+ eventId: string;
915
+ traceId: string;
916
+ runId: string | null;
917
+ idempotencyKey: string;
918
+ kind: RetrievalTraceEventKind;
919
+ payload: Record<string, unknown>;
920
+ createdAtMs: number;
921
+ }
922
+
923
+ export type RetrievalTraceEventRow = RetrievalTraceEventInput & {
924
+ payloadBytes: number;
925
+ canonicalDigest: string;
926
+ };
927
+
928
+ export interface RetrievalTraceJudgmentInput {
929
+ judgmentId: string;
930
+ traceId: string;
931
+ runId: string | null;
932
+ idempotencyKey: string;
933
+ label: RetrievalTraceJudgmentLabel;
934
+ targetKind: RetrievalTraceJudgmentTargetKind;
935
+ targetRef: string;
936
+ target: Record<string, unknown>;
937
+ createdAtMs: number;
938
+ }
939
+
940
+ export type RetrievalTraceJudgmentRow = RetrievalTraceJudgmentInput & {
941
+ targetBytes: number;
942
+ canonicalDigest: string;
943
+ };
944
+
945
+ export interface RetrievalTraceExportInput {
946
+ exportId: string;
947
+ traceId: string;
948
+ format: RetrievalTraceExportFormat;
949
+ artifactHash: string;
950
+ createdAtMs: number;
951
+ }
952
+
953
+ export interface RetrievalTraceExportRow extends RetrievalTraceExportInput {}
954
+
955
+ export interface RetrievalTraceCursor {
956
+ createdAtMs: number;
957
+ traceId: string;
958
+ }
959
+
960
+ export interface RetrievalTraceExportManifestInput {
961
+ exportId: string;
962
+ traceIds: string[];
963
+ format: RetrievalTraceExportFormat;
964
+ artifactHash: string;
965
+ createdAtMs: number;
966
+ }
967
+
968
+ export interface RetrievalTraceExportManifestRow extends Omit<
969
+ RetrievalTraceExportManifestInput,
970
+ "traceIds"
971
+ > {
972
+ traceIds: string[];
973
+ }
974
+
975
+ export interface RetrievalTraceBundle {
976
+ trace: RetrievalTraceRow;
977
+ runs: RetrievalTraceRunRow[];
978
+ events: RetrievalTraceEventRow[];
979
+ judgments: RetrievalTraceJudgmentRow[];
980
+ exports: RetrievalTraceExportRow[];
981
+ }
982
+
983
+ /** One aggregate export identity and every complete linked trace bundle. */
984
+ export interface RetrievalTraceExportBundle {
985
+ manifest: RetrievalTraceExportManifestRow;
986
+ traces: RetrievalTraceBundle[];
987
+ }
988
+
989
+ export interface RetrievalTraceBundleTotals {
990
+ runs: number;
991
+ events: number;
992
+ judgments: number;
993
+ exports: number;
994
+ }
995
+
996
+ export interface RetrievalTraceBoundedBundle {
997
+ bundle: RetrievalTraceBundle;
998
+ totals: RetrievalTraceBundleTotals;
999
+ }
1000
+
1001
+ export interface RetrievalTraceRetentionPolicy {
1002
+ maxAgeDays: number;
1003
+ maxTraces: number;
1004
+ maxRecordsPerTrace: number;
1005
+ maxBytes: number;
1006
+ }
1007
+
1008
+ export interface RetrievalTraceDeleteCounts {
1009
+ traces: number;
1010
+ runs: number;
1011
+ events: number;
1012
+ judgments: number;
1013
+ exports: number;
1014
+ exportLinks: number;
1015
+ }
1016
+
1017
+ export interface RetrievalTraceRetentionResult {
1018
+ deleted: RetrievalTraceDeleteCounts;
1019
+ deletedTraceIds: string[];
1020
+ remainingTraces: number;
1021
+ remainingBytes: number;
1022
+ }
1023
+
1024
+ export type RetrievalTracePhysicalCleanupStatus =
1025
+ | "completed"
1026
+ | "wal_busy"
1027
+ | "failed";
1028
+
1029
+ export interface RetrievalTracePurgeResult extends RetrievalTraceDeleteCounts {
1030
+ physicalCleanup: RetrievalTracePhysicalCleanupStatus;
1031
+ checkpointedFrames: number;
1032
+ remainingWalFrames: number;
1033
+ }
1034
+
819
1035
  // ─────────────────────────────────────────────────────────────────────────────
820
1036
  // Transaction Types
821
1037
  // ─────────────────────────────────────────────────────────────────────────────
@@ -925,6 +1141,87 @@ export interface StorePort {
925
1141
  receipt: ActivationVerificationReceipt
926
1142
  ): Promise<StoreResult<void>>;
927
1143
 
1144
+ /** Persist an already-redacted, versioned retrieval trace header. */
1145
+ createRetrievalTrace(
1146
+ trace: RetrievalTraceInput
1147
+ ): Promise<StoreResult<RetrievalTraceAppendResult>>;
1148
+
1149
+ /** Return a trace and all of its locally stored subordinate records. */
1150
+ getRetrievalTrace(
1151
+ traceId: string
1152
+ ): Promise<StoreResult<RetrievalTraceBundle | null>>;
1153
+
1154
+ /** Read bounded subordinate detail while returning exact aggregate counts. */
1155
+ getBoundedRetrievalTrace(
1156
+ traceId: string,
1157
+ detailLimit: number
1158
+ ): Promise<StoreResult<RetrievalTraceBoundedBundle | null>>;
1159
+
1160
+ /** List trace headers newest-first with a bounded caller-selected limit. */
1161
+ listRetrievalTraces(
1162
+ limit: number,
1163
+ cursor?: RetrievalTraceCursor
1164
+ ): Promise<StoreResult<RetrievalTraceRow[]>>;
1165
+
1166
+ /** Transition an open trace to one explicit terminal outcome idempotently. */
1167
+ finalizeRetrievalTrace(
1168
+ traceId: string,
1169
+ status: RetrievalTraceTerminalStatus,
1170
+ updatedAtMs: number
1171
+ ): Promise<StoreResult<RetrievalTraceAppendResult>>;
1172
+
1173
+ /** Append a run once per trace-scoped idempotency key. */
1174
+ appendRetrievalTraceRun(
1175
+ run: RetrievalTraceRunInput
1176
+ ): Promise<StoreResult<RetrievalTraceAppendResult>>;
1177
+
1178
+ /** Append an event once per trace-scoped idempotency key. */
1179
+ appendRetrievalTraceEvent(
1180
+ event: RetrievalTraceEventInput
1181
+ ): Promise<StoreResult<RetrievalTraceAppendResult>>;
1182
+
1183
+ /** Append an explicit judgment once per trace-scoped idempotency key. */
1184
+ appendRetrievalTraceJudgment(
1185
+ judgment: RetrievalTraceJudgmentInput
1186
+ ): Promise<StoreResult<RetrievalTraceAppendResult>>;
1187
+
1188
+ /** Record a locally produced explicit export receipt idempotently. */
1189
+ appendRetrievalTraceExport(
1190
+ traceExport: RetrievalTraceExportInput
1191
+ ): Promise<StoreResult<RetrievalTraceAppendResult>>;
1192
+
1193
+ /** Record one export manifest and all sorted trace memberships atomically. */
1194
+ appendRetrievalTraceExportManifest(
1195
+ manifest: RetrievalTraceExportManifestInput
1196
+ ): Promise<StoreResult<RetrievalTraceAppendResult>>;
1197
+
1198
+ /** Read one aggregate export manifest with stable sorted membership. */
1199
+ getRetrievalTraceExportManifest(
1200
+ exportId: string
1201
+ ): Promise<StoreResult<RetrievalTraceExportManifestRow | null>>;
1202
+
1203
+ /** Read one export and all linked traces without bounded-detail truncation. */
1204
+ getRetrievalTraceExportBundle(
1205
+ exportId: string
1206
+ ): Promise<StoreResult<RetrievalTraceExportBundle | null>>;
1207
+
1208
+ /** Durable random index-local secret used only to redact metadata labels. */
1209
+ getOrCreateRetrievalTraceRedactionSecret(): Promise<StoreResult<string>>;
1210
+
1211
+ /** Delete one trace and report exact cascade counts. */
1212
+ deleteRetrievalTrace(
1213
+ traceId: string
1214
+ ): Promise<StoreResult<RetrievalTraceDeleteCounts>>;
1215
+
1216
+ /** Delete every trace and subordinate record in one transaction. */
1217
+ purgeRetrievalTraces(): Promise<StoreResult<RetrievalTracePurgeResult>>;
1218
+
1219
+ /** Apply deterministic time, row, and byte retention limits. */
1220
+ enforceRetrievalTraceRetention(
1221
+ policy: RetrievalTraceRetentionPolicy,
1222
+ nowMs: number
1223
+ ): Promise<StoreResult<RetrievalTraceRetentionResult>>;
1224
+
928
1225
  // ─────────────────────────────────────────────────────────────────────────
929
1226
  // Documents
930
1227
  // ─────────────────────────────────────────────────────────────────────────
@@ -74,6 +74,16 @@ function formatUnavailableMessage(loadError?: string): string {
74
74
  return `Vector search requires sqlite-vec. Embeddings are stored, but KNN search is disabled.${reason} ${SQLITE_VEC_GUIDANCE}`;
75
75
  }
76
76
 
77
+ const ALLOWED_HASH_BATCH_SIZE = 800;
78
+
79
+ const compareVectorResults = (
80
+ left: VectorSearchResult,
81
+ right: VectorSearchResult
82
+ ): number =>
83
+ left.distance - right.distance ||
84
+ left.mirrorHash.localeCompare(right.mirrorHash) ||
85
+ left.seq - right.seq;
86
+
77
87
  /**
78
88
  * Create a VectorIndexPort for a specific model.
79
89
  * sqlite-vec is optional - storage works without it, search disabled.
@@ -243,15 +253,80 @@ export async function createVectorIndexPort(
243
253
  searchNearest(
244
254
  embedding: Float32Array,
245
255
  k: number,
246
- searchOptions?: { minScore?: number }
256
+ searchOptions?: {
257
+ minScore?: number;
258
+ allowedMirrorHashes?: string[];
259
+ }
247
260
  ): Promise<StoreResult<VectorSearchResult[]>> {
248
261
  if (!(searchAvailable && searchStmt)) {
249
262
  return Promise.resolve(
250
263
  err("VEC_SEARCH_UNAVAILABLE", formatUnavailableMessage(loadError))
251
264
  );
252
265
  }
266
+ if (!Number.isSafeInteger(k) || k < 1) {
267
+ return Promise.resolve(
268
+ err("INVALID_INPUT", "Vector search limit must be a positive integer")
269
+ );
270
+ }
253
271
 
254
272
  try {
273
+ const allowed = searchOptions?.allowedMirrorHashes;
274
+ if (allowed) {
275
+ const hashes = [
276
+ ...new Set(allowed.filter((hash) => hash.length > 0)),
277
+ ].sort();
278
+ if (hashes.length === 0) return Promise.resolve(ok([]));
279
+ const distanceFunction =
280
+ distanceMetric === "cosine"
281
+ ? "vec_distance_cosine"
282
+ : "vec_distance_L2";
283
+ const scoped: VectorSearchResult[] = [];
284
+ for (
285
+ let index = 0;
286
+ index < hashes.length;
287
+ index += ALLOWED_HASH_BATCH_SIZE
288
+ ) {
289
+ const batch = hashes.slice(index, index + ALLOWED_HASH_BATCH_SIZE);
290
+ const placeholders = batch.map(() => "?").join(",");
291
+ const rows = db
292
+ .query<
293
+ {
294
+ mirror_hash: string;
295
+ seq: number;
296
+ distance: number;
297
+ },
298
+ (Uint8Array | string | number)[]
299
+ >(
300
+ `SELECT mirror_hash, seq,
301
+ ${distanceFunction}(embedding, ?) AS distance
302
+ FROM content_vectors
303
+ WHERE model = ?
304
+ AND mirror_hash IN (${placeholders})
305
+ ORDER BY distance, mirror_hash, seq
306
+ LIMIT ?`
307
+ )
308
+ .all(encodeEmbedding(embedding), model, ...batch, k);
309
+ scoped.push(
310
+ ...rows.map((row) => ({
311
+ mirrorHash: row.mirror_hash,
312
+ seq: row.seq,
313
+ distance: row.distance,
314
+ }))
315
+ );
316
+ }
317
+ const minScore = searchOptions.minScore;
318
+ return Promise.resolve(
319
+ ok(
320
+ scoped
321
+ .sort(compareVectorResults)
322
+ .filter(
323
+ (row) =>
324
+ minScore === undefined || 1 - row.distance >= minScore
325
+ )
326
+ .slice(0, k)
327
+ )
328
+ );
329
+ }
255
330
  const results = searchStmt.all(encodeEmbedding(embedding), k) as {
256
331
  chunk_id: string;
257
332
  distance: number;
@@ -84,7 +84,7 @@ export interface VectorIndexPort {
84
84
  searchNearest(
85
85
  embedding: Float32Array,
86
86
  k: number,
87
- options?: { minScore?: number }
87
+ options?: { minScore?: number; allowedMirrorHashes?: string[] }
88
88
  ): Promise<StoreResult<VectorSearchResult[]>>;
89
89
 
90
90
  // ─────────────────────────────────────────────────────────────────────────