@littlebigbrain/client 0.6.0 → 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 CHANGED
@@ -1,106 +1,89 @@
1
1
  # @littlebigbrain/client
2
2
 
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`.
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
- ## Five-minute start
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
- await graph.facts.create({
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" });
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
- 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.
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
- `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.
49
+ ## Examples
61
50
 
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.
51
+ **Search with filters.** Pass the request body to filter before ranking — here, only facts an ACL principal may see:
67
52
 
68
- The [enterprise-search integration guide](https://docs.littlebigbrain.com/guides/enterprise-search/)
69
- contains the graph model, migration sequence, and acceptance tests.
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
- ## Main surface
68
+ **Bulk import.** Load an array of records (or an NDJSON string) in one call:
72
69
 
73
70
  ```ts
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(...)
82
-
83
- const build = await graph.indexes.submit({}, { idempotencyKey: "index:head:147" })
84
- await graph.indexes.job(build.job_id)
85
- await graph.indexes.cancel(build.job_id)
86
-
87
- const gc = await graph.indexes.submitGc({ dry_run: false }, { idempotencyKey: "gc:2026-07-15" })
88
- await graph.indexes.gcJob(gc.job_id)
89
-
90
- await graph.branch("review").deleteBranch({ confirm: "review" })
91
- await graph.delete({ confirm: "main" }) // whole graph, every branch
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
+ );
92
78
  ```
93
79
 
94
- Other focused methods cover managed embeddings, full-text/vector search,
95
- multi-query fusion, traversal, temporal state/history, SHACL, ontology
96
- evolution, feedback, indexing, and graph inspection. Request/response types are
97
- generated from `contracts/openapi.json`; common aliases and the complete
98
- `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:
99
81
 
100
- Use `rawRequest()` when you need response headers, request ID, retry count, or
101
- elapsed time. `onRequest` and `onResponse` provide body-free instrumentation.
82
+ ```ts
83
+ const asOf = await graph.search.hybrid("retention policy", { asOf: "2026-01-01T00:00:00Z" });
84
+ ```
102
85
 
103
- ## SPARQL
86
+ **SPARQL.** `sparqlRows` runs a SPARQL 1.1 SELECT/ASK and returns parsed rows:
104
87
 
105
88
  ```ts
106
89
  const { rows } = await lbb.sparqlRows({
@@ -108,15 +91,21 @@ const { rows } = await lbb.sparqlRows({
108
91
  });
109
92
  ```
110
93
 
111
- `sparqlRows` parses SELECT/ASK results. The native SPARQL 1.1 Protocol is also
112
- available at `/sparql` for standard RDF clients.
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/).
113
103
 
114
104
  ## Develop
115
105
 
116
106
  ```sh
117
107
  npm install
118
- npm run generate
108
+ npm run generate # regenerate types from contracts/openapi.json
119
109
  npm run typecheck
120
110
  npm test
121
- npm run pack:check
122
111
  ```
package/dist/client.js CHANGED
@@ -32,7 +32,11 @@ export class LbbClient {
32
32
  ontology;
33
33
  query;
34
34
  constructor(options) {
35
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
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(/\/+$/, "");
36
40
  this.apiKey = options.apiKey;
37
41
  this.graphName = options.graph;
38
42
  this.branchName = options.branch;
@@ -34,6 +34,8 @@ export declare class LbbError extends Error {
34
34
  readonly docUrl?: string | null;
35
35
  readonly retryable?: boolean;
36
36
  readonly retryAfterSeconds?: number;
37
+ /** Actionable guidance for composite stack-endpoint routing errors. */
38
+ readonly endpointHint?: string;
37
39
  constructor(status: number, body: string, error?: LbbErrorPayload | undefined);
38
40
  }
39
41
  export type QueryValue = string | number | boolean | undefined;
package/dist/transport.js CHANGED
@@ -10,6 +10,8 @@ export class LbbError extends Error {
10
10
  docUrl;
11
11
  retryable;
12
12
  retryAfterSeconds;
13
+ /** Actionable guidance for composite stack-endpoint routing errors. */
14
+ endpointHint;
13
15
  constructor(status, body, error) {
14
16
  super(error?.message ?? `Little Big Brain ${status}: ${body}`);
15
17
  this.status = status;
@@ -23,8 +25,18 @@ export class LbbError extends Error {
23
25
  this.docUrl = error?.doc_url;
24
26
  this.retryable = error?.retryable;
25
27
  this.retryAfterSeconds = error?.retry_after_seconds;
28
+ this.endpointHint = endpointMigrationHint(this.code);
26
29
  }
27
30
  }
31
+ function endpointMigrationHint(code) {
32
+ if (code === "stack_endpoint_required") {
33
+ return "Copy endpoint_url from the stack's Connect page and use it as baseUrl.";
34
+ }
35
+ if (code === "stack_endpoint_mismatch") {
36
+ return "Use the endpoint_url and API key from the same stack.";
37
+ }
38
+ return undefined;
39
+ }
28
40
  export function sleep(ms) {
29
41
  if (ms <= 0)
30
42
  return Promise.resolve();
package/dist/types.d.ts CHANGED
@@ -153,7 +153,7 @@ export declare function parseSparqlResults(response: Schemas["SparqlTextResponse
153
153
  export declare function firstPatternVariable(patterns: Schemas["AnalyticTriplePattern"][]): string;
154
154
  export declare function attributeFilter(filter: AttributeFilter, defaultVar: string): Schemas["SparqlFilter"];
155
155
  export interface LbbClientOptions {
156
- /** Base URL of the little big brain server, e.g. `https://db.eu.littlebigbrain.com`. */
156
+ /** Hosted stack endpoint, e.g. `https://7k3m9q2x--production.db.eu.littlebigbrain.com`. */
157
157
  baseUrl: string;
158
158
  /** Stack API key (`lbb_sk_test_…` / `lbb_sk_live_…`) or single-mode token. */
159
159
  apiKey?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@littlebigbrain/client",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "TypeScript client for the little big brain graph + hybrid search HTTP API",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {