@babav/knowledge-core-client 0.22.4 → 0.22.5
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/index.d.ts +35 -0
- package/dist/index.js +62 -0
- package/package.json +1 -1
- package/src/index.ts +78 -0
package/dist/index.d.ts
CHANGED
|
@@ -359,12 +359,41 @@ export interface StreamHandlers {
|
|
|
359
359
|
/** Catch-all for any event (incl. unknown ones). */
|
|
360
360
|
onEvent?: (event: string, data: unknown) => void;
|
|
361
361
|
}
|
|
362
|
+
/** A live document status transition pushed over the ingestion-status SSE stream
|
|
363
|
+
* (documents.events / folders.events). Replaces polling GET /documents/count. */
|
|
364
|
+
export interface DocumentStatusEvent {
|
|
365
|
+
document_id: string;
|
|
366
|
+
corpus_id?: string | null;
|
|
367
|
+
folder_id?: string | null;
|
|
368
|
+
status: string;
|
|
369
|
+
filename?: string | null;
|
|
370
|
+
chunk_count?: number | null;
|
|
371
|
+
error?: string | null;
|
|
372
|
+
counts?: DocumentCount;
|
|
373
|
+
}
|
|
374
|
+
export interface DocumentEventsSnapshot {
|
|
375
|
+
documents: DocumentStatusEvent[];
|
|
376
|
+
counts: DocumentCount;
|
|
377
|
+
}
|
|
378
|
+
export interface DocumentEventHandlers {
|
|
379
|
+
/** Current state on connect (one query) — render the list from this. */
|
|
380
|
+
onSnapshot?: (s: DocumentEventsSnapshot) => void;
|
|
381
|
+
/** A single document's status changed (the moment it happened). Update that row + counts. */
|
|
382
|
+
onDocument?: (e: DocumentStatusEvent) => void;
|
|
383
|
+
/** Nothing is in-flight anymore — the stream is about to close. Authoritative final counts. */
|
|
384
|
+
onComplete?: (counts: DocumentCount) => void;
|
|
385
|
+
onError?: (err: unknown) => void;
|
|
386
|
+
}
|
|
362
387
|
export declare class KnowledgeCoreClient extends HttpBase {
|
|
363
388
|
/** @param opts.apiKey a TENANT key, supplied by the caller. */
|
|
364
389
|
constructor(opts: ClientOptions);
|
|
365
390
|
query(agentId: UUID, body: QueryRequest): Promise<QueryResponse>;
|
|
366
391
|
/** Streaming query (SSE). Resolves when the stream ends. */
|
|
367
392
|
queryStream(agentId: UUID, body: QueryRequest, handlers: StreamHandlers, signal?: AbortSignal): Promise<void>;
|
|
393
|
+
/** Shared SSE reader for the document-status streams (documents.events / folders.events).
|
|
394
|
+
* Resolves when the stream ends (server sends `complete` once nothing is in-flight, or the
|
|
395
|
+
* cap is hit). Abort via the signal to stop watching. Throws 501 if the env has no bus. */
|
|
396
|
+
_streamDocEvents(path: string, handlers: DocumentEventHandlers, signal?: AbortSignal): Promise<void>;
|
|
368
397
|
retrieve(body: {
|
|
369
398
|
query: string;
|
|
370
399
|
corpus_ids: UUID[];
|
|
@@ -466,6 +495,8 @@ export declare class KnowledgeCoreClient extends HttpBase {
|
|
|
466
495
|
limit?: number;
|
|
467
496
|
cursor?: string;
|
|
468
497
|
}) => Promise<Page<Document>>;
|
|
498
|
+
/** Live ingestion-status stream for ONE folder (same contract as documents.events). */
|
|
499
|
+
events: (folderId: UUID, handlers: DocumentEventHandlers, signal?: AbortSignal) => Promise<void>;
|
|
469
500
|
};
|
|
470
501
|
documents: {
|
|
471
502
|
get: (id: UUID) => Promise<Document>;
|
|
@@ -478,6 +509,10 @@ export declare class KnowledgeCoreClient extends HttpBase {
|
|
|
478
509
|
}) => Promise<Document>;
|
|
479
510
|
contentUrl: (id: UUID, disposition?: "inline" | "attachment") => Promise<ContentUrl>;
|
|
480
511
|
delete: (id: UUID) => Promise<void>;
|
|
512
|
+
/** Live ingestion-status stream for a corpus (SSE PUSH — replaces polling count). Snapshot on
|
|
513
|
+
* connect, then a delta per transition, then `complete` when nothing is in-flight. Abort via
|
|
514
|
+
* the signal. 501 (onError) if the environment has no doc-status bus — fall back to polling. */
|
|
515
|
+
events: (corpusId: UUID, handlers: DocumentEventHandlers, signal?: AbortSignal) => Promise<void>;
|
|
481
516
|
};
|
|
482
517
|
conversations: {
|
|
483
518
|
create: (b?: {
|
package/dist/index.js
CHANGED
|
@@ -176,6 +176,38 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
176
176
|
if (buf.trim())
|
|
177
177
|
dispatchSse(buf, handlers);
|
|
178
178
|
}
|
|
179
|
+
/** Shared SSE reader for the document-status streams (documents.events / folders.events).
|
|
180
|
+
* Resolves when the stream ends (server sends `complete` once nothing is in-flight, or the
|
|
181
|
+
* cap is hit). Abort via the signal to stop watching. Throws 501 if the env has no bus. */
|
|
182
|
+
async _streamDocEvents(path, handlers, signal) {
|
|
183
|
+
const res = await this.raw("GET", path, { signal });
|
|
184
|
+
if (!res.ok || !res.body) {
|
|
185
|
+
const t = await res.text();
|
|
186
|
+
const err = new KnowledgeCoreError(res.status, safeJson(t), path);
|
|
187
|
+
if (handlers.onError) {
|
|
188
|
+
handlers.onError(err);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
throw err;
|
|
192
|
+
}
|
|
193
|
+
const reader = res.body.getReader();
|
|
194
|
+
const decoder = new TextDecoder();
|
|
195
|
+
let buf = "";
|
|
196
|
+
for (;;) {
|
|
197
|
+
const { value, done } = await reader.read();
|
|
198
|
+
if (done)
|
|
199
|
+
break;
|
|
200
|
+
buf += decoder.decode(value, { stream: true });
|
|
201
|
+
let idx;
|
|
202
|
+
while ((idx = buf.indexOf("\n\n")) !== -1) {
|
|
203
|
+
const frame = buf.slice(0, idx);
|
|
204
|
+
buf = buf.slice(idx + 2);
|
|
205
|
+
dispatchDocEvent(frame, handlers);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (buf.trim())
|
|
209
|
+
dispatchDocEvent(buf, handlers);
|
|
210
|
+
}
|
|
179
211
|
// --- retrieve (cross-corpus primitive, no generation) ---
|
|
180
212
|
retrieve(body) {
|
|
181
213
|
return this.request("POST", "/v1/retrieve", { json: body });
|
|
@@ -255,6 +287,8 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
255
287
|
countDocuments: (folderId) => this.request("GET", `/v1/folders/${folderId}/documents/count`),
|
|
256
288
|
/** Documents in the folder whose filename contains `q` (case-insensitive), paginated. */
|
|
257
289
|
searchDocuments: (folderId, q, opts) => this.request("GET", `/v1/folders/${folderId}/documents/search`, { query: { q, ...opts } }),
|
|
290
|
+
/** Live ingestion-status stream for ONE folder (same contract as documents.events). */
|
|
291
|
+
events: (folderId, handlers, signal) => this._streamDocEvents(`/v1/folders/${folderId}/documents/events`, handlers, signal),
|
|
258
292
|
};
|
|
259
293
|
// --- documents ---
|
|
260
294
|
documents = {
|
|
@@ -265,6 +299,10 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
265
299
|
update: (id, b) => this.request("PATCH", `/v1/documents/${id}`, { json: b }),
|
|
266
300
|
contentUrl: (id, disposition = "inline") => this.request("GET", `/v1/documents/${id}/content-url`, { query: { disposition } }),
|
|
267
301
|
delete: (id) => this.request("DELETE", `/v1/documents/${id}`),
|
|
302
|
+
/** Live ingestion-status stream for a corpus (SSE PUSH — replaces polling count). Snapshot on
|
|
303
|
+
* connect, then a delta per transition, then `complete` when nothing is in-flight. Abort via
|
|
304
|
+
* the signal. 501 (onError) if the environment has no doc-status bus — fall back to polling. */
|
|
305
|
+
events: (corpusId, handlers, signal) => this._streamDocEvents(`/v1/corpora/${corpusId}/documents/events`, handlers, signal),
|
|
268
306
|
};
|
|
269
307
|
// --- conversations ---
|
|
270
308
|
conversations = {
|
|
@@ -384,3 +422,27 @@ function dispatchSse(frame, h) {
|
|
|
384
422
|
break;
|
|
385
423
|
}
|
|
386
424
|
}
|
|
425
|
+
function dispatchDocEvent(frame, h) {
|
|
426
|
+
let event = "message";
|
|
427
|
+
const dataLines = [];
|
|
428
|
+
for (const line of frame.split("\n")) {
|
|
429
|
+
if (line.startsWith("event:"))
|
|
430
|
+
event = line.slice(6).trim();
|
|
431
|
+
else if (line.startsWith("data:"))
|
|
432
|
+
dataLines.push(line.slice(5).trim());
|
|
433
|
+
}
|
|
434
|
+
if (dataLines.length === 0)
|
|
435
|
+
return; // heartbeat / comment frame
|
|
436
|
+
const data = safeJson(dataLines.join("\n"));
|
|
437
|
+
switch (event) {
|
|
438
|
+
case "snapshot":
|
|
439
|
+
h.onSnapshot?.(data);
|
|
440
|
+
break;
|
|
441
|
+
case "document":
|
|
442
|
+
h.onDocument?.(data);
|
|
443
|
+
break;
|
|
444
|
+
case "complete":
|
|
445
|
+
h.onComplete?.(data);
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babav/knowledge-core-client",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.5",
|
|
4
4
|
"description": "TypeScript client for the Babav Knowledge Core API (Deno + Node 18+, zero deps). Includes the babav.visual grammar TYPES at the ./visual subpath (types only; all visual rendering is server-side).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
package/src/index.ts
CHANGED
|
@@ -480,6 +480,32 @@ export interface StreamHandlers {
|
|
|
480
480
|
onEvent?: (event: string, data: unknown) => void;
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
+
/** A live document status transition pushed over the ingestion-status SSE stream
|
|
484
|
+
* (documents.events / folders.events). Replaces polling GET /documents/count. */
|
|
485
|
+
export interface DocumentStatusEvent {
|
|
486
|
+
document_id: string;
|
|
487
|
+
corpus_id?: string | null;
|
|
488
|
+
folder_id?: string | null;
|
|
489
|
+
status: string; // pending | ingesting | indexed | failed | deleting
|
|
490
|
+
filename?: string | null;
|
|
491
|
+
chunk_count?: number | null;
|
|
492
|
+
error?: string | null;
|
|
493
|
+
counts?: DocumentCount; // running aggregate, included on each `document` delta
|
|
494
|
+
}
|
|
495
|
+
export interface DocumentEventsSnapshot {
|
|
496
|
+
documents: DocumentStatusEvent[]; // current state of every doc in the corpus/folder
|
|
497
|
+
counts: DocumentCount;
|
|
498
|
+
}
|
|
499
|
+
export interface DocumentEventHandlers {
|
|
500
|
+
/** Current state on connect (one query) — render the list from this. */
|
|
501
|
+
onSnapshot?: (s: DocumentEventsSnapshot) => void;
|
|
502
|
+
/** A single document's status changed (the moment it happened). Update that row + counts. */
|
|
503
|
+
onDocument?: (e: DocumentStatusEvent) => void;
|
|
504
|
+
/** Nothing is in-flight anymore — the stream is about to close. Authoritative final counts. */
|
|
505
|
+
onComplete?: (counts: DocumentCount) => void;
|
|
506
|
+
onError?: (err: unknown) => void;
|
|
507
|
+
}
|
|
508
|
+
|
|
483
509
|
// ---------------------------------------------------------------------------
|
|
484
510
|
// Tenant client (data ops) — use a TENANT key
|
|
485
511
|
// ---------------------------------------------------------------------------
|
|
@@ -518,6 +544,34 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
518
544
|
if (buf.trim()) dispatchSse(buf, handlers);
|
|
519
545
|
}
|
|
520
546
|
|
|
547
|
+
/** Shared SSE reader for the document-status streams (documents.events / folders.events).
|
|
548
|
+
* Resolves when the stream ends (server sends `complete` once nothing is in-flight, or the
|
|
549
|
+
* cap is hit). Abort via the signal to stop watching. Throws 501 if the env has no bus. */
|
|
550
|
+
async _streamDocEvents(path: string, handlers: DocumentEventHandlers, signal?: AbortSignal): Promise<void> {
|
|
551
|
+
const res = await this.raw("GET", path, { signal });
|
|
552
|
+
if (!res.ok || !res.body) {
|
|
553
|
+
const t = await res.text();
|
|
554
|
+
const err = new KnowledgeCoreError(res.status, safeJson(t), path);
|
|
555
|
+
if (handlers.onError) { handlers.onError(err); return; }
|
|
556
|
+
throw err;
|
|
557
|
+
}
|
|
558
|
+
const reader = res.body.getReader();
|
|
559
|
+
const decoder = new TextDecoder();
|
|
560
|
+
let buf = "";
|
|
561
|
+
for (;;) {
|
|
562
|
+
const { value, done } = await reader.read();
|
|
563
|
+
if (done) break;
|
|
564
|
+
buf += decoder.decode(value, { stream: true });
|
|
565
|
+
let idx: number;
|
|
566
|
+
while ((idx = buf.indexOf("\n\n")) !== -1) {
|
|
567
|
+
const frame = buf.slice(0, idx);
|
|
568
|
+
buf = buf.slice(idx + 2);
|
|
569
|
+
dispatchDocEvent(frame, handlers);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (buf.trim()) dispatchDocEvent(buf, handlers);
|
|
573
|
+
}
|
|
574
|
+
|
|
521
575
|
// --- retrieve (cross-corpus primitive, no generation) ---
|
|
522
576
|
retrieve(body: { query: string; corpus_ids: UUID[]; top_k_retrieved_chunks?: number; top_k_reranked_chunks?: number; rerank?: boolean; instruction?: string; filter?: MetadataFilter; }): Promise<{ retrieval_contents: RetrievalContent[] }> {
|
|
523
577
|
return this.request("POST", "/v1/retrieve", { json: body });
|
|
@@ -607,6 +661,9 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
607
661
|
/** Documents in the folder whose filename contains `q` (case-insensitive), paginated. */
|
|
608
662
|
searchDocuments: (folderId: UUID, q: string, opts?: { limit?: number; cursor?: string }) =>
|
|
609
663
|
this.request<Page<Document>>("GET", `/v1/folders/${folderId}/documents/search`, { query: { q, ...opts } }),
|
|
664
|
+
/** Live ingestion-status stream for ONE folder (same contract as documents.events). */
|
|
665
|
+
events: (folderId: UUID, handlers: DocumentEventHandlers, signal?: AbortSignal) =>
|
|
666
|
+
this._streamDocEvents(`/v1/folders/${folderId}/documents/events`, handlers, signal),
|
|
610
667
|
};
|
|
611
668
|
|
|
612
669
|
// --- documents ---
|
|
@@ -620,6 +677,11 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
620
677
|
contentUrl: (id: UUID, disposition: "inline" | "attachment" = "inline") =>
|
|
621
678
|
this.request<ContentUrl>("GET", `/v1/documents/${id}/content-url`, { query: { disposition } }),
|
|
622
679
|
delete: (id: UUID) => this.request<void>("DELETE", `/v1/documents/${id}`),
|
|
680
|
+
/** Live ingestion-status stream for a corpus (SSE PUSH — replaces polling count). Snapshot on
|
|
681
|
+
* connect, then a delta per transition, then `complete` when nothing is in-flight. Abort via
|
|
682
|
+
* the signal. 501 (onError) if the environment has no doc-status bus — fall back to polling. */
|
|
683
|
+
events: (corpusId: UUID, handlers: DocumentEventHandlers, signal?: AbortSignal) =>
|
|
684
|
+
this._streamDocEvents(`/v1/corpora/${corpusId}/documents/events`, handlers, signal),
|
|
623
685
|
};
|
|
624
686
|
|
|
625
687
|
// --- conversations ---
|
|
@@ -733,3 +795,19 @@ function dispatchSse(frame: string, h: StreamHandlers): void {
|
|
|
733
795
|
case "done": h.onDone?.(); break;
|
|
734
796
|
}
|
|
735
797
|
}
|
|
798
|
+
|
|
799
|
+
function dispatchDocEvent(frame: string, h: DocumentEventHandlers): void {
|
|
800
|
+
let event = "message";
|
|
801
|
+
const dataLines: string[] = [];
|
|
802
|
+
for (const line of frame.split("\n")) {
|
|
803
|
+
if (line.startsWith("event:")) event = line.slice(6).trim();
|
|
804
|
+
else if (line.startsWith("data:")) dataLines.push(line.slice(5).trim());
|
|
805
|
+
}
|
|
806
|
+
if (dataLines.length === 0) return; // heartbeat / comment frame
|
|
807
|
+
const data = safeJson(dataLines.join("\n"));
|
|
808
|
+
switch (event) {
|
|
809
|
+
case "snapshot": h.onSnapshot?.(data as DocumentEventsSnapshot); break;
|
|
810
|
+
case "document": h.onDocument?.(data as DocumentStatusEvent); break;
|
|
811
|
+
case "complete": h.onComplete?.(data as DocumentCount); break;
|
|
812
|
+
}
|
|
813
|
+
}
|