@littlebigbrain/client 0.7.0 → 0.8.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.
package/dist/client.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { parseSparqlResults } from "./types.js";
2
2
  import { bodyMarksTerminal, errorCodeFromBody, fullJitterBackoffMs, parseLbbError, parseResponseJson, retryAllowed, retryableStatus, retryDelayMs, sleep, } from "./transport.js";
3
- import { ContextNamespace, EntityNamespace, GraphNamespace, IndexNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
3
+ import { ContextNamespace, EntityNamespace, GraphNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
4
4
  export { parseSparqlResults } from "./types.js";
5
5
  export { LbbError } from "./transport.js";
6
- export { ContextNamespace, EntityNamespace, FactsNamespace, GraphNamespace, IndexNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
6
+ export { ContextNamespace, EntityNamespace, FactsNamespace, GraphNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
7
7
  /**
8
8
  * A typed HTTP client for a little big brain graph server. One instance is scoped to a
9
9
  * single graph/branch; construct another for a different scope. All methods
@@ -24,9 +24,10 @@ export class LbbClient {
24
24
  onRequest;
25
25
  onResponse;
26
26
  onRetry;
27
+ /** A5 default read consistency applied when a read omits its own value. */
28
+ defaultConsistency;
27
29
  context;
28
30
  search;
29
- indexes;
30
31
  entities;
31
32
  schema;
32
33
  ontology;
@@ -41,7 +42,7 @@ export class LbbClient {
41
42
  this.graphName = options.graph;
42
43
  this.branchName = options.branch;
43
44
  this.stack = options.stack;
44
- this.apiVersion = options.apiVersion ?? "2026-06-22";
45
+ this.apiVersion = options.apiVersion ?? "2026-07-23";
45
46
  this.maxRetries = options.maxRetries ?? 6;
46
47
  this.retryDelayMs = options.retryDelayMs ?? 100;
47
48
  this.retryBudgetMs = options.retryBudgetMs ?? 60_000;
@@ -49,6 +50,7 @@ export class LbbClient {
49
50
  this.onRequest = options.onRequest;
50
51
  this.onResponse = options.onResponse;
51
52
  this.onRetry = options.onRetry;
53
+ this.defaultConsistency = options.defaultConsistency;
52
54
  if (!Number.isInteger(this.maxRetries) || this.maxRetries < 0) {
53
55
  throw new RangeError("maxRetries must be a non-negative integer");
54
56
  }
@@ -69,7 +71,6 @@ export class LbbClient {
69
71
  this.fetchImpl = chosen;
70
72
  this.context = new ContextNamespace(this);
71
73
  this.search = new SearchNamespace(this);
72
- this.indexes = new IndexNamespace(this);
73
74
  this.entities = new EntityNamespace(this);
74
75
  this.schema = new SchemaNamespace(this);
75
76
  this.ontology = new OntologyNamespace(this);
@@ -103,8 +104,38 @@ export class LbbClient {
103
104
  onRequest: this.onRequest,
104
105
  onResponse: this.onResponse,
105
106
  onRetry: this.onRetry,
107
+ defaultConsistency: this.defaultConsistency,
106
108
  });
107
109
  }
110
+ /**
111
+ * A5: fold read-consistency options into a request body's own `consistency` /
112
+ * `min_indexed_seq` fields (the shape used by full-text, embedding, and
113
+ * structured-SPARQL bodies). A per-call value wins over the client
114
+ * `defaultConsistency`; an explicit body field wins over both.
115
+ */
116
+ resolveConsistency(opts) {
117
+ return opts?.consistency ?? this.defaultConsistency;
118
+ }
119
+ mergeReadConsistency(body, opts) {
120
+ const consistency = this.resolveConsistency(opts);
121
+ const merged = { ...body };
122
+ if (consistency !== undefined && merged.consistency === undefined) {
123
+ merged.consistency = consistency;
124
+ }
125
+ if (opts?.minIndexedSeq !== undefined &&
126
+ merged.min_indexed_seq === undefined) {
127
+ merged.min_indexed_seq = opts.minIndexedSeq;
128
+ }
129
+ return merged;
130
+ }
131
+ /** A5: read-consistency options rendered as URL query params, for the routes
132
+ * that carry consistency on the URL (SPARQL-text, graph summary). */
133
+ readConsistencyQuery(opts) {
134
+ return {
135
+ consistency: this.resolveConsistency(opts),
136
+ min_indexed_seq: opts?.minIndexedSeq,
137
+ };
138
+ }
108
139
  buildUrl(path, query) {
109
140
  const params = [];
110
141
  const push = (key, value) => params.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
@@ -292,11 +323,14 @@ export class LbbClient {
292
323
  }
293
324
  // --- writes ---
294
325
  /** Commit triplets and optional entity embeddings. Prefer `client.graph("main").facts.create(...)`. */
295
- commit(body, opts = {}) {
296
- return this.request("POST", "/v1/graph/commit", {
326
+ async commit(body, opts = {}) {
327
+ const response = await this.request("POST", "/v1/graph/commit", {
297
328
  body,
298
329
  idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("facts.create"),
299
330
  });
331
+ // A5: surface the committed sequence as `commitSeq` so the write→floor→read
332
+ // loop reads naturally: `const { commitSeq } = await client.commit(…)`.
333
+ return { ...response, commitSeq: response.commit_seq };
300
334
  }
301
335
  /**
302
336
  * Validate-only preflight: run the same ontology/schema validation a real
@@ -318,28 +352,28 @@ export class LbbClient {
318
352
  * streamed request without a single oversized commit. Pass `lines` as an array
319
353
  * (serialized to NDJSON here) or a pre-built NDJSON string.
320
354
  *
321
- * Set `index: true` to run one full index build after the last batch, so the
322
- * data is served from the persisted runs (not just the ephemeral snapshot
323
- * fallback) by the time the call returns — the "bulk load, queryable on return"
324
- * path. Prefer this over indexing per batch (which serializes builds and races
325
- * the throttle): import the whole dataset, index once. The response's `index`
326
- * object reports whether the build ran or was skipped.
355
+ * A successful import durably enqueues one complete published-generation
356
+ * build after the final batch. It does not build index families or wait for
357
+ * visibility; the response's `published_generation` object carries the
358
+ * durable job and due sequence to observe.
327
359
  */
328
- import(lines, opts = {}) {
360
+ async import(lines, opts = {}) {
329
361
  const ndjson = typeof lines === "string"
330
362
  ? lines
331
363
  : lines.map((line) => JSON.stringify(line)).join("\n");
332
- return this.request("POST", "/v1/graph/import", {
364
+ const response = await this.request("POST", "/v1/graph/import", {
333
365
  rawBody: ndjson,
334
366
  contentType: "application/x-ndjson",
335
367
  query: {
336
368
  batch: opts.batch,
337
369
  strict: opts.strict,
338
370
  observed_at: opts.observedAt,
339
- index: opts.index,
340
371
  },
341
372
  idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("import"),
342
373
  });
374
+ // A5: surface the last committed sequence (null for an empty import) so the
375
+ // write→floor→read loop reads naturally after a bulk load.
376
+ return { ...response, commitSeq: response.committed_commit_seq ?? null };
343
377
  }
344
378
  /**
345
379
  * Bulk-ingest N-Triples, Turtle, N-Quads, or TriG without client-side conversion. Resource-object
@@ -371,19 +405,6 @@ export class LbbClient {
371
405
  idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("import-rdf"),
372
406
  });
373
407
  }
374
- /** Export the snapshot-visible RDF projection as Turtle, N-Triples, TriG, or N-Quads. */
375
- exportRdf(opts = {}) {
376
- return this.request("GET", "/v1/graph/export/rdf", {
377
- query: {
378
- format: opts.format === "ntriples" ? "nt" : opts.format,
379
- max_triples: opts.maxTriples,
380
- as_of_valid_time: opts.asOfValidTime,
381
- as_of_commit_seq: opts.asOfCommitSeq,
382
- entailment: opts.entailment,
383
- reason: opts.reason,
384
- },
385
- });
386
- }
387
408
  /**
388
409
  * Retract specific edges and/or every edge touching given entities. Appends
389
410
  * superseding retract events rather than deleting — history stays visible in an
@@ -601,23 +622,19 @@ export class LbbClient {
601
622
  query: { kind: opts.kind, run: opts.run },
602
623
  });
603
624
  }
604
- /**
605
- * Champion vs challenger retrieval over one pinned snapshot. Returns
606
- * promotion evidence (hit-rate@k, latency, overlap); never promotes.
607
- */
608
- shadowEval(body) {
609
- return this.request("POST", "/v1/models/shadow-eval", { body });
610
- }
611
- /**
612
- * Execution-verified QA probes generated from the graph's current edges —
613
- * labels are the executed projections, so they are verified by construction.
614
- * Feeds `shadowEval` directly.
615
- */
625
+ /** Execution-verified QA probes generated from the graph's current edges. */
616
626
  syntheticEval(opts = {}) {
617
627
  return this.request("GET", "/v1/models/synthetic-eval", {
618
628
  query: { limit: opts.limit },
619
629
  });
620
630
  }
631
+ /**
632
+ * Compare champion and challenger retrieval over one pinned published
633
+ * snapshot. The endpoint returns promotion evidence but never promotes.
634
+ */
635
+ shadowEval(body) {
636
+ return this.request("POST", "/v1/models/shadow-eval", { body });
637
+ }
621
638
  /** The doubling retrain policy: is a retrain due for this model kind? */
622
639
  modelCadence(opts) {
623
640
  return this.request("GET", "/v1/models/cadence", {
@@ -643,18 +660,6 @@ export class LbbClient {
643
660
  setTrainingConfig(body) {
644
661
  return this.request("POST", "/v1/models/training-config", { body });
645
662
  }
646
- /**
647
- * Verdict on an ask (`accepted` | `rejected` | `corrected` + the right
648
- * plan), joined to the ask's trace by `ask_id` — the planner fine-tune's
649
- * explicit feedback capture. `accepted: false` in the response means
650
- * signal capture is off on this deployment (the contract is identical).
651
- */
652
- askFeedback(body, opts = {}) {
653
- return this.request("POST", "/v1/ask/feedback", {
654
- body,
655
- idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("ask-feedback"),
656
- });
657
- }
658
663
  ingestSignals(body, opts = {}) {
659
664
  return this.request("POST", "/v1/signals", {
660
665
  body,
@@ -679,39 +684,25 @@ export class LbbClient {
679
684
  ],
680
685
  }, opts);
681
686
  }
682
- /**
683
- * The planner fine-tune's training feed: accepted/corrected feedback
684
- * joined to its traces (signals ≤ the split pin), topped up with
685
- * execution-verified synthetic plans.
686
- */
687
+ /** Planner training examples at or before an optional signal split. */
687
688
  plannerDataset(opts = {}) {
688
689
  return this.request("GET", "/v1/models/planner-dataset", {
689
690
  query: { limit: opts.limit, split_seq: opts.splitSeq },
690
691
  });
691
692
  }
692
- /**
693
- * The DPO pass's training feed: preference pairs from corrected verdicts,
694
- * paired rejections, and synthetic corrupted-slot pairs.
695
- */
693
+ /** Planner preference pairs at or before an optional signal split. */
696
694
  plannerPreferenceDataset(opts = {}) {
697
695
  return this.request("GET", "/v1/models/planner-preference-dataset", {
698
696
  query: { limit: opts.limit, split_seq: opts.splitSeq },
699
697
  });
700
698
  }
701
- /**
702
- * The suggest-ranker trainer's probe feed: `suggestion_adopted` signals
703
- * (typed prefix + adopted text) ≤ the split pin, topped up with
704
- * execution-verified synthetic vocabulary pairs.
705
- */
699
+ /** Suggest-ranker examples at or before an optional signal split. */
706
700
  suggestDataset(opts = {}) {
707
701
  return this.request("GET", "/v1/models/suggest-dataset", {
708
702
  query: { limit: opts.limit, split_seq: opts.splitSeq },
709
703
  });
710
704
  }
711
- /**
712
- * The extractor fine-tune's training feed: EPISODE transcripts joined to
713
- * the facts the observe pipeline committed from them.
714
- */
705
+ /** Extractor examples at or before an optional signal split. */
715
706
  extractorDataset(opts = {}) {
716
707
  return this.request("GET", "/v1/models/extractor-dataset", {
717
708
  query: { limit: opts.limit, split_seq: opts.splitSeq },
@@ -729,8 +720,7 @@ export class LbbClient {
729
720
  }
730
721
  /**
731
722
  * Promote a finished `planner_lora` training run: gated on held-out slot
732
- * exactness, recorded as a `kind=planner` training run whose adapter `/v1/ask`
733
- * then serves.
723
+ * exactness and recorded as a `kind=planner` training run.
734
724
  */
735
725
  promotePlanner(opts) {
736
726
  return this.request("POST", "/v1/models/promote-planner", {
@@ -739,8 +729,15 @@ export class LbbClient {
739
729
  }
740
730
  // --- search ---
741
731
  /** Full semantic hybrid search from a request body (`POST /v1/graph/search`). */
742
- graphSearch(body) {
743
- return this.request("POST", "/v1/graph/search", { body });
732
+ graphSearch(body, opts) {
733
+ // Consistency for hybrid graph search lives on the nested `search` options.
734
+ const consistency = this.resolveConsistency(opts);
735
+ const search = consistency !== undefined || opts?.minIndexedSeq !== undefined
736
+ ? this.mergeReadConsistency(body.search ?? {}, opts)
737
+ : body.search;
738
+ return this.request("POST", "/v1/graph/search", {
739
+ body: { ...body, search },
740
+ });
744
741
  }
745
742
  /** Reciprocal-rank-fusion across sub-queries. */
746
743
  multiSearch(body) {
@@ -754,37 +751,18 @@ export class LbbClient {
754
751
  suggest(body) {
755
752
  return this.request("POST", "/v1/search/suggest", { body });
756
753
  }
757
- /**
758
- * Snap free text to the nearest real vocabulary item. Embedding cosine
759
- * on a managed graph, else lexical; never fabricates a term.
760
- */
754
+ /** Snap free text to the nearest term in the pinned published vocabulary. */
761
755
  resolveTerm(body) {
762
756
  return this.request("POST", "/v1/search/resolve-term", { body });
763
757
  }
764
- /**
765
- * Ground a natural-language question to the graph's real vocabulary, retrieve
766
- * against the pinned snapshot, and answer with citations (`/v1/ask`).
767
- */
768
- ask(body) {
769
- return this.request("POST", "/v1/ask", { body });
770
- }
771
- /**
772
- * Name the relation between two entities (`/v1/decode`): the DB narrows the
773
- * candidates to the type pair's admissible relations, answers alone
774
- * when the pair forces a single relation, and otherwise decodes it with the
775
- * graph-native fine-tuned model — the "DB narrows, cheap model decodes" call.
776
- */
758
+ /** Decode a relation from the graph's admissible published vocabulary. */
777
759
  decode(body) {
778
760
  return this.request("POST", "/v1/decode", { body });
779
761
  }
780
- /**
781
- * Report which completion mechanisms will carry on this graph:
782
- * signature sparsity, name semantics, sampled narrowing recall, and a
783
- * narrow / narrow+finetune / lexical-first recommendation.
784
- */
762
+ /** Report completion strategy fitness for the pinned published graph. */
785
763
  groundability(opts = {}) {
786
764
  return this.request("GET", "/v1/graph/groundability", {
787
- query: opts.sample != null ? { sample: String(opts.sample) } : undefined,
765
+ query: opts.sample == null ? undefined : { sample: opts.sample },
788
766
  });
789
767
  }
790
768
  /**
@@ -805,12 +783,16 @@ export class LbbClient {
805
783
  return this.request("GET", "/v1/search/feedback/export");
806
784
  }
807
785
  /** BM25 search. */
808
- fullTextSearch(body) {
809
- return this.request("POST", "/v1/search/full-text", { body });
786
+ fullTextSearch(body, opts) {
787
+ return this.request("POST", "/v1/search/full-text", {
788
+ body: this.mergeReadConsistency(body, opts),
789
+ });
810
790
  }
811
791
  /** ANN/vector search. */
812
- embeddingSearch(body) {
813
- return this.request("POST", "/v1/search/embedding", { body });
792
+ embeddingSearch(body, opts) {
793
+ return this.request("POST", "/v1/search/embedding", {
794
+ body: this.mergeReadConsistency(body, opts),
795
+ });
814
796
  }
815
797
  // --- traversal ---
816
798
  /** Bounded k-hop graph traversal. */
@@ -830,7 +812,6 @@ export class LbbClient {
830
812
  name: opts.name,
831
813
  relations: opts.relations?.join(","),
832
814
  as_of: opts.asOf,
833
- indexed: opts.indexed,
834
815
  },
835
816
  });
836
817
  }
@@ -870,39 +851,11 @@ export class LbbClient {
870
851
  },
871
852
  });
872
853
  }
873
- /**
874
- * Paged edge listing. Scope to one node with `id` (or `type`+`name`) and a
875
- * `direction` (`out`/`in`/`both`) to walk **every** edge of a high-degree node
876
- * — `entityDetail` returns the full set but is awkward to page; this carries
877
- * `offset`/`limit` and reports `total_count`. Optional `relation`/`q` filters
878
- * and an `asOf`/`asOfCommitSeq` snapshot pin. Each row carries `valid_time`, so
879
- * the page is enough to reconstruct a per-edge timeline.
880
- */
881
- graphEdges(opts = {}) {
882
- return this.request("GET", "/v1/graph/edges", {
883
- query: {
884
- id: opts.id,
885
- type: opts.type,
886
- name: opts.name,
887
- direction: opts.direction,
888
- relation: opts.relation,
889
- q: opts.q,
890
- limit: opts.limit,
891
- cursor: opts.cursor,
892
- offset: opts.offset,
893
- as_of: opts.asOf,
894
- as_of_commit_seq: opts.asOfCommitSeq,
895
- },
896
- });
897
- }
898
854
  /**
899
855
  * Page through every row of a list endpoint, following `next_cursor` until
900
856
  * exhausted. Pass a fetcher that takes a cursor and returns a
901
857
  * {@link ListResponse}:
902
- * ```ts
903
- * for await (const e of client.listAll((cursor) =>
904
- * client.entities.list({ cursor, fields: "title" }))) { … }
905
- * ```
858
+ * The caller supplies a bounded collection endpoint and its cursor.
906
859
  */
907
860
  async *listAll(fetchPage) {
908
861
  let cursor;
@@ -932,10 +885,6 @@ export class LbbClient {
932
885
  why(body) {
933
886
  return this.request("POST", "/v1/query/why", { body });
934
887
  }
935
- /** SHACL-style shape/pattern query. */
936
- shacl(body) {
937
- return this.request("POST", "/v1/query/shacl", { body });
938
- }
939
888
  /**
940
889
  * SPARQL-subset SELECT/ASK/aggregate query (FILTER, HAVING, ORDER BY, ASK,
941
890
  * COUNT/SUM/AVG/MIN/MAX). GROUP BY is not limited to entity identity:
@@ -946,12 +895,17 @@ export class LbbClient {
946
895
  * keys come back per group in `groups[].value_keys[<as>]`, entity keys in
947
896
  * `groups[].keys`.
948
897
  */
949
- sparql(body) {
950
- return this.request("POST", "/v1/query/sparql", { body });
898
+ sparql(body, opts) {
899
+ return this.request("POST", "/v1/query/sparql", {
900
+ body: this.mergeReadConsistency(body, opts),
901
+ });
951
902
  }
952
- /** SPARQL 1.1 query from text (SELECT/ASK) over the live graph; `results` is SPARQL 1.1 Query Results JSON. */
953
- sparqlText(body) {
954
- return this.request("POST", "/v1/query/sparql-text", { body });
903
+ /** SPARQL 1.1 query from text (SELECT/ASK) over the live graph; `results` is SPARQL 1.1 Query Results JSON. The text dialect carries `consistency`/`min_indexed_seq` on the URL. */
904
+ sparqlText(body, opts) {
905
+ return this.request("POST", "/v1/query/sparql-text", {
906
+ body,
907
+ query: this.readConsistencyQuery(opts),
908
+ });
955
909
  }
956
910
  /**
957
911
  * Run a SPARQL 1.1 text query and return parsed results — the ergonomic
@@ -960,8 +914,8 @@ export class LbbClient {
960
914
  * `rows` is the bindings flattened to `{ variable: lexicalValue }`, `boolean`
961
915
  * is the ASK answer (or `null` for a SELECT).
962
916
  */
963
- async sparqlRows(body) {
964
- return parseSparqlResults(await this.sparqlText(body));
917
+ async sparqlRows(body, opts) {
918
+ return parseSparqlResults(await this.sparqlText(body, opts));
965
919
  }
966
920
  /**
967
921
  * Basic-graph-pattern query with group-graph-pattern combinators
@@ -973,36 +927,6 @@ export class LbbClient {
973
927
  analytics(body) {
974
928
  return this.request("POST", "/v1/query/analytics", { body });
975
929
  }
976
- /**
977
- * Run inference rules (SHACL-AF `sh:TripleRule` shape) to a bounded fixpoint
978
- * and return the derived edges as a **preview** — derived facts are never
979
- * written to the asserted graph. Each rule is a BGP `body`/`where` plus a
980
- * `head` triple template instantiated per binding.
981
- */
982
- infer(body) {
983
- return this.request("POST", "/v1/inference/run", { body });
984
- }
985
- /**
986
- * Define (replace) the versioned rule set stored on the scoped graph branch.
987
- * The stored set is what SHACL `include_derived` and `infer` use when a
988
- * request carries no inline rules. Returns the new `rules_version`.
989
- */
990
- defineRules(body) {
991
- return this.request("POST", "/v1/inference/rules", { body });
992
- }
993
- /** The rule set stored on the scoped graph branch (version + rules). */
994
- graphRules() {
995
- return this.request("GET", "/v1/inference/rules");
996
- }
997
- /**
998
- * Derive edges from calibrated retrieval matches (preview): each
999
- * candidate scored `P >= threshold` becomes a derived edge `(anchor, relation,
1000
- * matched)` with a typed `Retrieval` provenance leaf. Pass either explicit
1001
- * `candidates` or a `query` the server runs as BM25 entity retrieval.
1002
- */
1003
- retrievalPremises(body) {
1004
- return this.request("POST", "/v1/inference/retrieval-premises", { body });
1005
- }
1006
930
  // --- ontology ---
1007
931
  /**
1008
932
  * The active ontology (entity types and relations) for the scoped graph.
@@ -1019,12 +943,13 @@ export class LbbClient {
1019
943
  * Audit the current snapshot against the ontology's *implied* constraints —
1020
944
  * capped `cardinality` derived as `sh:maxCount` — returning a SHACL-shaped
1021
945
  * report. Whole-snapshot and never blocks a write. Unlike
1022
- * {@link SchemaNamespace.audit}, this needs no published shape bundle: the
1023
- * shapes come from the ontology itself. See the `decoration_status` catalog on
1024
- * {@link ontologyView} for which decorations are enforced.
946
+ * The report is referenced by the pinned published read root and carries its
947
+ * own validation watermark and ontology/shapes provenance.
1025
948
  */
1026
- ontologyConformance() {
1027
- return this.request("GET", "/v1/ontology/conformance");
949
+ ontologyConformance(opts) {
950
+ return this.request("GET", "/v1/ontology/conformance", {
951
+ query: { consistency: this.resolveConsistency(opts) },
952
+ });
1028
953
  }
1029
954
  /** Discover ontology concepts, terms, and relations. */
1030
955
  ontologySearch(body) {
@@ -1051,75 +976,6 @@ export class LbbClient {
1051
976
  induceOntology(body) {
1052
977
  return this.request("POST", "/v1/ontology/induce", { body, retry: true });
1053
978
  }
1054
- // --- index lifecycle ---
1055
- /**
1056
- * Build default ANN + BM25 indexes. With `{ background: true }` the build
1057
- * runs detached on the server and the call returns immediately — use it for
1058
- * large corpora whose synchronous build would exceed a fronting gateway's
1059
- * timeout (a 504), then poll `metadata()` for completion.
1060
- */
1061
- indexBuild(opts = {}) {
1062
- return this.request("POST", "/v1/index/build", {
1063
- query: { background: opts.background || undefined },
1064
- });
1065
- }
1066
- /**
1067
- * Build BM25, ANN/vector, and adjacency index families. With
1068
- * `{ background: true }` the build runs detached on the server and the call
1069
- * returns immediately — use it for large corpora whose synchronous build would
1070
- * exceed a fronting gateway's timeout, then poll `metadata()` for completion.
1071
- */
1072
- indexRun(opts = {}) {
1073
- return this.request("POST", "/v1/index/run", {
1074
- query: { background: opts.background || undefined },
1075
- });
1076
- }
1077
- /** Submit a durable full-index build. Requires a reconnect-safe idempotency key. */
1078
- indexSubmit(body = {}, opts) {
1079
- return this.request("POST", "/v1/index/jobs", {
1080
- body,
1081
- idempotencyKey: opts.idempotencyKey,
1082
- });
1083
- }
1084
- /** Poll a durable full-index build. */
1085
- indexJob(jobId) {
1086
- return this.request("GET", "/v1/index/jobs", { query: { job_id: jobId } });
1087
- }
1088
- /** Cancel a durable full-index build. Repeated cancellation returns its current terminal status. */
1089
- cancelIndexJob(jobId) {
1090
- return this.request("DELETE", "/v1/index/jobs", {
1091
- query: { job_id: jobId },
1092
- });
1093
- }
1094
- /** Append a BM25 delta segment for the unindexed WAL tail. */
1095
- indexDelta() {
1096
- return this.request("POST", "/v1/index/delta");
1097
- }
1098
- /** Preview or delete superseded persisted index runs. */
1099
- indexGc(opts = {}) {
1100
- return this.request("POST", "/v1/index/gc", {
1101
- query: { keep_runs: opts.keepRuns, dry_run: opts.dryRun },
1102
- });
1103
- }
1104
- /** Submit durable, cancellable index garbage collection. */
1105
- indexGcSubmit(body = {}, opts) {
1106
- return this.request("POST", "/v1/index/gc-jobs", {
1107
- body,
1108
- idempotencyKey: opts.idempotencyKey,
1109
- });
1110
- }
1111
- /** Poll exact planning/deletion progress for durable index garbage collection. */
1112
- indexGcJob(jobId) {
1113
- return this.request("GET", "/v1/index/gc-jobs", {
1114
- query: { job_id: jobId },
1115
- });
1116
- }
1117
- /** Cancel durable index garbage collection. */
1118
- cancelIndexGcJob(jobId) {
1119
- return this.request("DELETE", "/v1/index/gc-jobs", {
1120
- query: { job_id: jobId },
1121
- });
1122
- }
1123
979
  /** Fold the WAL tail into snapshot segments. */
1124
980
  compact(opts = {}) {
1125
981
  return this.request("POST", "/v1/graph/compact", {
@@ -1134,13 +990,11 @@ export class LbbClient {
1134
990
  status() {
1135
991
  return this.request("GET", "/v1/status");
1136
992
  }
1137
- /** Graph footprint, WAL tail, and index coverage. Exact object inventory is opt-in. */
993
+ /** Graph footprint, WAL tail, and published-index coverage. */
1138
994
  metadata(opts = {}) {
1139
995
  return this.request("GET", "/v1/graph/metadata", {
1140
996
  query: {
1141
- include_objects: opts.includeObjects,
1142
997
  include_indexes: opts.includeIndexes,
1143
- include_temporal_coverage: opts.includeTemporalCoverage,
1144
998
  },
1145
999
  });
1146
1000
  }
@@ -1175,9 +1029,15 @@ export class LbbClient {
1175
1029
  await sleep(opts.pollIntervalMs ?? 250);
1176
1030
  }
1177
1031
  }
1178
- /** Graph counts and type/relation buckets. */
1179
- summary() {
1180
- return this.request("GET", "/v1/graph/summary");
1032
+ /** Graph counts and type/relation buckets. Carries `consistency`/`min_indexed_seq` on the URL. */
1033
+ summary(opts) {
1034
+ return this.request("GET", "/v1/graph/summary", {
1035
+ query: this.readConsistencyQuery(opts),
1036
+ });
1037
+ }
1038
+ /** Pinned published read root and its query/conformance lag against one coherent head. */
1039
+ readSnapshot() {
1040
+ return this.request("GET", "/v1/graph/read-snapshot");
1181
1041
  }
1182
1042
  /** List the graphs (and branches) under the scoped tenant. */
1183
1043
  listGraphs() {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { LbbClient, LbbError, parseSparqlResults } from "./client.js";
2
- export type { LbbClientOptions, CallOptions, RequestOptions, EntityListOptions, HybridSearchOptions, LbbRequestEvent, LbbResponseEvent, FetchLike, Schemas, SparqlResults, SparqlResultsJson, SparqlTerm, AskRequest, AskResponse, CommitRequest, CommitResponse, Entity, EntitySelector, GraphMetadata, GraphSummary, SchemaView, SearchRequest, SearchResponse, SearchResult, Snapshot, } from "./client.js";
2
+ export type { LbbClientOptions, CallOptions, RequestOptions, HybridSearchOptions, LbbRequestEvent, LbbResponseEvent, FetchLike, ReadConsistencyOptions, SearchConsistency, Schemas, SparqlResults, SparqlResultsJson, SparqlTerm, CommitRequest, CommitResponse, Entity, EntitySelector, GraphMetadata, GraphSummary, SchemaView, SearchRequest, SearchResponse, SearchResult, Snapshot, } from "./client.js";
3
3
  export type { components, paths, operations } from "./schema.js";