@littlebigbrain/client 0.4.2 → 0.5.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.
- package/README.md +69 -126
- package/dist/client.d.ts +39 -1
- package/dist/client.js +92 -5
- package/dist/namespaces.d.ts +9 -0
- package/dist/namespaces.js +24 -4
- package/dist/schema.d.ts +1033 -201
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,169 +1,112 @@
|
|
|
1
1
|
# @littlebigbrain/client
|
|
2
2
|
|
|
3
|
-
TypeScript client for
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
truth, derived from the Rust `lbb-api` types); the client itself is a thin,
|
|
7
|
-
dependency-free wrapper over the platform `fetch`.
|
|
3
|
+
Typed TypeScript client for little big brain: ingest, BM25/vector/graph index,
|
|
4
|
+
authorized hybrid search, traversal, ontology, feedback, and training jobs.
|
|
5
|
+
Runs on Node 18+, browsers, and edge workers using the platform `fetch`.
|
|
8
6
|
|
|
9
7
|
```sh
|
|
10
8
|
npm install @littlebigbrain/client
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Five-minute start
|
|
14
12
|
|
|
15
13
|
```ts
|
|
16
|
-
import { LbbClient
|
|
14
|
+
import { LbbClient } from "@littlebigbrain/client";
|
|
17
15
|
|
|
18
16
|
const lbb = new LbbClient({
|
|
19
17
|
baseUrl: "https://db.eu.littlebigbrain.com",
|
|
20
|
-
apiKey: process.env.LBB_API_KEY,
|
|
18
|
+
apiKey: process.env.LBB_API_KEY,
|
|
21
19
|
});
|
|
22
|
-
|
|
23
20
|
const graph = lbb.graph("main");
|
|
24
21
|
|
|
25
22
|
await graph.facts.create({
|
|
26
|
-
triplets: [
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
}, {
|
|
36
|
-
idempotencyKey: "import-2026-06-13",
|
|
37
|
-
});
|
|
23
|
+
triplets: [{
|
|
24
|
+
source: { type: "CONCEPT", name: "policy-42" },
|
|
25
|
+
relation: "RELATED_TO",
|
|
26
|
+
target: { type: "CONCEPT", name: "seven-year retention" },
|
|
27
|
+
evidence: "Customer records are retained for seven years.",
|
|
28
|
+
}],
|
|
29
|
+
}, { idempotencyKey: "policy-42-v1" });
|
|
38
30
|
|
|
39
31
|
await graph.indexes.run({ wait: true });
|
|
40
32
|
|
|
41
|
-
const results = await graph.search.hybrid(
|
|
42
|
-
|
|
43
|
-
source: "persisted",
|
|
44
|
-
|
|
45
|
-
targets: ["entities", "assertions"],
|
|
46
|
-
});
|
|
47
|
-
for (const assertion of results.assertions ?? []) {
|
|
48
|
-
console.log(assertion.relation?.name, assertion.score);
|
|
49
|
-
}
|
|
33
|
+
const results = await graph.search.hybrid(
|
|
34
|
+
"How long are customer records retained?",
|
|
35
|
+
{ topK: 10, source: "persisted", consistency: "strong" },
|
|
36
|
+
);
|
|
50
37
|
```
|
|
51
38
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`message`, `param`, `requestId`, and `docUrl` on a non-2xx response.
|
|
56
|
-
|
|
57
|
-
Requests have a 120-second per-attempt timeout by default (`timeoutMs: 0`
|
|
58
|
-
disables it). Safe reads and idempotency-keyed writes retry `429`/`5xx` and
|
|
59
|
-
network failures up to twice, honoring `Retry-After` with a one-minute cap.
|
|
60
|
-
Bulk NDJSON and RDF imports receive an idempotency key automatically unless you
|
|
61
|
-
provide one explicitly. The preferred namespaced surface accepts the same final
|
|
62
|
-
request options everywhere: `timeoutMs`, `maxRetries`, `signal`, `headers`, and
|
|
63
|
-
`idempotencyKey` for mutations.
|
|
39
|
+
Methods return parsed JSON and throw `LbbError` on non-2xx responses. Safe
|
|
40
|
+
reads and idempotency-keyed writes retry transient failures and honor
|
|
41
|
+
`Retry-After`. Keep live stack keys on the server, never in browser bundles.
|
|
64
42
|
|
|
65
|
-
##
|
|
43
|
+
## Enterprise search integrations
|
|
66
44
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
compatibility.
|
|
45
|
+
Keep the host product's users, connectors, tasks, and cursors in its existing
|
|
46
|
+
database. Put searchable documents, passages, facts, embeddings, indexes,
|
|
47
|
+
feedback, and model runs in little big brain:
|
|
71
48
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
49
|
+
1. Give every document/chunk/passage a stable external key.
|
|
50
|
+
2. Bulk-import content, provenance, and native ACL/tag/project sets.
|
|
51
|
+
3. Configure managed embeddings; build ANN, BM25, and adjacency once per batch.
|
|
52
|
+
4. Filter by ACL inside the search request before ranking and return projected
|
|
53
|
+
fields on the ranked hits.
|
|
54
|
+
5. Grade cited results, reconnect to durable trainer jobs, and require a
|
|
55
|
+
held-out quality plus latency gate before promotion.
|
|
78
56
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
57
|
+
`suggestionShown`, `suggestionAdopted`, `externalPlannerTrace`, and
|
|
58
|
+
`askFeedback` use generated versioned payload types and idempotency keys. Their
|
|
59
|
+
acknowledgements expose stable receipt/event identity, replay state, and why an
|
|
60
|
+
event is or is not trainable.
|
|
83
61
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
fires once for the final response; neither event contains bodies or
|
|
90
|
-
credentials. `rawRequest(...)` additionally reports `attempts`, `retryCount`,
|
|
91
|
-
and `elapsedMs`.
|
|
92
|
-
|
|
93
|
-
## Methods
|
|
94
|
-
|
|
95
|
-
| Area | Methods |
|
|
96
|
-
| --- | --- |
|
|
97
|
-
| Write | `graph("main").facts.create` |
|
|
98
|
-
| Managed embeddings | `graph("main").embeddingConfig`, `graph("main").setEmbeddingConfig`, `graph("main").backfillEmbeddings`, `graph("main").promoteEmbedding` |
|
|
99
|
-
| Search | `search.hybrid`, `search.multi`, `search.fullText`, `search.vector` |
|
|
100
|
-
| Context substrate | `context.ask`, `context.suggest`, `context.resolve`, `context.decode`, `context.groundability` |
|
|
101
|
-
| Search feedback (training data) | `search.feedback`, `search.feedbackExport` |
|
|
102
|
-
| Traversal | `traverse`, `semanticTraverse` |
|
|
103
|
-
| Temporal / lineage / shapes | `currentState`, `history`, `why`, `shacl` |
|
|
104
|
-
| Query | `query.sparql`, `query.structured`, `query.analytics`, `query.shacl`, `query.infer`, `query.premises` |
|
|
105
|
-
| Ontology | `ontology.view`, `ontology.conformance`, `ontology.search`, `ontology.resolve`, `ontology.define`, `ontology.evolve`, `ontology.induce` |
|
|
106
|
-
| Index lifecycle | `indexes.run`, `indexes.build`, `indexes.delta`, `indexes.gc`, `compact` |
|
|
107
|
-
| Inspection | `entities.list`, `entities.filterByAttributes`, `status`, `metadata`, `summary` |
|
|
108
|
-
| Schema activation | `schema.view`, `schema.preview`, `schema.publish`, `schema.audit` |
|
|
109
|
-
|
|
110
|
-
Common request/response shapes have direct imports such as `SearchRequest`,
|
|
111
|
-
`SearchResponse`, `Entity`, `GraphSummary`, `CommitRequest`, `AskResponse`, and
|
|
112
|
-
`SchemaView`. Every generated shape remains available as `Schemas["TypeName"]`;
|
|
113
|
-
the raw `components`, `paths`, and `operations` are exported too.
|
|
62
|
+
For an LLM query planner, call `lbb.context.suggest(...)` to fill grounded
|
|
63
|
+
schema/value prefixes, then `lbb.context.resolve(...)` to snap free-text guesses
|
|
64
|
+
onto real vocabulary. `resolve` uses managed embeddings when configured. Record
|
|
65
|
+
adopted suggestions and accepted/rejected/corrected plans so a smaller planner
|
|
66
|
+
and suggest ranker can be trained on the product's actual workload.
|
|
114
67
|
|
|
115
|
-
|
|
68
|
+
The [enterprise-search integration guide](https://docs.littlebigbrain.com/guides/enterprise-search/)
|
|
69
|
+
contains the graph model, migration sequence, and acceptance tests.
|
|
116
70
|
|
|
117
|
-
|
|
118
|
-
returns parsed results, so you never have to `JSON.parse` the results string or
|
|
119
|
-
zip `head.vars` with binding values yourself:
|
|
71
|
+
## Main surface
|
|
120
72
|
|
|
121
73
|
```ts
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const exists = (await client.sparqlRows({ query: "ASK { ?s ?p ?o }" })).boolean;
|
|
74
|
+
graph.facts.create(...)
|
|
75
|
+
graph.facts.import(...)
|
|
76
|
+
graph.search.hybrid(...)
|
|
77
|
+
graph.entities.iterate(...)
|
|
78
|
+
graph.context.ask(...)
|
|
79
|
+
graph.ontology.view(...)
|
|
80
|
+
graph.query.sparql(...)
|
|
81
|
+
graph.schema.audit(...)
|
|
131
82
|
```
|
|
132
83
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
84
|
+
Other focused methods cover managed embeddings, full-text/vector search,
|
|
85
|
+
multi-query fusion, traversal, temporal state/history, SHACL, ontology
|
|
86
|
+
evolution, feedback, indexing, and graph inspection. Request/response types are
|
|
87
|
+
generated from `contracts/openapi.json`; common aliases and the complete
|
|
88
|
+
`Schemas` map are exported from the package.
|
|
89
|
+
|
|
90
|
+
Use `rawRequest()` when you need response headers, request ID, retry count, or
|
|
91
|
+
elapsed time. `onRequest` and `onResponse` provide body-free instrumentation.
|
|
92
|
+
|
|
93
|
+
## SPARQL
|
|
136
94
|
|
|
137
95
|
```ts
|
|
138
|
-
await
|
|
139
|
-
|
|
140
|
-
where: [{ field: "slo", op: "ge", value: 0.99 }, { var: "db", field: "tier", value: "prod" }],
|
|
141
|
-
select: ["service"],
|
|
96
|
+
const { rows } = await lbb.sparqlRows({
|
|
97
|
+
query: `SELECT ?doc WHERE { ?doc ?p ?o } LIMIT 10`,
|
|
142
98
|
});
|
|
143
99
|
```
|
|
144
100
|
|
|
145
|
-
`sparqlRows`
|
|
146
|
-
|
|
147
|
-
objects, and `boolean` is the ASK answer (or `null` for a SELECT). `client.sparqlText(...)`
|
|
148
|
-
returns the unparsed envelope, and the standalone `parseSparqlResults(response)`
|
|
149
|
-
helper (also exported) parses it. For the structured BGP form use
|
|
150
|
-
`client.sparql(body)` (`SparqlSelectRequest`).
|
|
151
|
-
|
|
152
|
-
A standalone stack also serves the **native SPARQL 1.1 Protocol** at `/sparql`
|
|
153
|
-
(`GET ?query=`, `POST` form or `application/sparql-query` body,
|
|
154
|
-
`Accept`-negotiated JSON/XML/CSV/TSV) for off-the-shelf SPARQL clients (YASGUI,
|
|
155
|
-
Protégé); `sparqlRows` returns parsed JSON rows for in-process use.
|
|
101
|
+
`sparqlRows` parses SELECT/ASK results. The native SPARQL 1.1 Protocol is also
|
|
102
|
+
available at `/sparql` for standard RDF clients.
|
|
156
103
|
|
|
157
104
|
## Develop
|
|
158
105
|
|
|
159
106
|
```sh
|
|
160
107
|
npm install
|
|
161
|
-
npm run generate
|
|
162
|
-
npm run
|
|
163
|
-
npm test
|
|
164
|
-
npm run
|
|
165
|
-
npm run pack:check # exact tarball: publint + ATTW
|
|
108
|
+
npm run generate
|
|
109
|
+
npm run typecheck
|
|
110
|
+
npm test
|
|
111
|
+
npm run pack:check
|
|
166
112
|
```
|
|
167
|
-
|
|
168
|
-
`runtime`: any environment with a global `fetch` (Node 18+, browsers, edge
|
|
169
|
-
workers), or pass your own via the `fetch` option.
|
package/dist/client.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ export { LbbError } from "./transport.js";
|
|
|
7
7
|
export type { CallOptions, Query, QueryValue, RequestOptions, } from "./transport.js";
|
|
8
8
|
export type { EntityListOptions, HybridSearchOptions } from "./namespaces.js";
|
|
9
9
|
export { ContextNamespace, EntityNamespace, FactsNamespace, GraphNamespace, IndexNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
|
|
10
|
+
export interface IndexLineageObservation {
|
|
11
|
+
metadata: Schemas["GraphMetadataResponse"];
|
|
12
|
+
lineage: Schemas["IndexLineage"];
|
|
13
|
+
buildCommit?: string;
|
|
14
|
+
replica?: string;
|
|
15
|
+
requestId?: string;
|
|
16
|
+
attempts: number;
|
|
17
|
+
elapsedMs: number;
|
|
18
|
+
}
|
|
10
19
|
/**
|
|
11
20
|
* A typed HTTP client for a little big brain graph server. One instance is scoped to a
|
|
12
21
|
* single graph/branch; construct another for a different scope. All methods
|
|
@@ -133,10 +142,21 @@ export declare class LbbClient {
|
|
|
133
142
|
}): Promise<unknown>;
|
|
134
143
|
embeddingConfig(): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
135
144
|
setEmbeddingConfig(body: Schemas["ManagedEmbeddingConfigRequest"]): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
145
|
+
submitEmbeddingBackfill(opts?: {
|
|
146
|
+
batchSize?: number;
|
|
147
|
+
limit?: number;
|
|
148
|
+
full?: boolean;
|
|
149
|
+
idempotencyKey?: string;
|
|
150
|
+
}): Promise<Schemas["ManagedEmbeddingBackfillJobStatusResponse"]>;
|
|
151
|
+
embeddingBackfillJob(jobId: string): Promise<Schemas["ManagedEmbeddingBackfillJobStatusResponse"]>;
|
|
152
|
+
cancelEmbeddingBackfill(jobId: string): Promise<Schemas["ManagedEmbeddingBackfillJobStatusResponse"]>;
|
|
136
153
|
backfillEmbeddings(opts?: {
|
|
137
154
|
batchSize?: number;
|
|
138
155
|
limit?: number;
|
|
139
156
|
full?: boolean;
|
|
157
|
+
idempotencyKey?: string;
|
|
158
|
+
timeoutMs?: number;
|
|
159
|
+
pollIntervalMs?: number;
|
|
140
160
|
}): Promise<Schemas["ManagedEmbeddingBackfillResponse"]>;
|
|
141
161
|
promoteEmbedding(opts: {
|
|
142
162
|
runId: string;
|
|
@@ -224,7 +244,21 @@ export declare class LbbClient {
|
|
|
224
244
|
* explicit feedback capture. `accepted: false` in the response means
|
|
225
245
|
* signal capture is off on this deployment (the contract is identical).
|
|
226
246
|
*/
|
|
227
|
-
askFeedback(body: Schemas["AskFeedbackRequest"]
|
|
247
|
+
askFeedback(body: Schemas["AskFeedbackRequest"], opts?: {
|
|
248
|
+
idempotencyKey?: string;
|
|
249
|
+
}): Promise<Schemas["AskFeedbackResponse"]>;
|
|
250
|
+
ingestSignals(body: Schemas["SignalIngestRequest"], opts?: {
|
|
251
|
+
idempotencyKey?: string;
|
|
252
|
+
}): Promise<Schemas["SignalIngestResponse"]>;
|
|
253
|
+
suggestionShown(payload: Schemas["SuggestionShownV1"], opts?: {
|
|
254
|
+
idempotencyKey?: string;
|
|
255
|
+
}): Promise<Schemas["SignalIngestResponse"]>;
|
|
256
|
+
suggestionAdopted(payload: Schemas["SuggestionAdoptedV1"], opts?: {
|
|
257
|
+
idempotencyKey?: string;
|
|
258
|
+
}): Promise<Schemas["SignalIngestResponse"]>;
|
|
259
|
+
externalPlannerTrace(payload: Schemas["ExternalPlannerTraceV1"], opts?: {
|
|
260
|
+
idempotencyKey?: string;
|
|
261
|
+
}): Promise<Schemas["SignalIngestResponse"]>;
|
|
228
262
|
/**
|
|
229
263
|
* The planner fine-tune's training feed: accepted/corrected feedback
|
|
230
264
|
* joined to its traces (signals ≤ the split pin), topped up with
|
|
@@ -521,6 +555,10 @@ export declare class LbbClient {
|
|
|
521
555
|
status(): Promise<unknown>;
|
|
522
556
|
/** Graph footprint, WAL tail, and index coverage. */
|
|
523
557
|
metadata(): Promise<Schemas["GraphMetadataResponse"]>;
|
|
558
|
+
waitForIndexLineage(targetSeq: number, opts?: {
|
|
559
|
+
timeoutMs?: number;
|
|
560
|
+
pollIntervalMs?: number;
|
|
561
|
+
}): Promise<IndexLineageObservation>;
|
|
524
562
|
/** Graph counts and type/relation buckets. */
|
|
525
563
|
summary(): Promise<Schemas["GraphSummaryResponse"]>;
|
|
526
564
|
/** List the graphs (and branches) under the scoped tenant. */
|
package/dist/client.js
CHANGED
|
@@ -395,11 +395,40 @@ export class LbbClient {
|
|
|
395
395
|
setEmbeddingConfig(body) {
|
|
396
396
|
return this.request("POST", "/v1/graph/embedding", { body });
|
|
397
397
|
}
|
|
398
|
-
|
|
399
|
-
return this.request("POST", "/v1/graph/embedding/backfill", {
|
|
400
|
-
|
|
398
|
+
submitEmbeddingBackfill(opts = {}) {
|
|
399
|
+
return this.request("POST", "/v1/graph/embedding/backfill-jobs", {
|
|
400
|
+
body: {
|
|
401
|
+
batch_size: opts.batchSize,
|
|
402
|
+
limit: opts.limit,
|
|
403
|
+
full: opts.full ?? false,
|
|
404
|
+
},
|
|
405
|
+
idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("embedding-backfill"),
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
embeddingBackfillJob(jobId) {
|
|
409
|
+
return this.request("GET", "/v1/graph/embedding/backfill-jobs", {
|
|
410
|
+
query: { job_id: jobId },
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
cancelEmbeddingBackfill(jobId) {
|
|
414
|
+
return this.request("DELETE", "/v1/graph/embedding/backfill-jobs", {
|
|
415
|
+
query: { job_id: jobId },
|
|
401
416
|
});
|
|
402
417
|
}
|
|
418
|
+
async backfillEmbeddings(opts = {}) {
|
|
419
|
+
let status = await this.submitEmbeddingBackfill(opts);
|
|
420
|
+
const deadline = Date.now() + (opts.timeoutMs ?? 30 * 60_000);
|
|
421
|
+
while (status.status === "pending" || status.status === "running") {
|
|
422
|
+
if (Date.now() >= deadline)
|
|
423
|
+
throw new Error(`embedding backfill ${status.job_id} did not finish before timeout`);
|
|
424
|
+
await sleep(opts.pollIntervalMs ?? 2_000);
|
|
425
|
+
status = await this.embeddingBackfillJob(status.job_id);
|
|
426
|
+
}
|
|
427
|
+
if (status.status !== "succeeded" || status.result == null)
|
|
428
|
+
throw new Error(status.terminal_error ??
|
|
429
|
+
`embedding backfill ${status.job_id} ended ${status.status}`);
|
|
430
|
+
return status.result;
|
|
431
|
+
}
|
|
403
432
|
promoteEmbedding(opts) {
|
|
404
433
|
return this.request("POST", "/v1/graph/embedding/promote", {
|
|
405
434
|
query: { run_id: opts.runId, allow_regression: opts.allowRegression },
|
|
@@ -506,8 +535,35 @@ export class LbbClient {
|
|
|
506
535
|
* explicit feedback capture. `accepted: false` in the response means
|
|
507
536
|
* signal capture is off on this deployment (the contract is identical).
|
|
508
537
|
*/
|
|
509
|
-
askFeedback(body) {
|
|
510
|
-
return this.request("POST", "/v1/ask/feedback", {
|
|
538
|
+
askFeedback(body, opts = {}) {
|
|
539
|
+
return this.request("POST", "/v1/ask/feedback", {
|
|
540
|
+
body,
|
|
541
|
+
idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("ask-feedback"),
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
ingestSignals(body, opts = {}) {
|
|
545
|
+
return this.request("POST", "/v1/signals", {
|
|
546
|
+
body,
|
|
547
|
+
idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("signals"),
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
suggestionShown(payload, opts = {}) {
|
|
551
|
+
return this.ingestSignals({ signals: [{ kind: "suggestion_shown", payload }] }, opts);
|
|
552
|
+
}
|
|
553
|
+
suggestionAdopted(payload, opts = {}) {
|
|
554
|
+
return this.ingestSignals({ signals: [{ kind: "suggestion_adopted", payload }] }, opts);
|
|
555
|
+
}
|
|
556
|
+
externalPlannerTrace(payload, opts = {}) {
|
|
557
|
+
return this.ingestSignals({
|
|
558
|
+
signals: [
|
|
559
|
+
{
|
|
560
|
+
kind: "external_planner_trace",
|
|
561
|
+
request_id: payload.ask_id,
|
|
562
|
+
snapshot_token: payload.snapshot_token,
|
|
563
|
+
payload,
|
|
564
|
+
},
|
|
565
|
+
],
|
|
566
|
+
}, opts);
|
|
511
567
|
}
|
|
512
568
|
/**
|
|
513
569
|
* The planner fine-tune's training feed: accepted/corrected feedback
|
|
@@ -923,6 +979,37 @@ export class LbbClient {
|
|
|
923
979
|
metadata() {
|
|
924
980
|
return this.request("GET", "/v1/graph/metadata");
|
|
925
981
|
}
|
|
982
|
+
async waitForIndexLineage(targetSeq, opts = {}) {
|
|
983
|
+
const deadline = Date.now() + (opts.timeoutMs ?? 30_000);
|
|
984
|
+
let last;
|
|
985
|
+
while (true) {
|
|
986
|
+
last = await this.rawRequest("GET", "/v1/graph/metadata");
|
|
987
|
+
const lineage = last.data.index_lineage;
|
|
988
|
+
if (lineage != null &&
|
|
989
|
+
lineage.bm25_indexed_commit_seq != null &&
|
|
990
|
+
lineage.bm25_indexed_commit_seq >= targetSeq &&
|
|
991
|
+
lineage.ann_indexed_commit_seq != null &&
|
|
992
|
+
lineage.ann_indexed_commit_seq >= targetSeq &&
|
|
993
|
+
lineage.adjacency_indexed_commit_seq != null &&
|
|
994
|
+
lineage.adjacency_indexed_commit_seq >= targetSeq) {
|
|
995
|
+
return {
|
|
996
|
+
metadata: last.data,
|
|
997
|
+
lineage,
|
|
998
|
+
buildCommit: last.headers?.get("lbb-build-commit") ?? undefined,
|
|
999
|
+
replica: last.headers?.get("lbb-replica") ?? undefined,
|
|
1000
|
+
requestId: last.requestId,
|
|
1001
|
+
attempts: last.attempts,
|
|
1002
|
+
elapsedMs: last.elapsedMs,
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
if (Date.now() >= deadline) {
|
|
1006
|
+
const build = last.headers?.get("lbb-build-commit") ?? "unknown";
|
|
1007
|
+
const replica = last.headers?.get("lbb-replica") ?? "unknown";
|
|
1008
|
+
throw new Error(`index lineage did not reach ${targetSeq} before timeout (build=${build}, replica=${replica}, last=${JSON.stringify(last.data.index_lineage)})`);
|
|
1009
|
+
}
|
|
1010
|
+
await sleep(opts.pollIntervalMs ?? 250);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
926
1013
|
/** Graph counts and type/relation buckets. */
|
|
927
1014
|
summary() {
|
|
928
1015
|
return this.request("GET", "/v1/graph/summary");
|
package/dist/namespaces.d.ts
CHANGED
|
@@ -39,7 +39,15 @@ export declare class GraphNamespace {
|
|
|
39
39
|
batchSize?: number;
|
|
40
40
|
limit?: number;
|
|
41
41
|
full?: boolean;
|
|
42
|
+
pollIntervalMs?: number;
|
|
42
43
|
}): Promise<Schemas["ManagedEmbeddingBackfillResponse"]>;
|
|
44
|
+
submitEmbeddingBackfill(options?: CallOptions & {
|
|
45
|
+
batchSize?: number;
|
|
46
|
+
limit?: number;
|
|
47
|
+
full?: boolean;
|
|
48
|
+
}): Promise<Schemas["ManagedEmbeddingBackfillJobStatusResponse"]>;
|
|
49
|
+
embeddingBackfillJob(jobId: string): Promise<Schemas["ManagedEmbeddingBackfillJobStatusResponse"]>;
|
|
50
|
+
cancelEmbeddingBackfill(jobId: string): Promise<Schemas["ManagedEmbeddingBackfillJobStatusResponse"]>;
|
|
43
51
|
promoteEmbedding(options: CallOptions & {
|
|
44
52
|
runId: string;
|
|
45
53
|
allowRegression?: boolean;
|
|
@@ -77,6 +85,7 @@ export declare class SearchNamespace {
|
|
|
77
85
|
multi(body: Schemas["HybridMultiSearchRequest"], opts?: CallOptions): Promise<Schemas["HybridMultiSearchResponse"]>;
|
|
78
86
|
feedback(body: Schemas["SearchFeedbackRequest"], opts?: CallOptions): Promise<Schemas["SearchFeedbackResponse"]>;
|
|
79
87
|
feedbackExport(opts?: CallOptions): Promise<Schemas["SearchFeedbackExportResponse"]>;
|
|
88
|
+
feedbackSummary(opts?: CallOptions): Promise<Schemas["SearchFeedbackSummaryResponse"]>;
|
|
80
89
|
fullText(body: Schemas["FullTextSearchRequest"], opts?: CallOptions): Promise<Schemas["FullTextSearchResponse"]>;
|
|
81
90
|
vector(body: Schemas["EmbeddingSearchRequest"], opts?: CallOptions): Promise<Schemas["EmbeddingSearchResponse"]>;
|
|
82
91
|
}
|
package/dist/namespaces.js
CHANGED
|
@@ -53,12 +53,29 @@ export class GraphNamespace {
|
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
backfillEmbeddings(options = {}) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
return this.client.backfillEmbeddings({
|
|
57
|
+
batchSize: options.batchSize,
|
|
58
|
+
limit: options.limit,
|
|
59
|
+
full: options.full,
|
|
60
|
+
idempotencyKey: options.idempotencyKey,
|
|
61
|
+
timeoutMs: options.timeoutMs,
|
|
62
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
submitEmbeddingBackfill(options = {}) {
|
|
66
|
+
return this.client.submitEmbeddingBackfill({
|
|
67
|
+
batchSize: options.batchSize,
|
|
68
|
+
limit: options.limit,
|
|
69
|
+
full: options.full,
|
|
70
|
+
idempotencyKey: options.idempotencyKey,
|
|
60
71
|
});
|
|
61
72
|
}
|
|
73
|
+
embeddingBackfillJob(jobId) {
|
|
74
|
+
return this.client.embeddingBackfillJob(jobId);
|
|
75
|
+
}
|
|
76
|
+
cancelEmbeddingBackfill(jobId) {
|
|
77
|
+
return this.client.cancelEmbeddingBackfill(jobId);
|
|
78
|
+
}
|
|
62
79
|
promoteEmbedding(options) {
|
|
63
80
|
const { runId, allowRegression, ...request } = options;
|
|
64
81
|
return this.client.request("POST", "/v1/graph/embedding/promote", {
|
|
@@ -184,6 +201,9 @@ export class SearchNamespace {
|
|
|
184
201
|
feedbackExport(opts = {}) {
|
|
185
202
|
return this.client.request("GET", "/v1/search/feedback/export", opts);
|
|
186
203
|
}
|
|
204
|
+
feedbackSummary(opts = {}) {
|
|
205
|
+
return this.client.request("GET", "/v1/search/feedback/summary", opts);
|
|
206
|
+
}
|
|
187
207
|
fullText(body, opts = {}) {
|
|
188
208
|
return this.client.request("POST", "/v1/search/full-text", {
|
|
189
209
|
...opts,
|