@babav/knowledge-core-client 0.31.0 → 0.33.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 +48 -17
- package/dist/index.js +27 -0
- package/package.json +1 -1
- package/src/index.ts +70 -17
package/dist/index.d.ts
CHANGED
|
@@ -94,36 +94,37 @@ export interface QueryRequest {
|
|
|
94
94
|
* "free" = renderer's judgment / not a declared arrangement (also the value for non-conceptual
|
|
95
95
|
* registers). */
|
|
96
96
|
export type VisualLayout = "linear-flow" | "ring-cycle" | "nesting" | "radial-hub" | "side-by-side" | "stacked-layers" | "two-state" | "free";
|
|
97
|
-
/** A visual attached to a response
|
|
98
|
-
* system as citations).
|
|
97
|
+
/** A visual attached to a response.
|
|
99
98
|
*
|
|
100
|
-
*
|
|
101
|
-
* PNG served
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* parses inline SVG. `rendered_svg` appears ONLY as a rare fail-soft fallback (server rasterization
|
|
106
|
-
* failed); prefer `image` and treat `rendered_svg` as a last resort. */
|
|
99
|
+
* IDs-ONLY: the API never returns a URL. Every visual (chart / structural / conceptual / scenic) is
|
|
100
|
+
* a PNG served by KC and identified by its `id`. To display it, fetch the bytes by id —
|
|
101
|
+
* `getVisualImage(visual.id)` for one, or `getVisualImages([...ids])` to fetch a whole answer's
|
|
102
|
+
* visuals in a SINGLE call (no per-visual fan-out). The image is authenticated + tenant-scoped
|
|
103
|
+
* exactly like every other KC call; there is no URL, no signed GCS link. */
|
|
107
104
|
export interface Visual {
|
|
108
105
|
id: string;
|
|
109
|
-
|
|
106
|
+
/** Char offsets into `answer` (SAME coordinate system as citations). OPTIONAL: a visual may be
|
|
107
|
+
* anchorless (belongs in the trailing strip) — when absent, place it after the answer. */
|
|
108
|
+
anchor?: {
|
|
110
109
|
start: number;
|
|
111
110
|
end: number;
|
|
112
111
|
};
|
|
113
112
|
register: "chart" | "structural" | "conceptual" | "scenic";
|
|
114
|
-
|
|
113
|
+
/** Client display ordering (higher first). OPTIONAL — default to 0 / arrival order if absent. */
|
|
114
|
+
priority?: number;
|
|
115
115
|
payload: Record<string, unknown>;
|
|
116
116
|
/** Declared spatial arrangement (meaningful for `conceptual`; "free" otherwise). */
|
|
117
117
|
layout: VisualLayout;
|
|
118
|
-
/**
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
/** Pixel dimensions of the PNG — ALWAYS present on a shipped visual, so the UI can reserve space
|
|
119
|
+
* before the bytes arrive (no layout shift). Fetch the bytes with getVisualImage(id). */
|
|
120
|
+
image: {
|
|
121
121
|
width: number;
|
|
122
122
|
height: number;
|
|
123
|
-
expires_at?: number;
|
|
124
123
|
};
|
|
125
|
-
/**
|
|
126
|
-
|
|
124
|
+
/** Short KC-authored figure caption (the idea the visual carries). Present when authored. */
|
|
125
|
+
caption?: string;
|
|
126
|
+
/** Plain-text description for screen readers / accessible PDF·DOCX·LaTeX export. Present when authored. */
|
|
127
|
+
alt?: string;
|
|
127
128
|
}
|
|
128
129
|
/** Visual stage (streaming): generation has started. MAY be emitted twice — first with
|
|
129
130
|
* `pending: null` (started, count unknown), then again with the ACCURATE post-vet count before
|
|
@@ -132,8 +133,24 @@ export interface VisualsPending {
|
|
|
132
133
|
pending: number | null;
|
|
133
134
|
}
|
|
134
135
|
export interface VisualsMeta {
|
|
136
|
+
/** Visuals that shipped (authoritative — always matches the number of `visual` events). */
|
|
135
137
|
count: number;
|
|
138
|
+
/** Concepts accepted by the vet but not shipped (render_failed + timeout). */
|
|
136
139
|
dropped: number;
|
|
140
|
+
/** Counts-by-cause for every PROPOSED concept that did not become a visible visual, so a missing
|
|
141
|
+
* visual is explainable rather than silent. Keys (zero causes omitted):
|
|
142
|
+
* - `declined` the vet declined/trimmed the concept (never promised; reduces the pending count)
|
|
143
|
+
* - `render_failed` accepted but authoring/rendering/vision-review dropped it
|
|
144
|
+
* - `timeout` accepted but the post-answer render budget cut it off
|
|
145
|
+
* `dropped` = render_failed + timeout; `declined` is extra context beyond `dropped`. */
|
|
146
|
+
dropped_reasons?: Record<string, number>;
|
|
147
|
+
}
|
|
148
|
+
/** One image returned by getVisualImages(). `blob` is the PNG (browser: `URL.createObjectURL(blob)`). */
|
|
149
|
+
export interface VisualImage {
|
|
150
|
+
id: string;
|
|
151
|
+
blob: Blob;
|
|
152
|
+
width: number;
|
|
153
|
+
height: number;
|
|
137
154
|
}
|
|
138
155
|
export interface QueryResponse {
|
|
139
156
|
conversation_id: UUID | null;
|
|
@@ -541,6 +558,20 @@ export declare class KnowledgeCoreClient extends HttpBase {
|
|
|
541
558
|
* error). Pass `signal` and abort() on unmount / when the user cancels or navigates away so the
|
|
542
559
|
* connection doesn't linger. Transient (ends on `done`) — no reopen logic needed. */
|
|
543
560
|
queryStream(agentId: UUID, body: QueryRequest, handlers: StreamHandlers, signal?: AbortSignal): Promise<void>;
|
|
561
|
+
/** Fetch a visual's PNG bytes BY ID. This is the ONLY way to get a visual image — the API never
|
|
562
|
+
* returns a URL. Authenticated + tenant-scoped like every call. Use `visual.id` from a query
|
|
563
|
+
* response / streamed `visual` event / persisted message. Returns a Blob (browser: `URL.
|
|
564
|
+
* createObjectURL(blob)` for an <img>; Node: `Buffer.from(await blob.arrayBuffer())`). */
|
|
565
|
+
getVisualImage(visualId: UUID | string, signal?: AbortSignal): Promise<Blob>;
|
|
566
|
+
/** Fetch MANY visual PNGs in ONE call — the way to load all of an answer's (or a conversation's)
|
|
567
|
+
* visuals without a per-visual round trip. Pass up to 32 ids; over that, split into chunks (the
|
|
568
|
+
* API returns 400 `too_many_ids`). Returns the found images (as Blobs, ready for
|
|
569
|
+
* `URL.createObjectURL`) plus `missing` — ids with no stored image (reaped/expired), which the UI
|
|
570
|
+
* can show as "visual no longer available". Order of `images` is not guaranteed; key by `id`. */
|
|
571
|
+
getVisualImages(visualIds: Array<UUID | string>, signal?: AbortSignal): Promise<{
|
|
572
|
+
images: VisualImage[];
|
|
573
|
+
missing: string[];
|
|
574
|
+
}>;
|
|
544
575
|
/** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
|
|
545
576
|
* to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
|
|
546
577
|
* `query`/`queryStream` ONLY for programmatic one-shots (tools).
|
package/dist/index.js
CHANGED
|
@@ -178,6 +178,33 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
178
178
|
if (buf.trim())
|
|
179
179
|
dispatchSse(buf, handlers);
|
|
180
180
|
}
|
|
181
|
+
/** Fetch a visual's PNG bytes BY ID. This is the ONLY way to get a visual image — the API never
|
|
182
|
+
* returns a URL. Authenticated + tenant-scoped like every call. Use `visual.id` from a query
|
|
183
|
+
* response / streamed `visual` event / persisted message. Returns a Blob (browser: `URL.
|
|
184
|
+
* createObjectURL(blob)` for an <img>; Node: `Buffer.from(await blob.arrayBuffer())`). */
|
|
185
|
+
async getVisualImage(visualId, signal) {
|
|
186
|
+
const res = await this.raw("GET", `/v1/visuals/${visualId}/image`, { signal });
|
|
187
|
+
if (!res.ok) {
|
|
188
|
+
const t = await res.text();
|
|
189
|
+
throw new KnowledgeCoreError(res.status, safeJson(t), `/v1/visuals/${visualId}/image`);
|
|
190
|
+
}
|
|
191
|
+
return await res.blob();
|
|
192
|
+
}
|
|
193
|
+
/** Fetch MANY visual PNGs in ONE call — the way to load all of an answer's (or a conversation's)
|
|
194
|
+
* visuals without a per-visual round trip. Pass up to 32 ids; over that, split into chunks (the
|
|
195
|
+
* API returns 400 `too_many_ids`). Returns the found images (as Blobs, ready for
|
|
196
|
+
* `URL.createObjectURL`) plus `missing` — ids with no stored image (reaped/expired), which the UI
|
|
197
|
+
* can show as "visual no longer available". Order of `images` is not guaranteed; key by `id`. */
|
|
198
|
+
async getVisualImages(visualIds, signal) {
|
|
199
|
+
if (visualIds.length === 0)
|
|
200
|
+
return { images: [], missing: [] };
|
|
201
|
+
const r = await this.request("POST", "/v1/visuals/images", { json: { ids: visualIds }, signal });
|
|
202
|
+
const images = r.images.map((im) => {
|
|
203
|
+
const bytes = Uint8Array.from(atob(im.png_base64), (c) => c.charCodeAt(0));
|
|
204
|
+
return { id: im.id, blob: new Blob([bytes], { type: "image/png" }), width: im.width, height: im.height };
|
|
205
|
+
});
|
|
206
|
+
return { images, missing: r.missing ?? [] };
|
|
207
|
+
}
|
|
181
208
|
/** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
|
|
182
209
|
* to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
|
|
183
210
|
* `query`/`queryStream` ONLY for programmatic one-shots (tools).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babav/knowledge-core-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.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
|
@@ -128,28 +128,31 @@ export type VisualLayout =
|
|
|
128
128
|
| "two-state"
|
|
129
129
|
| "free";
|
|
130
130
|
|
|
131
|
-
/** A visual attached to a response
|
|
132
|
-
* system as citations).
|
|
131
|
+
/** A visual attached to a response.
|
|
133
132
|
*
|
|
134
|
-
*
|
|
135
|
-
* PNG served
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* parses inline SVG. `rendered_svg` appears ONLY as a rare fail-soft fallback (server rasterization
|
|
140
|
-
* failed); prefer `image` and treat `rendered_svg` as a last resort. */
|
|
133
|
+
* IDs-ONLY: the API never returns a URL. Every visual (chart / structural / conceptual / scenic) is
|
|
134
|
+
* a PNG served by KC and identified by its `id`. To display it, fetch the bytes by id —
|
|
135
|
+
* `getVisualImage(visual.id)` for one, or `getVisualImages([...ids])` to fetch a whole answer's
|
|
136
|
+
* visuals in a SINGLE call (no per-visual fan-out). The image is authenticated + tenant-scoped
|
|
137
|
+
* exactly like every other KC call; there is no URL, no signed GCS link. */
|
|
141
138
|
export interface Visual {
|
|
142
139
|
id: string;
|
|
143
|
-
|
|
140
|
+
/** Char offsets into `answer` (SAME coordinate system as citations). OPTIONAL: a visual may be
|
|
141
|
+
* anchorless (belongs in the trailing strip) — when absent, place it after the answer. */
|
|
142
|
+
anchor?: { start: number; end: number };
|
|
144
143
|
register: "chart" | "structural" | "conceptual" | "scenic";
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
/** Client display ordering (higher first). OPTIONAL — default to 0 / arrival order if absent. */
|
|
145
|
+
priority?: number;
|
|
146
|
+
payload: Record<string, unknown>; // {kind: "grammar"|"vega_lite"|"image", ...}
|
|
147
147
|
/** Declared spatial arrangement (meaningful for `conceptual`; "free" otherwise). */
|
|
148
148
|
layout: VisualLayout;
|
|
149
|
-
/**
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
/** Pixel dimensions of the PNG — ALWAYS present on a shipped visual, so the UI can reserve space
|
|
150
|
+
* before the bytes arrive (no layout shift). Fetch the bytes with getVisualImage(id). */
|
|
151
|
+
image: { width: number; height: number };
|
|
152
|
+
/** Short KC-authored figure caption (the idea the visual carries). Present when authored. */
|
|
153
|
+
caption?: string;
|
|
154
|
+
/** Plain-text description for screen readers / accessible PDF·DOCX·LaTeX export. Present when authored. */
|
|
155
|
+
alt?: string;
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
/** Visual stage (streaming): generation has started. MAY be emitted twice — first with
|
|
@@ -160,8 +163,25 @@ export interface VisualsPending {
|
|
|
160
163
|
}
|
|
161
164
|
|
|
162
165
|
export interface VisualsMeta {
|
|
166
|
+
/** Visuals that shipped (authoritative — always matches the number of `visual` events). */
|
|
163
167
|
count: number;
|
|
168
|
+
/** Concepts accepted by the vet but not shipped (render_failed + timeout). */
|
|
164
169
|
dropped: number;
|
|
170
|
+
/** Counts-by-cause for every PROPOSED concept that did not become a visible visual, so a missing
|
|
171
|
+
* visual is explainable rather than silent. Keys (zero causes omitted):
|
|
172
|
+
* - `declined` the vet declined/trimmed the concept (never promised; reduces the pending count)
|
|
173
|
+
* - `render_failed` accepted but authoring/rendering/vision-review dropped it
|
|
174
|
+
* - `timeout` accepted but the post-answer render budget cut it off
|
|
175
|
+
* `dropped` = render_failed + timeout; `declined` is extra context beyond `dropped`. */
|
|
176
|
+
dropped_reasons?: Record<string, number>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** One image returned by getVisualImages(). `blob` is the PNG (browser: `URL.createObjectURL(blob)`). */
|
|
180
|
+
export interface VisualImage {
|
|
181
|
+
id: string;
|
|
182
|
+
blob: Blob;
|
|
183
|
+
width: number;
|
|
184
|
+
height: number;
|
|
165
185
|
}
|
|
166
186
|
|
|
167
187
|
export interface QueryResponse {
|
|
@@ -359,7 +379,7 @@ export interface Message {
|
|
|
359
379
|
groundedness: Record<string, unknown> | null;
|
|
360
380
|
retrieval_contents: unknown[] | null;
|
|
361
381
|
usage: Record<string, unknown> | null;
|
|
362
|
-
visuals?: { items: Visual[]; meta: VisualsMeta } | null; //
|
|
382
|
+
visuals?: { items: Visual[]; meta: VisualsMeta } | null; // persisted visuals; fetch bytes by id (getVisualImages)
|
|
363
383
|
}
|
|
364
384
|
export interface Attachment {
|
|
365
385
|
id: UUID;
|
|
@@ -655,6 +675,39 @@ export class KnowledgeCoreClient extends HttpBase {
|
|
|
655
675
|
if (buf.trim()) dispatchSse(buf, handlers);
|
|
656
676
|
}
|
|
657
677
|
|
|
678
|
+
/** Fetch a visual's PNG bytes BY ID. This is the ONLY way to get a visual image — the API never
|
|
679
|
+
* returns a URL. Authenticated + tenant-scoped like every call. Use `visual.id` from a query
|
|
680
|
+
* response / streamed `visual` event / persisted message. Returns a Blob (browser: `URL.
|
|
681
|
+
* createObjectURL(blob)` for an <img>; Node: `Buffer.from(await blob.arrayBuffer())`). */
|
|
682
|
+
async getVisualImage(visualId: UUID | string, signal?: AbortSignal): Promise<Blob> {
|
|
683
|
+
const res = await this.raw("GET", `/v1/visuals/${visualId}/image`, { signal });
|
|
684
|
+
if (!res.ok) {
|
|
685
|
+
const t = await res.text();
|
|
686
|
+
throw new KnowledgeCoreError(res.status, safeJson(t), `/v1/visuals/${visualId}/image`);
|
|
687
|
+
}
|
|
688
|
+
return await res.blob();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/** Fetch MANY visual PNGs in ONE call — the way to load all of an answer's (or a conversation's)
|
|
692
|
+
* visuals without a per-visual round trip. Pass up to 32 ids; over that, split into chunks (the
|
|
693
|
+
* API returns 400 `too_many_ids`). Returns the found images (as Blobs, ready for
|
|
694
|
+
* `URL.createObjectURL`) plus `missing` — ids with no stored image (reaped/expired), which the UI
|
|
695
|
+
* can show as "visual no longer available". Order of `images` is not guaranteed; key by `id`. */
|
|
696
|
+
async getVisualImages(
|
|
697
|
+
visualIds: Array<UUID | string>,
|
|
698
|
+
signal?: AbortSignal,
|
|
699
|
+
): Promise<{ images: VisualImage[]; missing: string[] }> {
|
|
700
|
+
if (visualIds.length === 0) return { images: [], missing: [] };
|
|
701
|
+
const r = await this.request<{ images: Array<{ id: string; png_base64: string; width: number; height: number }>; missing: string[] }>(
|
|
702
|
+
"POST", "/v1/visuals/images", { json: { ids: visualIds }, signal },
|
|
703
|
+
);
|
|
704
|
+
const images = r.images.map((im) => {
|
|
705
|
+
const bytes = Uint8Array.from(atob(im.png_base64), (c) => c.charCodeAt(0));
|
|
706
|
+
return { id: im.id, blob: new Blob([bytes], { type: "image/png" }), width: im.width, height: im.height };
|
|
707
|
+
});
|
|
708
|
+
return { images, missing: r.missing ?? [] };
|
|
709
|
+
}
|
|
710
|
+
|
|
658
711
|
/** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
|
|
659
712
|
* to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
|
|
660
713
|
* `query`/`queryStream` ONLY for programmatic one-shots (tools).
|