@babav/knowledge-core-client 0.28.0 → 0.30.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/index.d.ts +54 -0
- package/dist/index.js +57 -0
- package/package.json +1 -1
- package/src/index.ts +86 -2
package/dist/index.d.ts
CHANGED
|
@@ -181,6 +181,7 @@ export interface Corpus {
|
|
|
181
181
|
id: UUID;
|
|
182
182
|
name: string;
|
|
183
183
|
description: string | null;
|
|
184
|
+
custom_metadata: Record<string, unknown>;
|
|
184
185
|
}
|
|
185
186
|
export interface Folder {
|
|
186
187
|
id: UUID;
|
|
@@ -530,6 +531,16 @@ export declare class KnowledgeCoreClient extends HttpBase {
|
|
|
530
531
|
* error). Pass `signal` and abort() on unmount / when the user cancels or navigates away so the
|
|
531
532
|
* connection doesn't linger. Transient (ends on `done`) — no reopen logic needed. */
|
|
532
533
|
queryStream(agentId: UUID, body: QueryRequest, handlers: StreamHandlers, signal?: AbortSignal): Promise<void>;
|
|
534
|
+
/** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
|
|
535
|
+
* to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
|
|
536
|
+
* `query`/`queryStream` ONLY for programmatic one-shots (tools).
|
|
537
|
+
* New chat: const chat = kc.chat(agentId, corpusIds);
|
|
538
|
+
* Resume: const chat = kc.chat(agentId, corpusIds, { conversationId });
|
|
539
|
+
* The conversation is created LAZILY on the first `send()` (opening a "new chat" and never
|
|
540
|
+
* sending leaves nothing behind). See ChatSession.send. */
|
|
541
|
+
chat(agentId: UUID, corpusIds: UUID[], opts?: {
|
|
542
|
+
conversationId?: UUID;
|
|
543
|
+
}): ChatSession;
|
|
533
544
|
/** Shared SSE reader for the document-status streams (documents.events / folders.events).
|
|
534
545
|
* Resolves when the stream ends (server sends `complete` once nothing is in-flight, or the
|
|
535
546
|
* cap is hit). Abort via the signal to stop watching. Throws 501 if the env has no bus. */
|
|
@@ -549,16 +560,25 @@ export declare class KnowledgeCoreClient extends HttpBase {
|
|
|
549
560
|
create: (b: {
|
|
550
561
|
name: string;
|
|
551
562
|
description?: string;
|
|
563
|
+
custom_metadata?: Record<string, unknown>;
|
|
552
564
|
}) => Promise<Corpus>;
|
|
553
565
|
list: (q?: {
|
|
554
566
|
limit?: number;
|
|
555
567
|
cursor?: string;
|
|
556
568
|
}) => Promise<Page<Corpus>>;
|
|
557
569
|
listAll: () => Promise<Corpus[]>;
|
|
570
|
+
/** Filter corpora by custom_metadata using the same metadata filter as documents. */
|
|
571
|
+
search: (b: {
|
|
572
|
+
filter?: MetadataFilter;
|
|
573
|
+
limit?: number;
|
|
574
|
+
cursor?: string;
|
|
575
|
+
}) => Promise<Page<Corpus>>;
|
|
558
576
|
get: (id: UUID) => Promise<Corpus>;
|
|
577
|
+
/** `custom_metadata` merges (provided keys upsert, a null value deletes a key). */
|
|
559
578
|
update: (id: UUID, b: {
|
|
560
579
|
name?: string;
|
|
561
580
|
description?: string;
|
|
581
|
+
custom_metadata?: Record<string, unknown>;
|
|
562
582
|
}) => Promise<Corpus>;
|
|
563
583
|
delete: (id: UUID, confirmName: string) => Promise<void>;
|
|
564
584
|
listFolders: (id: UUID) => Promise<Folder[]>;
|
|
@@ -886,3 +906,37 @@ export declare class AdminClient extends HttpBase {
|
|
|
886
906
|
delete: (id: UUID) => Promise<void>;
|
|
887
907
|
};
|
|
888
908
|
}
|
|
909
|
+
export interface ChatSendOptions extends StreamHandlers {
|
|
910
|
+
overrides?: QueryRequest["overrides"];
|
|
911
|
+
filter?: QueryRequest["filter"];
|
|
912
|
+
visual?: QueryRequest["visual"];
|
|
913
|
+
/** Abort on unmount / navigation so the SSE connection doesn't linger. */
|
|
914
|
+
signal?: AbortSignal;
|
|
915
|
+
/** Applied ONLY when the conversation is lazily created on the FIRST message. `title` defaults
|
|
916
|
+
* to the message text (truncated) so a chat is never left untitled. */
|
|
917
|
+
title?: string;
|
|
918
|
+
customMetadata?: Record<string, unknown>;
|
|
919
|
+
ephemeral?: boolean;
|
|
920
|
+
/** Fired with the conversation id the moment it is created (first message) or resumed — use it to
|
|
921
|
+
* update the sidebar/URL/route IMMEDIATELY, before the answer streams. */
|
|
922
|
+
onConversationId?: (id: UUID) => void;
|
|
923
|
+
}
|
|
924
|
+
/** A chat session bound to ONE conversation (created via `kc.chat(...)`). Every `send()` is ALWAYS
|
|
925
|
+
* conversational: the conversation_id is attached for you, so a chat turn can never be a
|
|
926
|
+
* non-persisted one-shot. Combined with server-side persist-on-close salvage + the orphan reaper,
|
|
927
|
+
* a chat turn is never lost and a chat conversation is never left blank. */
|
|
928
|
+
export declare class ChatSession {
|
|
929
|
+
#private;
|
|
930
|
+
/** The conversation id — null until the first `send()` (unless resumed). */
|
|
931
|
+
conversationId: UUID | null;
|
|
932
|
+
constructor(kc: KnowledgeCoreClient, agentId: UUID, corpusIds: UUID[], conversationId: UUID | null);
|
|
933
|
+
/** Send a chat message (streaming). Lazily creates the conversation on the first message and
|
|
934
|
+
* ALWAYS passes conversation_id, so the turn is persisted. `onConversationId` fires before the
|
|
935
|
+
* stream so you can show the conversation immediately. Pass `signal` to cancel on unmount. */
|
|
936
|
+
send(text: string, o?: ChatSendOptions): Promise<void>;
|
|
937
|
+
/** The conversation history (messages), once it exists. Empty page before the first send. */
|
|
938
|
+
messages(q?: {
|
|
939
|
+
limit?: number;
|
|
940
|
+
cursor?: string;
|
|
941
|
+
}): Promise<Page<Message>>;
|
|
942
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -178,6 +178,16 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
178
178
|
if (buf.trim())
|
|
179
179
|
dispatchSse(buf, handlers);
|
|
180
180
|
}
|
|
181
|
+
/** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
|
|
182
|
+
* to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
|
|
183
|
+
* `query`/`queryStream` ONLY for programmatic one-shots (tools).
|
|
184
|
+
* New chat: const chat = kc.chat(agentId, corpusIds);
|
|
185
|
+
* Resume: const chat = kc.chat(agentId, corpusIds, { conversationId });
|
|
186
|
+
* The conversation is created LAZILY on the first `send()` (opening a "new chat" and never
|
|
187
|
+
* sending leaves nothing behind). See ChatSession.send. */
|
|
188
|
+
chat(agentId, corpusIds, opts) {
|
|
189
|
+
return new ChatSession(this, agentId, corpusIds, opts?.conversationId ?? null);
|
|
190
|
+
}
|
|
181
191
|
/** Shared SSE reader for the document-status streams (documents.events / folders.events).
|
|
182
192
|
* Resolves when the stream ends (server sends `complete` once nothing is in-flight, or the
|
|
183
193
|
* cap is hit). Abort via the signal to stop watching. Throws 501 if the env has no bus. */
|
|
@@ -219,7 +229,10 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
219
229
|
create: (b) => this.request("POST", "/v1/corpora", { json: b }),
|
|
220
230
|
list: (q) => this.request("GET", "/v1/corpora", { query: q }),
|
|
221
231
|
listAll: () => this.pageAll("/v1/corpora"),
|
|
232
|
+
/** Filter corpora by custom_metadata using the same metadata filter as documents. */
|
|
233
|
+
search: (b) => this.request("POST", "/v1/corpora/search", { json: b }),
|
|
222
234
|
get: (id) => this.request("GET", `/v1/corpora/${id}`),
|
|
235
|
+
/** `custom_metadata` merges (provided keys upsert, a null value deletes a key). */
|
|
223
236
|
update: (id, b) => this.request("PATCH", `/v1/corpora/${id}`, { json: b }),
|
|
224
237
|
delete: (id, confirmName) => this.request("DELETE", `/v1/corpora/${id}`, { query: { confirm: confirmName } }),
|
|
225
238
|
listFolders: (id) => this.pageAll(`/v1/corpora/${id}/folders`),
|
|
@@ -457,6 +470,50 @@ export class AdminClient extends HttpBase {
|
|
|
457
470
|
delete: (id) => this.request("DELETE", `/v1/agents/${id}`),
|
|
458
471
|
};
|
|
459
472
|
}
|
|
473
|
+
/** A chat session bound to ONE conversation (created via `kc.chat(...)`). Every `send()` is ALWAYS
|
|
474
|
+
* conversational: the conversation_id is attached for you, so a chat turn can never be a
|
|
475
|
+
* non-persisted one-shot. Combined with server-side persist-on-close salvage + the orphan reaper,
|
|
476
|
+
* a chat turn is never lost and a chat conversation is never left blank. */
|
|
477
|
+
export class ChatSession {
|
|
478
|
+
#kc;
|
|
479
|
+
#agentId;
|
|
480
|
+
#corpusIds;
|
|
481
|
+
#creating = null;
|
|
482
|
+
/** The conversation id — null until the first `send()` (unless resumed). */
|
|
483
|
+
conversationId;
|
|
484
|
+
constructor(kc, agentId, corpusIds, conversationId) {
|
|
485
|
+
this.#kc = kc;
|
|
486
|
+
this.#agentId = agentId;
|
|
487
|
+
this.#corpusIds = corpusIds;
|
|
488
|
+
this.conversationId = conversationId;
|
|
489
|
+
}
|
|
490
|
+
/** Lazy create-once (concurrency-safe): the first send starts creation; a racing send awaits it. */
|
|
491
|
+
#ensure(o, text) {
|
|
492
|
+
if (this.conversationId)
|
|
493
|
+
return Promise.resolve(this.conversationId);
|
|
494
|
+
if (!this.#creating) {
|
|
495
|
+
this.#creating = this.#kc.conversations
|
|
496
|
+
.create({ title: o.title ?? text.slice(0, 80), custom_metadata: o.customMetadata, ephemeral: o.ephemeral })
|
|
497
|
+
.then((c) => { this.conversationId = c.id; return c.id; });
|
|
498
|
+
}
|
|
499
|
+
return this.#creating;
|
|
500
|
+
}
|
|
501
|
+
/** Send a chat message (streaming). Lazily creates the conversation on the first message and
|
|
502
|
+
* ALWAYS passes conversation_id, so the turn is persisted. `onConversationId` fires before the
|
|
503
|
+
* stream so you can show the conversation immediately. Pass `signal` to cancel on unmount. */
|
|
504
|
+
async send(text, o = {}) {
|
|
505
|
+
const convId = await this.#ensure(o, text);
|
|
506
|
+
o.onConversationId?.(convId);
|
|
507
|
+
await this.#kc.queryStream(this.#agentId, { corpus_ids: this.#corpusIds, query: text, conversation_id: convId,
|
|
508
|
+
overrides: o.overrides, filter: o.filter, visual: o.visual }, o, o.signal);
|
|
509
|
+
}
|
|
510
|
+
/** The conversation history (messages), once it exists. Empty page before the first send. */
|
|
511
|
+
messages(q) {
|
|
512
|
+
if (!this.conversationId)
|
|
513
|
+
return Promise.resolve({ items: [], next_cursor: null });
|
|
514
|
+
return this.#kc.conversations.listMessages(this.conversationId, q);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
460
517
|
// ---------------------------------------------------------------------------
|
|
461
518
|
// helpers
|
|
462
519
|
// ---------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babav/knowledge-core-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
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
|
@@ -211,6 +211,7 @@ export interface Corpus {
|
|
|
211
211
|
id: UUID;
|
|
212
212
|
name: string;
|
|
213
213
|
description: string | null;
|
|
214
|
+
custom_metadata: Record<string, unknown>;
|
|
214
215
|
}
|
|
215
216
|
export interface Folder {
|
|
216
217
|
id: UUID;
|
|
@@ -644,6 +645,17 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
644
645
|
if (buf.trim()) dispatchSse(buf, handlers);
|
|
645
646
|
}
|
|
646
647
|
|
|
648
|
+
/** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
|
|
649
|
+
* to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
|
|
650
|
+
* `query`/`queryStream` ONLY for programmatic one-shots (tools).
|
|
651
|
+
* New chat: const chat = kc.chat(agentId, corpusIds);
|
|
652
|
+
* Resume: const chat = kc.chat(agentId, corpusIds, { conversationId });
|
|
653
|
+
* The conversation is created LAZILY on the first `send()` (opening a "new chat" and never
|
|
654
|
+
* sending leaves nothing behind). See ChatSession.send. */
|
|
655
|
+
chat(agentId: UUID, corpusIds: UUID[], opts?: { conversationId?: UUID }): ChatSession {
|
|
656
|
+
return new ChatSession(this, agentId, corpusIds, opts?.conversationId ?? null);
|
|
657
|
+
}
|
|
658
|
+
|
|
647
659
|
/** Shared SSE reader for the document-status streams (documents.events / folders.events).
|
|
648
660
|
* Resolves when the stream ends (server sends `complete` once nothing is in-flight, or the
|
|
649
661
|
* cap is hit). Abort via the signal to stop watching. Throws 501 if the env has no bus. */
|
|
@@ -679,12 +691,16 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
679
691
|
|
|
680
692
|
// --- corpora ---
|
|
681
693
|
corpora = {
|
|
682
|
-
create: (b: { name: string; description?: string }) =>
|
|
694
|
+
create: (b: { name: string; description?: string; custom_metadata?: Record<string, unknown> }) =>
|
|
683
695
|
this.request<Corpus>("POST", "/v1/corpora", { json: b }),
|
|
684
696
|
list: (q?: { limit?: number; cursor?: string }) => this.request<Page<Corpus>>("GET", "/v1/corpora", { query: q }),
|
|
685
697
|
listAll: () => this.pageAll<Corpus>("/v1/corpora"),
|
|
698
|
+
/** Filter corpora by custom_metadata using the same metadata filter as documents. */
|
|
699
|
+
search: (b: { filter?: MetadataFilter; limit?: number; cursor?: string }) =>
|
|
700
|
+
this.request<Page<Corpus>>("POST", "/v1/corpora/search", { json: b }),
|
|
686
701
|
get: (id: UUID) => this.request<Corpus>("GET", `/v1/corpora/${id}`),
|
|
687
|
-
|
|
702
|
+
/** `custom_metadata` merges (provided keys upsert, a null value deletes a key). */
|
|
703
|
+
update: (id: UUID, b: { name?: string; description?: string; custom_metadata?: Record<string, unknown> }) =>
|
|
688
704
|
this.request<Corpus>("PATCH", `/v1/corpora/${id}`, { json: b }),
|
|
689
705
|
delete: (id: UUID, confirmName: string) => this.request<void>("DELETE", `/v1/corpora/${id}`, { query: { confirm: confirmName } }),
|
|
690
706
|
listFolders: (id: UUID) => this.pageAll<Folder>(`/v1/corpora/${id}/folders`),
|
|
@@ -996,6 +1012,74 @@ export class AdminClient extends HttpBase {
|
|
|
996
1012
|
};
|
|
997
1013
|
}
|
|
998
1014
|
|
|
1015
|
+
export interface ChatSendOptions extends StreamHandlers {
|
|
1016
|
+
overrides?: QueryRequest["overrides"];
|
|
1017
|
+
filter?: QueryRequest["filter"];
|
|
1018
|
+
visual?: QueryRequest["visual"];
|
|
1019
|
+
/** Abort on unmount / navigation so the SSE connection doesn't linger. */
|
|
1020
|
+
signal?: AbortSignal;
|
|
1021
|
+
/** Applied ONLY when the conversation is lazily created on the FIRST message. `title` defaults
|
|
1022
|
+
* to the message text (truncated) so a chat is never left untitled. */
|
|
1023
|
+
title?: string;
|
|
1024
|
+
customMetadata?: Record<string, unknown>;
|
|
1025
|
+
ephemeral?: boolean;
|
|
1026
|
+
/** Fired with the conversation id the moment it is created (first message) or resumed — use it to
|
|
1027
|
+
* update the sidebar/URL/route IMMEDIATELY, before the answer streams. */
|
|
1028
|
+
onConversationId?: (id: UUID) => void;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/** A chat session bound to ONE conversation (created via `kc.chat(...)`). Every `send()` is ALWAYS
|
|
1032
|
+
* conversational: the conversation_id is attached for you, so a chat turn can never be a
|
|
1033
|
+
* non-persisted one-shot. Combined with server-side persist-on-close salvage + the orphan reaper,
|
|
1034
|
+
* a chat turn is never lost and a chat conversation is never left blank. */
|
|
1035
|
+
export class ChatSession {
|
|
1036
|
+
#kc: KnowledgeCoreClient;
|
|
1037
|
+
#agentId: UUID;
|
|
1038
|
+
#corpusIds: UUID[];
|
|
1039
|
+
#creating: Promise<UUID> | null = null;
|
|
1040
|
+
/** The conversation id — null until the first `send()` (unless resumed). */
|
|
1041
|
+
conversationId: UUID | null;
|
|
1042
|
+
|
|
1043
|
+
constructor(kc: KnowledgeCoreClient, agentId: UUID, corpusIds: UUID[], conversationId: UUID | null) {
|
|
1044
|
+
this.#kc = kc;
|
|
1045
|
+
this.#agentId = agentId;
|
|
1046
|
+
this.#corpusIds = corpusIds;
|
|
1047
|
+
this.conversationId = conversationId;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/** Lazy create-once (concurrency-safe): the first send starts creation; a racing send awaits it. */
|
|
1051
|
+
#ensure(o: ChatSendOptions, text: string): Promise<UUID> {
|
|
1052
|
+
if (this.conversationId) return Promise.resolve(this.conversationId);
|
|
1053
|
+
if (!this.#creating) {
|
|
1054
|
+
this.#creating = this.#kc.conversations
|
|
1055
|
+
.create({ title: o.title ?? text.slice(0, 80), custom_metadata: o.customMetadata, ephemeral: o.ephemeral })
|
|
1056
|
+
.then((c) => { this.conversationId = c.id; return c.id; });
|
|
1057
|
+
}
|
|
1058
|
+
return this.#creating;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/** Send a chat message (streaming). Lazily creates the conversation on the first message and
|
|
1062
|
+
* ALWAYS passes conversation_id, so the turn is persisted. `onConversationId` fires before the
|
|
1063
|
+
* stream so you can show the conversation immediately. Pass `signal` to cancel on unmount. */
|
|
1064
|
+
async send(text: string, o: ChatSendOptions = {}): Promise<void> {
|
|
1065
|
+
const convId = await this.#ensure(o, text);
|
|
1066
|
+
o.onConversationId?.(convId);
|
|
1067
|
+
await this.#kc.queryStream(
|
|
1068
|
+
this.#agentId,
|
|
1069
|
+
{ corpus_ids: this.#corpusIds, query: text, conversation_id: convId,
|
|
1070
|
+
overrides: o.overrides, filter: o.filter, visual: o.visual },
|
|
1071
|
+
o,
|
|
1072
|
+
o.signal,
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
/** The conversation history (messages), once it exists. Empty page before the first send. */
|
|
1077
|
+
messages(q?: { limit?: number; cursor?: string }): Promise<Page<Message>> {
|
|
1078
|
+
if (!this.conversationId) return Promise.resolve({ items: [], next_cursor: null });
|
|
1079
|
+
return this.#kc.conversations.listMessages(this.conversationId, q);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
999
1083
|
// ---------------------------------------------------------------------------
|
|
1000
1084
|
// helpers
|
|
1001
1085
|
// ---------------------------------------------------------------------------
|