@littlebigbrain/client 0.5.2 → 0.6.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/README.md +62 -63
- package/dist/client.d.ts +35 -7
- package/dist/client.js +114 -11
- package/dist/namespaces.d.ts +21 -1
- package/dist/namespaces.js +55 -0
- package/dist/schema.d.ts +1018 -37
- package/dist/transport.d.ts +34 -2
- package/dist/transport.js +79 -3
- package/dist/types.d.ts +27 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,96 +1,89 @@
|
|
|
1
1
|
# @littlebigbrain/client
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
authorized hybrid search, traversal, ontology, feedback, and training jobs.
|
|
5
|
-
Runs on Node 18+, browsers, and edge workers using the platform `fetch`.
|
|
3
|
+
The typed TypeScript client for [Little Big Brain](https://littlebigbrain.com) — write graph facts, build indexes, and run hybrid search over one snapshot. Request and response types are generated from the API contract, so every call is fully typed. Runs anywhere there's a global `fetch`: Node 18+, browsers, and edge workers.
|
|
6
4
|
|
|
7
5
|
```sh
|
|
8
6
|
npm install @littlebigbrain/client
|
|
9
7
|
```
|
|
10
8
|
|
|
11
|
-
##
|
|
9
|
+
## Quickstart
|
|
12
10
|
|
|
13
11
|
```ts
|
|
14
12
|
import { LbbClient } from "@littlebigbrain/client";
|
|
15
13
|
|
|
16
14
|
const lbb = new LbbClient({
|
|
17
|
-
baseUrl: "https://db.eu.littlebigbrain.com",
|
|
18
|
-
apiKey: process.env.LBB_API_KEY,
|
|
15
|
+
baseUrl: "https://0abc1def--production.db.eu.littlebigbrain.com",
|
|
16
|
+
apiKey: process.env.LBB_API_KEY, // lbb_sk_live_… — keep it server-side
|
|
19
17
|
});
|
|
20
18
|
const graph = lbb.graph("main");
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
// 1. Write a fact.
|
|
21
|
+
await graph.facts.create(
|
|
22
|
+
{
|
|
23
|
+
triplets: [
|
|
24
|
+
{
|
|
25
|
+
source: { type: "CONCEPT", name: "policy-42" },
|
|
26
|
+
relation: "RELATED_TO",
|
|
27
|
+
target: { type: "CONCEPT", name: "seven-year retention" },
|
|
28
|
+
evidence: "Customer records are retained for seven years.",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{ idempotencyKey: "policy-42-v1" },
|
|
33
|
+
);
|
|
30
34
|
|
|
35
|
+
// 2. Build persisted BM25 + vector + adjacency indexes and wait.
|
|
31
36
|
await graph.indexes.run({ wait: true });
|
|
32
37
|
|
|
38
|
+
// 3. Hybrid search over the snapshot.
|
|
33
39
|
const results = await graph.search.hybrid(
|
|
34
40
|
"How long are customer records retained?",
|
|
35
41
|
{ topK: 10, source: "persisted", consistency: "strong" },
|
|
36
42
|
);
|
|
37
43
|
```
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
## Enterprise search integrations
|
|
44
|
-
|
|
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:
|
|
48
|
-
|
|
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.
|
|
45
|
+
For hosted use, `baseUrl` is required and must be the exact `endpoint_url`
|
|
46
|
+
shown on the stack's Connect page. Graph and branch remain client scope
|
|
47
|
+
parameters; they are not encoded in the hostname.
|
|
56
48
|
|
|
57
|
-
|
|
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.
|
|
49
|
+
## Examples
|
|
61
50
|
|
|
62
|
-
|
|
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.
|
|
51
|
+
**Search with filters.** Pass the request body to filter before ranking — here, only facts an ACL principal may see:
|
|
67
52
|
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
```ts
|
|
54
|
+
const results = await graph.search.hybrid({
|
|
55
|
+
query: "incident response runbook",
|
|
56
|
+
targets: ["entities"],
|
|
57
|
+
search: {
|
|
58
|
+
filters: {
|
|
59
|
+
op: "overlaps",
|
|
60
|
+
field: "acl",
|
|
61
|
+
values: ["user:rino@example.com", "group:engineering"],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
top_k: 20,
|
|
65
|
+
});
|
|
66
|
+
```
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
**Bulk import.** Load an array of records (or an NDJSON string) in one call:
|
|
72
69
|
|
|
73
70
|
```ts
|
|
74
|
-
graph.facts.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
graph.schema.audit(...)
|
|
71
|
+
await graph.facts.import(
|
|
72
|
+
[
|
|
73
|
+
{ source: { type: "DOC", name: "handbook", key: "doc:42" }, relation: "HAS_PASSAGE", target: { type: "PASSAGE", name: "leave-policy", key: "p:42:1" } },
|
|
74
|
+
// …one record per line
|
|
75
|
+
],
|
|
76
|
+
{ idempotencyKey: "handbook-batch-1" },
|
|
77
|
+
);
|
|
82
78
|
```
|
|
83
79
|
|
|
84
|
-
|
|
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.
|
|
80
|
+
**Time-travel read.** Pin any search to a past instant — results reflect the graph as it was then:
|
|
89
81
|
|
|
90
|
-
|
|
91
|
-
|
|
82
|
+
```ts
|
|
83
|
+
const asOf = await graph.search.hybrid("retention policy", { asOf: "2026-01-01T00:00:00Z" });
|
|
84
|
+
```
|
|
92
85
|
|
|
93
|
-
|
|
86
|
+
**SPARQL.** `sparqlRows` runs a SPARQL 1.1 SELECT/ASK and returns parsed rows:
|
|
94
87
|
|
|
95
88
|
```ts
|
|
96
89
|
const { rows } = await lbb.sparqlRows({
|
|
@@ -98,15 +91,21 @@ const { rows } = await lbb.sparqlRows({
|
|
|
98
91
|
});
|
|
99
92
|
```
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
|
|
94
|
+
## Errors & retries
|
|
95
|
+
|
|
96
|
+
Methods return parsed JSON and throw `LbbError` (with `status`, `code`, `message`, `param`, `requestId`, `docUrl`) on any non-2xx response. Safe reads and idempotency-keyed writes retry `429`/`5xx` and network failures with full-jitter backoff, bounded by a retry budget (`retryBudgetMs`, default 60s) rather than a fixed count, and honor `Retry-After` — a terminal error the server marks non-retryable surfaces immediately. Use `rawRequest()` for response headers, request id, and retry/timing metadata.
|
|
97
|
+
|
|
98
|
+
## More
|
|
99
|
+
|
|
100
|
+
The `graph(...)` scope exposes `facts`, `search`, `entities`, `indexes`, `ontology`, `query`, `schema`, and `context` namespaces — covering managed embeddings, multi-query fusion, traversal, temporal state and history, SHACL, ontology evolution, and durable index jobs. Every generated shape is available as `Schemas["TypeName"]`.
|
|
101
|
+
|
|
102
|
+
Full reference and guides: [docs.littlebigbrain.com/sdks/typescript](https://docs.littlebigbrain.com/sdks/typescript/).
|
|
103
103
|
|
|
104
104
|
## Develop
|
|
105
105
|
|
|
106
106
|
```sh
|
|
107
107
|
npm install
|
|
108
|
-
npm run generate
|
|
108
|
+
npm run generate # regenerate types from contracts/openapi.json
|
|
109
109
|
npm run typecheck
|
|
110
110
|
npm test
|
|
111
|
-
npm run pack:check
|
|
112
111
|
```
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ImportLine, LbbClientOptions, LbbStackActivityResponse, LbbStackAc
|
|
|
2
2
|
import { type RequestOptions } from "./transport.js";
|
|
3
3
|
import { ContextNamespace, EntityNamespace, GraphNamespace, IndexNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace } from "./namespaces.js";
|
|
4
4
|
export { parseSparqlResults } from "./types.js";
|
|
5
|
-
export type { AttributeFilter, AttributeFilterOp, AttributeFilterValue, EntityAttributeFilterOptions, EntityPropertiesLine, FetchLike, FlatProperties, ImportLine, LbbClientOptions, LbbRequestEvent, LbbResponseEvent, LbbErrorPayload, LbbStackActivityResponse, LbbStackActivityWindow, ListResponse, RawLbbResponse, RdfExportOptions, RdfImportOptions, Schemas, SparqlResults, SparqlResultsJson, SparqlTerm, AskRequest, AskResponse, CommitRequest, CommitResponse, Entity, EntitySelector, GraphMetadata, GraphSummary, SchemaView, SearchRequest, SearchResponse, SearchResult, Snapshot, } from "./types.js";
|
|
5
|
+
export type { AttributeFilter, AttributeFilterOp, AttributeFilterValue, EntityAttributeFilterOptions, EntityPropertiesLine, FetchLike, FlatProperties, ImportLine, LbbClientOptions, LbbRequestEvent, LbbResponseEvent, LbbRetryEvent, LbbErrorPayload, LbbStackActivityResponse, LbbStackActivityWindow, ListResponse, RawLbbResponse, RdfExportOptions, RdfImportOptions, Schemas, SparqlResults, SparqlResultsJson, SparqlTerm, AskRequest, AskResponse, CommitRequest, CommitResponse, Entity, EntitySelector, GraphMetadata, GraphSummary, SchemaView, SearchRequest, SearchResponse, SearchResult, Snapshot, } from "./types.js";
|
|
6
6
|
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";
|
|
@@ -31,9 +31,11 @@ export declare class LbbClient {
|
|
|
31
31
|
private readonly apiVersion;
|
|
32
32
|
private readonly maxRetries;
|
|
33
33
|
private readonly retryDelayMs;
|
|
34
|
+
private readonly retryBudgetMs;
|
|
34
35
|
private readonly timeoutMs;
|
|
35
36
|
private readonly onRequest?;
|
|
36
37
|
private readonly onResponse?;
|
|
38
|
+
private readonly onRetry?;
|
|
37
39
|
readonly context: ContextNamespace;
|
|
38
40
|
readonly search: SearchNamespace;
|
|
39
41
|
readonly indexes: IndexNamespace;
|
|
@@ -132,15 +134,25 @@ export declare class LbbClient {
|
|
|
132
134
|
observe(body: Schemas["ObserveRequest"], opts?: {
|
|
133
135
|
idempotencyKey?: string;
|
|
134
136
|
}): Promise<Schemas["ObserveResponse"]>;
|
|
135
|
-
/**
|
|
136
|
-
* Delete every object under the scoped graph/branch — a destructive reset.
|
|
137
|
-
* `confirm` must equal the scoped graph id; the next commit re-initializes the
|
|
138
|
-
* graph. Branch-scoped: sibling branches are untouched.
|
|
139
|
-
*/
|
|
137
|
+
/** Delete the scoped graph, including every branch, feedback, and active graph-scoped job. */
|
|
140
138
|
deleteGraph(opts: {
|
|
141
139
|
confirm: string;
|
|
142
|
-
}): Promise<
|
|
140
|
+
}): Promise<Schemas["GraphDeleteResponse"]>;
|
|
141
|
+
/** Delete only the scoped branch. The server refuses to delete a graph's final live branch. */
|
|
142
|
+
deleteBranch(opts: {
|
|
143
|
+
confirm: string;
|
|
144
|
+
}): Promise<Schemas["GraphBranchDeleteResponse"]>;
|
|
143
145
|
embeddingConfig(): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
146
|
+
/** List the embedding models available on this deployment. */
|
|
147
|
+
embeddingModels(): Promise<Schemas["ManagedEmbeddingModelsResponse"]>;
|
|
148
|
+
/**
|
|
149
|
+
* Choose the model used automatically for writes and vector queries.
|
|
150
|
+
* Provider credentials and native dimension discovery stay server-side.
|
|
151
|
+
*/
|
|
152
|
+
setEmbeddingModel(modelId: string, opts?: {
|
|
153
|
+
autoEmbedQuery?: boolean;
|
|
154
|
+
}): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
155
|
+
/** Advanced configuration escape hatch. Prefer `setEmbeddingModel`. */
|
|
144
156
|
setEmbeddingConfig(body: Schemas["ManagedEmbeddingConfigRequest"]): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
145
157
|
submitEmbeddingBackfill(opts?: {
|
|
146
158
|
batchSize?: number;
|
|
@@ -539,6 +551,14 @@ export declare class LbbClient {
|
|
|
539
551
|
indexRun(opts?: {
|
|
540
552
|
background?: boolean;
|
|
541
553
|
}): Promise<unknown>;
|
|
554
|
+
/** Submit a durable full-index build. Requires a reconnect-safe idempotency key. */
|
|
555
|
+
indexSubmit(body: Partial<Schemas["IndexBuildOptions"]> | undefined, opts: {
|
|
556
|
+
idempotencyKey: string;
|
|
557
|
+
}): Promise<Schemas["SearchIndexJobStatusResponse"]>;
|
|
558
|
+
/** Poll a durable full-index build. */
|
|
559
|
+
indexJob(jobId: string): Promise<Schemas["SearchIndexJobStatusResponse"]>;
|
|
560
|
+
/** Cancel a durable full-index build. Repeated cancellation returns its current terminal status. */
|
|
561
|
+
cancelIndexJob(jobId: string): Promise<Schemas["SearchIndexJobStatusResponse"]>;
|
|
542
562
|
/** Append a BM25 delta segment for the unindexed WAL tail. */
|
|
543
563
|
indexDelta(): Promise<Schemas["IndexDeltaResponse"]>;
|
|
544
564
|
/** Preview or delete superseded persisted index runs. */
|
|
@@ -546,6 +566,14 @@ export declare class LbbClient {
|
|
|
546
566
|
keepRuns?: number;
|
|
547
567
|
dryRun?: boolean;
|
|
548
568
|
}): Promise<Schemas["IndexGcResponse"]>;
|
|
569
|
+
/** Submit durable, cancellable index garbage collection. */
|
|
570
|
+
indexGcSubmit(body: Schemas["IndexGcRequest"] | undefined, opts: {
|
|
571
|
+
idempotencyKey: string;
|
|
572
|
+
}): Promise<Schemas["IndexGcJobStatusResponse"]>;
|
|
573
|
+
/** Poll exact planning/deletion progress for durable index garbage collection. */
|
|
574
|
+
indexGcJob(jobId: string): Promise<Schemas["IndexGcJobStatusResponse"]>;
|
|
575
|
+
/** Cancel durable index garbage collection. */
|
|
576
|
+
cancelIndexGcJob(jobId: string): Promise<Schemas["IndexGcJobStatusResponse"]>;
|
|
549
577
|
/** Fold the WAL tail into snapshot segments. */
|
|
550
578
|
compact(opts?: {
|
|
551
579
|
minTailCommits?: number;
|
package/dist/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseSparqlResults } from "./types.js";
|
|
2
|
-
import { parseLbbError, parseResponseJson, retryAllowed,
|
|
2
|
+
import { bodyMarksTerminal, errorCodeFromBody, fullJitterBackoffMs, parseLbbError, parseResponseJson, retryAllowed, retryableStatus, retryDelayMs, sleep, } from "./transport.js";
|
|
3
3
|
import { ContextNamespace, EntityNamespace, GraphNamespace, IndexNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
|
|
4
4
|
export { parseSparqlResults } from "./types.js";
|
|
5
5
|
export { LbbError } from "./transport.js";
|
|
@@ -19,9 +19,11 @@ export class LbbClient {
|
|
|
19
19
|
apiVersion;
|
|
20
20
|
maxRetries;
|
|
21
21
|
retryDelayMs;
|
|
22
|
+
retryBudgetMs;
|
|
22
23
|
timeoutMs;
|
|
23
24
|
onRequest;
|
|
24
25
|
onResponse;
|
|
26
|
+
onRetry;
|
|
25
27
|
context;
|
|
26
28
|
search;
|
|
27
29
|
indexes;
|
|
@@ -30,23 +32,32 @@ export class LbbClient {
|
|
|
30
32
|
ontology;
|
|
31
33
|
query;
|
|
32
34
|
constructor(options) {
|
|
33
|
-
|
|
35
|
+
const baseUrl = options.baseUrl?.trim();
|
|
36
|
+
if (!baseUrl) {
|
|
37
|
+
throw new Error("baseUrl is required; copy endpoint_url from the stack's Connect page for hosted use");
|
|
38
|
+
}
|
|
39
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
34
40
|
this.apiKey = options.apiKey;
|
|
35
41
|
this.graphName = options.graph;
|
|
36
42
|
this.branchName = options.branch;
|
|
37
43
|
this.stack = options.stack;
|
|
38
44
|
this.apiVersion = options.apiVersion ?? "2026-06-22";
|
|
39
|
-
this.maxRetries = options.maxRetries ??
|
|
45
|
+
this.maxRetries = options.maxRetries ?? 6;
|
|
40
46
|
this.retryDelayMs = options.retryDelayMs ?? 100;
|
|
47
|
+
this.retryBudgetMs = options.retryBudgetMs ?? 60_000;
|
|
41
48
|
this.timeoutMs = options.timeoutMs ?? 120_000;
|
|
42
49
|
this.onRequest = options.onRequest;
|
|
43
50
|
this.onResponse = options.onResponse;
|
|
51
|
+
this.onRetry = options.onRetry;
|
|
44
52
|
if (!Number.isInteger(this.maxRetries) || this.maxRetries < 0) {
|
|
45
53
|
throw new RangeError("maxRetries must be a non-negative integer");
|
|
46
54
|
}
|
|
47
55
|
if (!Number.isFinite(this.retryDelayMs) || this.retryDelayMs < 0) {
|
|
48
56
|
throw new RangeError("retryDelayMs must be a non-negative number");
|
|
49
57
|
}
|
|
58
|
+
if (!Number.isFinite(this.retryBudgetMs) || this.retryBudgetMs < 0) {
|
|
59
|
+
throw new RangeError("retryBudgetMs must be a non-negative number");
|
|
60
|
+
}
|
|
50
61
|
if (!Number.isFinite(this.timeoutMs) || this.timeoutMs < 0) {
|
|
51
62
|
throw new RangeError("timeoutMs must be a non-negative number");
|
|
52
63
|
}
|
|
@@ -87,9 +98,11 @@ export class LbbClient {
|
|
|
87
98
|
apiVersion: this.apiVersion,
|
|
88
99
|
maxRetries: this.maxRetries,
|
|
89
100
|
retryDelayMs: this.retryDelayMs,
|
|
101
|
+
retryBudgetMs: this.retryBudgetMs,
|
|
90
102
|
timeoutMs: this.timeoutMs,
|
|
91
103
|
onRequest: this.onRequest,
|
|
92
104
|
onResponse: this.onResponse,
|
|
105
|
+
onRetry: this.onRetry,
|
|
93
106
|
});
|
|
94
107
|
}
|
|
95
108
|
buildUrl(path, query) {
|
|
@@ -135,6 +148,8 @@ export class LbbClient {
|
|
|
135
148
|
throw new RangeError("maxRetries must be a non-negative integer");
|
|
136
149
|
}
|
|
137
150
|
const startedAt = Date.now();
|
|
151
|
+
// Deadline is the binding limit; `maxRetries` is a secondary safety cap.
|
|
152
|
+
const deadline = startedAt + Math.max(0, opts.retryBudgetMs ?? this.retryBudgetMs);
|
|
138
153
|
const url = this.buildUrl(path, opts.query);
|
|
139
154
|
let attempts = 0;
|
|
140
155
|
let response;
|
|
@@ -175,8 +190,19 @@ export class LbbClient {
|
|
|
175
190
|
}), { name: "TimeoutError" })
|
|
176
191
|
: error;
|
|
177
192
|
if (!callerAborted && canRetry && attempt < maxRetries) {
|
|
178
|
-
|
|
179
|
-
|
|
193
|
+
const delayMs = fullJitterBackoffMs(this.retryDelayMs, attempt);
|
|
194
|
+
if (Date.now() + delayMs <= deadline) {
|
|
195
|
+
this.onRetry?.({
|
|
196
|
+
method: method.toUpperCase(),
|
|
197
|
+
url,
|
|
198
|
+
attempt: attempts,
|
|
199
|
+
status: undefined,
|
|
200
|
+
delayMs,
|
|
201
|
+
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
202
|
+
});
|
|
203
|
+
await sleep(delayMs);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
180
206
|
}
|
|
181
207
|
throw requestError;
|
|
182
208
|
}
|
|
@@ -193,7 +219,29 @@ export class LbbClient {
|
|
|
193
219
|
if (!canRetry) {
|
|
194
220
|
break;
|
|
195
221
|
}
|
|
196
|
-
|
|
222
|
+
// Honor the server's typed body verdict: a terminal error
|
|
223
|
+
// (`retryable: false`, e.g. an exhausted quota) is surfaced at once
|
|
224
|
+
// rather than retried to the budget.
|
|
225
|
+
if (bodyMarksTerminal(text)) {
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
const delayMs = retryDelayMs(this.retryDelayMs, attempt, {
|
|
229
|
+
retryAfterHeader: response.headers?.get("retry-after"),
|
|
230
|
+
body: text,
|
|
231
|
+
});
|
|
232
|
+
if (Date.now() + delayMs > deadline) {
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
this.onRetry?.({
|
|
236
|
+
method: method.toUpperCase(),
|
|
237
|
+
url,
|
|
238
|
+
attempt: attempts,
|
|
239
|
+
status: response.status,
|
|
240
|
+
errorCode: errorCodeFromBody(text),
|
|
241
|
+
delayMs,
|
|
242
|
+
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
243
|
+
});
|
|
244
|
+
await sleep(delayMs);
|
|
197
245
|
}
|
|
198
246
|
if (response === undefined)
|
|
199
247
|
throw new Error("request did not produce a response");
|
|
@@ -379,19 +427,38 @@ export class LbbClient {
|
|
|
379
427
|
idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("observe"),
|
|
380
428
|
});
|
|
381
429
|
}
|
|
382
|
-
/**
|
|
383
|
-
* Delete every object under the scoped graph/branch — a destructive reset.
|
|
384
|
-
* `confirm` must equal the scoped graph id; the next commit re-initializes the
|
|
385
|
-
* graph. Branch-scoped: sibling branches are untouched.
|
|
386
|
-
*/
|
|
430
|
+
/** Delete the scoped graph, including every branch, feedback, and active graph-scoped job. */
|
|
387
431
|
deleteGraph(opts) {
|
|
388
432
|
return this.request("POST", "/v1/graph/delete", {
|
|
389
433
|
query: { confirm: opts.confirm },
|
|
434
|
+
retry: true,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
/** Delete only the scoped branch. The server refuses to delete a graph's final live branch. */
|
|
438
|
+
deleteBranch(opts) {
|
|
439
|
+
return this.request("DELETE", "/v1/graph/branch", {
|
|
440
|
+
query: { confirm: opts.confirm },
|
|
390
441
|
});
|
|
391
442
|
}
|
|
392
443
|
embeddingConfig() {
|
|
393
444
|
return this.request("GET", "/v1/graph/embedding");
|
|
394
445
|
}
|
|
446
|
+
/** List the embedding models available on this deployment. */
|
|
447
|
+
embeddingModels() {
|
|
448
|
+
return this.request("GET", "/v1/graph/embedding/models");
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Choose the model used automatically for writes and vector queries.
|
|
452
|
+
* Provider credentials and native dimension discovery stay server-side.
|
|
453
|
+
*/
|
|
454
|
+
setEmbeddingModel(modelId, opts = {}) {
|
|
455
|
+
return this.setEmbeddingConfig({
|
|
456
|
+
model_id: modelId,
|
|
457
|
+
service: "open_router",
|
|
458
|
+
auto_embed_query: opts.autoEmbedQuery ?? true,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
/** Advanced configuration escape hatch. Prefer `setEmbeddingModel`. */
|
|
395
462
|
setEmbeddingConfig(body) {
|
|
396
463
|
return this.request("POST", "/v1/graph/embedding", { body });
|
|
397
464
|
}
|
|
@@ -951,6 +1018,23 @@ export class LbbClient {
|
|
|
951
1018
|
query: { background: opts.background || undefined },
|
|
952
1019
|
});
|
|
953
1020
|
}
|
|
1021
|
+
/** Submit a durable full-index build. Requires a reconnect-safe idempotency key. */
|
|
1022
|
+
indexSubmit(body = {}, opts) {
|
|
1023
|
+
return this.request("POST", "/v1/index/jobs", {
|
|
1024
|
+
body,
|
|
1025
|
+
idempotencyKey: opts.idempotencyKey,
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
/** Poll a durable full-index build. */
|
|
1029
|
+
indexJob(jobId) {
|
|
1030
|
+
return this.request("GET", "/v1/index/jobs", { query: { job_id: jobId } });
|
|
1031
|
+
}
|
|
1032
|
+
/** Cancel a durable full-index build. Repeated cancellation returns its current terminal status. */
|
|
1033
|
+
cancelIndexJob(jobId) {
|
|
1034
|
+
return this.request("DELETE", "/v1/index/jobs", {
|
|
1035
|
+
query: { job_id: jobId },
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
954
1038
|
/** Append a BM25 delta segment for the unindexed WAL tail. */
|
|
955
1039
|
indexDelta() {
|
|
956
1040
|
return this.request("POST", "/v1/index/delta");
|
|
@@ -961,6 +1045,25 @@ export class LbbClient {
|
|
|
961
1045
|
query: { keep_runs: opts.keepRuns, dry_run: opts.dryRun },
|
|
962
1046
|
});
|
|
963
1047
|
}
|
|
1048
|
+
/** Submit durable, cancellable index garbage collection. */
|
|
1049
|
+
indexGcSubmit(body = {}, opts) {
|
|
1050
|
+
return this.request("POST", "/v1/index/gc-jobs", {
|
|
1051
|
+
body,
|
|
1052
|
+
idempotencyKey: opts.idempotencyKey,
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
/** Poll exact planning/deletion progress for durable index garbage collection. */
|
|
1056
|
+
indexGcJob(jobId) {
|
|
1057
|
+
return this.request("GET", "/v1/index/gc-jobs", {
|
|
1058
|
+
query: { job_id: jobId },
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
/** Cancel durable index garbage collection. */
|
|
1062
|
+
cancelIndexGcJob(jobId) {
|
|
1063
|
+
return this.request("DELETE", "/v1/index/gc-jobs", {
|
|
1064
|
+
query: { job_id: jobId },
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
964
1067
|
/** Fold the WAL tail into snapshot segments. */
|
|
965
1068
|
compact(opts = {}) {
|
|
966
1069
|
return this.request("POST", "/v1/graph/compact", {
|
package/dist/namespaces.d.ts
CHANGED
|
@@ -32,8 +32,18 @@ export declare class GraphNamespace {
|
|
|
32
32
|
create(opts?: CallOptions): Promise<Schemas["CreateGraphResponse"]>;
|
|
33
33
|
delete(opts: {
|
|
34
34
|
confirm: string;
|
|
35
|
-
} & CallOptions): Promise<
|
|
35
|
+
} & CallOptions): Promise<Schemas["GraphDeleteResponse"]>;
|
|
36
|
+
deleteBranch(opts: {
|
|
37
|
+
confirm: string;
|
|
38
|
+
} & CallOptions): Promise<Schemas["GraphBranchDeleteResponse"]>;
|
|
36
39
|
embeddingConfig(opts?: CallOptions): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
40
|
+
/** List the embedding models available on this deployment. */
|
|
41
|
+
embeddingModels(opts?: CallOptions): Promise<Schemas["ManagedEmbeddingModelsResponse"]>;
|
|
42
|
+
/** Choose the model used automatically for writes and vector queries. */
|
|
43
|
+
setEmbeddingModel(modelId: string, options?: CallOptions & {
|
|
44
|
+
autoEmbedQuery?: boolean;
|
|
45
|
+
}): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
46
|
+
/** Advanced configuration escape hatch. Prefer `setEmbeddingModel`. */
|
|
37
47
|
setEmbeddingConfig(body: Schemas["ManagedEmbeddingConfigRequest"], opts?: CallOptions): Promise<Schemas["ManagedEmbeddingConfigResponse"]>;
|
|
38
48
|
backfillEmbeddings(options?: CallOptions & {
|
|
39
49
|
batchSize?: number;
|
|
@@ -115,10 +125,20 @@ export declare class IndexNamespace {
|
|
|
115
125
|
background?: boolean;
|
|
116
126
|
} & CallOptions): Promise<unknown>;
|
|
117
127
|
delta(opts?: CallOptions): Promise<Schemas["IndexDeltaResponse"]>;
|
|
128
|
+
submit(body: Partial<Schemas["IndexBuildOptions"]> | undefined, opts: CallOptions & {
|
|
129
|
+
idempotencyKey: string;
|
|
130
|
+
}): Promise<Schemas["SearchIndexJobStatusResponse"]>;
|
|
131
|
+
job(jobId: string, opts?: CallOptions): Promise<Schemas["SearchIndexJobStatusResponse"]>;
|
|
132
|
+
cancel(jobId: string, opts?: CallOptions): Promise<Schemas["SearchIndexJobStatusResponse"]>;
|
|
118
133
|
gc(opts?: {
|
|
119
134
|
keepRuns?: number;
|
|
120
135
|
dryRun?: boolean;
|
|
121
136
|
} & CallOptions): Promise<Schemas["IndexGcResponse"]>;
|
|
137
|
+
submitGc(body: Schemas["IndexGcRequest"] | undefined, opts: CallOptions & {
|
|
138
|
+
idempotencyKey: string;
|
|
139
|
+
}): Promise<Schemas["IndexGcJobStatusResponse"]>;
|
|
140
|
+
gcJob(jobId: string, opts?: CallOptions): Promise<Schemas["IndexGcJobStatusResponse"]>;
|
|
141
|
+
cancelGc(jobId: string, opts?: CallOptions): Promise<Schemas["IndexGcJobStatusResponse"]>;
|
|
122
142
|
}
|
|
123
143
|
export declare class EntityNamespace {
|
|
124
144
|
private readonly client;
|
package/dist/namespaces.js
CHANGED
|
@@ -41,11 +41,36 @@ export class GraphNamespace {
|
|
|
41
41
|
return this.client.request("POST", "/v1/graph/delete", {
|
|
42
42
|
...request,
|
|
43
43
|
query: { confirm },
|
|
44
|
+
retry: request.retry ?? true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
deleteBranch(opts) {
|
|
48
|
+
const { confirm, ...request } = opts;
|
|
49
|
+
return this.client.request("DELETE", "/v1/graph/branch", {
|
|
50
|
+
...request,
|
|
51
|
+
query: { confirm },
|
|
44
52
|
});
|
|
45
53
|
}
|
|
46
54
|
embeddingConfig(opts = {}) {
|
|
47
55
|
return this.client.request("GET", "/v1/graph/embedding", opts);
|
|
48
56
|
}
|
|
57
|
+
/** List the embedding models available on this deployment. */
|
|
58
|
+
embeddingModels(opts = {}) {
|
|
59
|
+
return this.client.request("GET", "/v1/graph/embedding/models", opts);
|
|
60
|
+
}
|
|
61
|
+
/** Choose the model used automatically for writes and vector queries. */
|
|
62
|
+
setEmbeddingModel(modelId, options = {}) {
|
|
63
|
+
const { autoEmbedQuery, ...request } = options;
|
|
64
|
+
return this.client.request("POST", "/v1/graph/embedding", {
|
|
65
|
+
...request,
|
|
66
|
+
body: {
|
|
67
|
+
model_id: modelId,
|
|
68
|
+
service: "open_router",
|
|
69
|
+
auto_embed_query: autoEmbedQuery ?? true,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** Advanced configuration escape hatch. Prefer `setEmbeddingModel`. */
|
|
49
74
|
setEmbeddingConfig(body, opts = {}) {
|
|
50
75
|
return this.client.request("POST", "/v1/graph/embedding", {
|
|
51
76
|
...opts,
|
|
@@ -276,6 +301,21 @@ export class IndexNamespace {
|
|
|
276
301
|
delta(opts = {}) {
|
|
277
302
|
return this.client.request("POST", "/v1/index/delta", opts);
|
|
278
303
|
}
|
|
304
|
+
submit(body = {}, opts) {
|
|
305
|
+
return this.client.request("POST", "/v1/index/jobs", { ...opts, body });
|
|
306
|
+
}
|
|
307
|
+
job(jobId, opts = {}) {
|
|
308
|
+
return this.client.request("GET", "/v1/index/jobs", {
|
|
309
|
+
...opts,
|
|
310
|
+
query: { job_id: jobId },
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
cancel(jobId, opts = {}) {
|
|
314
|
+
return this.client.request("DELETE", "/v1/index/jobs", {
|
|
315
|
+
...opts,
|
|
316
|
+
query: { job_id: jobId },
|
|
317
|
+
});
|
|
318
|
+
}
|
|
279
319
|
gc(opts = {}) {
|
|
280
320
|
const { keepRuns, dryRun, ...request } = opts;
|
|
281
321
|
return this.client.request("POST", "/v1/index/gc", {
|
|
@@ -283,6 +323,21 @@ export class IndexNamespace {
|
|
|
283
323
|
query: { keep_runs: keepRuns, dry_run: dryRun },
|
|
284
324
|
});
|
|
285
325
|
}
|
|
326
|
+
submitGc(body = {}, opts) {
|
|
327
|
+
return this.client.request("POST", "/v1/index/gc-jobs", { ...opts, body });
|
|
328
|
+
}
|
|
329
|
+
gcJob(jobId, opts = {}) {
|
|
330
|
+
return this.client.request("GET", "/v1/index/gc-jobs", {
|
|
331
|
+
...opts,
|
|
332
|
+
query: { job_id: jobId },
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
cancelGc(jobId, opts = {}) {
|
|
336
|
+
return this.client.request("DELETE", "/v1/index/gc-jobs", {
|
|
337
|
+
...opts,
|
|
338
|
+
query: { job_id: jobId },
|
|
339
|
+
});
|
|
340
|
+
}
|
|
286
341
|
}
|
|
287
342
|
export class EntityNamespace {
|
|
288
343
|
client;
|