@oberik/sdk 0.65.0 → 0.67.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/dist/cjs/index.js +65 -9
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +108 -12
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +65 -9
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -773,6 +773,25 @@ function asBlob(input) {
|
|
|
773
773
|
// handing that straight to Blob can carry bytes belonging to something else.
|
|
774
774
|
return new Blob([bytes.slice()]);
|
|
775
775
|
}
|
|
776
|
+
/**
|
|
777
|
+
* The name a document is stored under: what the caller passed, the file's own, or a
|
|
778
|
+
* placeholder.
|
|
779
|
+
*
|
|
780
|
+
* One function for both clients, because they disagreed about it. The project client
|
|
781
|
+
* derived a name and fell back to `"upload.bin"`; the end-user client took `filename` in a
|
|
782
|
+
* **required** options object, so a JavaScript caller writing the documented
|
|
783
|
+
* `uploadAndWait(file)` got `TypeError: Cannot read properties of undefined (reading
|
|
784
|
+
* 'filename')` — thrown from inside the SDK, with nothing in the stack naming Oberik, at
|
|
785
|
+
* the reader most likely to have copied the snippet (OBE-195).
|
|
786
|
+
*
|
|
787
|
+
* Both are optional now and both land here. `"upload.bin"` rather than a refusal: a `File`
|
|
788
|
+
* carries its name and a Blob, Buffer or ArrayBuffer does not, and an upload that arrives
|
|
789
|
+
* with a placeholder name is visibly wrong in the listing, where a caller can fix it with
|
|
790
|
+
* `documents.update`. Pass `filename` — it is what the document is listed and cited under.
|
|
791
|
+
*/
|
|
792
|
+
function uploadName(file, filename) {
|
|
793
|
+
return filename || file?.name || "upload.bin";
|
|
794
|
+
}
|
|
776
795
|
/** Normalise whatever an `onQuestion` handler returned into an answer the API accepts.
|
|
777
796
|
*
|
|
778
797
|
* A handler returning a bare string was silently ignored. `{ ...answer }` on a string
|
|
@@ -2361,17 +2380,35 @@ class AgentFramework {
|
|
|
2361
2380
|
},
|
|
2362
2381
|
};
|
|
2363
2382
|
documents = {
|
|
2383
|
+
/**
|
|
2384
|
+
* One PAGE of documents, newest first — `{ items, has_more, next_offset }`.
|
|
2385
|
+
*
|
|
2386
|
+
* It was a bare array, which asserts completeness by omission, on the one collection
|
|
2387
|
+
* that only grows: a live project of 302 documents returned all 302 and 181KB on every
|
|
2388
|
+
* call, and a 10k corpus would be ~6MB on a route a dashboard opens with (OBE-190).
|
|
2389
|
+
* `limit` defaults to 100 and is capped at 500; page with `next_offset`, which is given
|
|
2390
|
+
* rather than left as arithmetic because the cap can make `offset + limit` wrong.
|
|
2391
|
+
*
|
|
2392
|
+
* `with_total` adds a `total` and costs a second query — for a summary, not for paging.
|
|
2393
|
+
* "Is there another page" is `has_more`, and it is free.
|
|
2394
|
+
*/
|
|
2364
2395
|
list: (query = {}) => this.request("GET", "/documents", { query }),
|
|
2365
2396
|
get: (id) => this.request("GET", `/documents/${id}`),
|
|
2366
2397
|
delete: (id) => this.request("DELETE", `/documents/${id}`),
|
|
2367
2398
|
retrieve: (body) => this.request("POST", "/documents/retrieve", { body }),
|
|
2368
2399
|
/** Small-file convenience upload via multipart form (server proxies to S3). */
|
|
2369
|
-
uploadSimple: async (file,
|
|
2400
|
+
uploadSimple: async (file,
|
|
2401
|
+
// Optional, and the same shape the project client takes: this signature required an
|
|
2402
|
+
// options object, so `uploadSimple(file)` and `uploadAndWait(file)` — the way the
|
|
2403
|
+
// docs write them — threw a TypeError out of the SDK's own body instead of saying
|
|
2404
|
+
// what was missing (OBE-195).
|
|
2405
|
+
opts = {}) => {
|
|
2406
|
+
const filename = uploadName(file, opts.filename);
|
|
2370
2407
|
const form = new FormData();
|
|
2371
2408
|
const blob = typeof Blob !== "undefined" && file instanceof Blob
|
|
2372
2409
|
? file
|
|
2373
2410
|
: new Blob([file], { type: opts.contentType ?? "application/octet-stream" });
|
|
2374
|
-
form.append("file", blob,
|
|
2411
|
+
form.append("file", blob, filename);
|
|
2375
2412
|
form.append("tags", (opts.tags ?? []).join(","));
|
|
2376
2413
|
// Set visibility AT UPLOAD, not after: a document is retrievable as soon as
|
|
2377
2414
|
// ingestion finishes, so patching later leaves a window where it's readable by
|
|
@@ -2404,7 +2441,7 @@ class AgentFramework {
|
|
|
2404
2441
|
return (await res.json());
|
|
2405
2442
|
},
|
|
2406
2443
|
/** Resumable presigned multipart upload (direct to S3). */
|
|
2407
|
-
upload: (file, opts) => this.multipartUpload(file, opts),
|
|
2444
|
+
upload: (file, opts = {}) => this.multipartUpload(file, opts),
|
|
2408
2445
|
/** Poll a document until ingestion finishes (status "ready" or "failed").
|
|
2409
2446
|
* Ingestion is async, so querying a just-uploaded doc may return nothing until
|
|
2410
2447
|
* this resolves. Throws on "failed" or timeout. */
|
|
@@ -2428,7 +2465,7 @@ class AgentFramework {
|
|
|
2428
2465
|
// Takes the ACL fields too: this is the upload most callers use, so omitting them
|
|
2429
2466
|
// here forced a second `patch` and left a window where the document was already
|
|
2430
2467
|
// retrievable at its default visibility.
|
|
2431
|
-
opts) => {
|
|
2468
|
+
opts = {}) => {
|
|
2432
2469
|
const doc = await this.documents.uploadSimple(file, opts);
|
|
2433
2470
|
return this.documents.waitReady(doc.id, { timeoutMs: opts.timeoutMs, signal: opts.signal });
|
|
2434
2471
|
},
|
|
@@ -3089,7 +3126,7 @@ class AgentFramework {
|
|
|
3089
3126
|
const maxRetries = opts.maxRetries ?? 5;
|
|
3090
3127
|
const presign = await this.request("POST", "/documents/presign-upload", {
|
|
3091
3128
|
body: {
|
|
3092
|
-
filename: opts.filename,
|
|
3129
|
+
filename: uploadName(file, opts.filename),
|
|
3093
3130
|
content_type: opts.contentType,
|
|
3094
3131
|
tags: opts.tags ?? [],
|
|
3095
3132
|
...(opts.visibility ? { visibility: opts.visibility } : {}),
|
|
@@ -3369,6 +3406,9 @@ class OberikProject {
|
|
|
3369
3406
|
* turning citation markers off, meant dropping to raw HTTP through `raw()`.
|
|
3370
3407
|
*/
|
|
3371
3408
|
project = {
|
|
3409
|
+
/** The project, its capability ceiling and its settings — plus `readiness` and the
|
|
3410
|
+
* `health` / `healthDetail` badge, so "is this project working" is answered by the
|
|
3411
|
+
* first thing you fetch rather than one route further on. */
|
|
3372
3412
|
get: () => this.request("GET", ""),
|
|
3373
3413
|
/** Merges — send only what you want to change. */
|
|
3374
3414
|
set: (fields) => this.request("PATCH", "", fields),
|
|
@@ -3442,9 +3482,26 @@ class OberikProject {
|
|
|
3442
3482
|
* accepted nor needed — a recipe that worked by luck rather than by expression.
|
|
3443
3483
|
*/
|
|
3444
3484
|
documents = {
|
|
3445
|
-
/**
|
|
3485
|
+
/**
|
|
3486
|
+
* One PAGE of the corpus — the same envelope, the same filters and the same paging as
|
|
3487
|
+
* the end-user client's `documents.list`, because they are the same route.
|
|
3488
|
+
*
|
|
3489
|
+
* The route became a page in OBE-190 and this declaration did not move with it: it
|
|
3490
|
+
* still said `Promise<DocumentOut[]>`, so a TypeScript caller wrote `.length` and got
|
|
3491
|
+
* `undefined` with no type error and no exception — a census that counted documents
|
|
3492
|
+
* reported zero. That is OBE-147 verbatim, one collection over, and the docstring
|
|
3493
|
+
* describing it sits sixty lines above this one (OBE-195). The query type had the
|
|
3494
|
+
* mirror-image gap: `limit`/`offset` worked at runtime and were unwritable in
|
|
3495
|
+
* TypeScript, so the documented paging loop did not compile against the client that
|
|
3496
|
+
* recommends it.
|
|
3497
|
+
*
|
|
3498
|
+
* `with_total` adds a `total`; it is what "how big is this corpus" is asked with, and
|
|
3499
|
+
* it costs a second query. "Is there another page" is `has_more`, and it is free.
|
|
3500
|
+
*/
|
|
3446
3501
|
list: (query = {}) => {
|
|
3447
|
-
const qs = new URLSearchParams(Object.entries(query)
|
|
3502
|
+
const qs = new URLSearchParams(Object.entries(query)
|
|
3503
|
+
.filter(([, v]) => v != null)
|
|
3504
|
+
.map(([k, v]) => [k, String(v)])).toString();
|
|
3448
3505
|
return this.request("GET", `/documents${qs ? `?${qs}` : ""}`);
|
|
3449
3506
|
},
|
|
3450
3507
|
get: (documentId) => this.request("GET", `/documents/${documentId}`),
|
|
@@ -3489,8 +3546,7 @@ class OberikProject {
|
|
|
3489
3546
|
*/
|
|
3490
3547
|
opts = {}) => {
|
|
3491
3548
|
const form = new FormData();
|
|
3492
|
-
|
|
3493
|
-
form.append("file", asBlob(file), name);
|
|
3549
|
+
form.append("file", asBlob(file), uploadName(file, opts.filename));
|
|
3494
3550
|
form.append("tags", (opts.tags ?? []).join(","));
|
|
3495
3551
|
if (opts.visibility)
|
|
3496
3552
|
form.append("visibility", opts.visibility);
|