@babav/knowledge-core-client 0.32.0 → 0.34.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 CHANGED
@@ -94,30 +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, anchored by char offsets into `answer` (SAME coordinate
98
- * system as citations).
97
+ /** A visual attached to a response.
99
98
  *
100
99
  * IDs-ONLY: the API never returns a URL. Every visual (chart / structural / conceptual / scenic) is
101
- * a PNG served by KC and identified by its `id`. To display it, fetch the bytes by id:
102
- * `getVisualImage(visual.id)` (or GET /v1/visuals/{id}/image with your API key). `image` carries only
103
- * the pixel DIMENSIONS, for layout. The image is authenticated + tenant-scoped exactly like every
104
- * other KC call; there is no URL, no signed GCS link, and nothing to expire. */
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. */
105
104
  export interface Visual {
106
105
  id: string;
107
- anchor: {
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?: {
108
109
  start: number;
109
110
  end: number;
110
111
  };
111
112
  register: "chart" | "structural" | "conceptual" | "scenic";
112
- priority: number;
113
+ /** Client display ordering (higher first). OPTIONAL — default to 0 / arrival order if absent. */
114
+ priority?: number;
113
115
  payload: Record<string, unknown>;
114
116
  /** Declared spatial arrangement (meaningful for `conceptual`; "free" otherwise). */
115
117
  layout: VisualLayout;
116
- /** Pixel dimensions of the PNG (for layout). Fetch the bytes with getVisualImage(id). */
117
- image?: {
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: {
118
121
  width: number;
119
122
  height: number;
120
123
  };
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;
121
128
  }
122
129
  /** Visual stage (streaming): generation has started. MAY be emitted twice — first with
123
130
  * `pending: null` (started, count unknown), then again with the ACCURATE post-vet count before
@@ -126,8 +133,24 @@ export interface VisualsPending {
126
133
  pending: number | null;
127
134
  }
128
135
  export interface VisualsMeta {
136
+ /** Visuals that shipped (authoritative — always matches the number of `visual` events). */
129
137
  count: number;
138
+ /** Concepts accepted by the vet but not shipped (render_failed + timeout). */
130
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;
131
154
  }
132
155
  export interface QueryResponse {
133
156
  conversation_id: UUID | null;
@@ -394,6 +417,7 @@ export interface Feedback {
394
417
  }
395
418
  export interface Agent {
396
419
  id: UUID;
420
+ tenant_id: UUID | null;
397
421
  name: string;
398
422
  identity_prompt: string | null;
399
423
  response_prompt: string | null;
@@ -412,6 +436,41 @@ export interface Agent {
412
436
  groundedness_threshold: number | null;
413
437
  grounding_enabled: boolean | null;
414
438
  citations_enabled: boolean | null;
439
+ visual_mode_default: string | null;
440
+ visual_concept_model: string | null;
441
+ visual_concept_vet_model: string | null;
442
+ visual_proposer_model: string | null;
443
+ visual_claims_check_model: string | null;
444
+ visual_vision_judge_model: string | null;
445
+ visual_max_revisions: number | null;
446
+ visual_combine_generation_and_concept: boolean | null;
447
+ concept_model_mode: string | null;
448
+ }
449
+ /** Fields settable when creating/updating an agent. All optional (null/omit => server default); model
450
+ * fields must be one of `getModelOptions().fields[field].supported`. `tenant_id` is create-only. */
451
+ export type AgentWrite = Partial<Omit<Agent, "id" | "tenant_id">>;
452
+ /** Model catalog for the agent-config UI (GET /v1/agents/model-options). `models` maps id → its
453
+ * capabilities; `fields` gives each agent model-field its supported ids + default (+ usage metadata);
454
+ * `modes` says which model field governs each mode (reasoning is valid only if that model's
455
+ * supports_reasoning is true). KC provides the data; the UI decides presentation. */
456
+ export interface ModelOptions {
457
+ models: Record<string, {
458
+ label: string;
459
+ provider: "anthropic" | "vertex";
460
+ kind: "text" | "vision";
461
+ supports_reasoning: boolean;
462
+ }>;
463
+ fields: Record<string, {
464
+ supported: string[];
465
+ default: string;
466
+ applies_when?: string;
467
+ applies_to?: string[];
468
+ note?: string;
469
+ }>;
470
+ modes: Record<string, {
471
+ depends_on: string;
472
+ values: string[];
473
+ }>;
415
474
  }
416
475
  export interface Tenant {
417
476
  id: UUID;
@@ -540,6 +599,15 @@ export declare class KnowledgeCoreClient extends HttpBase {
540
599
  * response / streamed `visual` event / persisted message. Returns a Blob (browser: `URL.
541
600
  * createObjectURL(blob)` for an <img>; Node: `Buffer.from(await blob.arrayBuffer())`). */
542
601
  getVisualImage(visualId: UUID | string, signal?: AbortSignal): Promise<Blob>;
602
+ /** Fetch MANY visual PNGs in ONE call — the way to load all of an answer's (or a conversation's)
603
+ * visuals without a per-visual round trip. Pass up to 32 ids; over that, split into chunks (the
604
+ * API returns 400 `too_many_ids`). Returns the found images (as Blobs, ready for
605
+ * `URL.createObjectURL`) plus `missing` — ids with no stored image (reaped/expired), which the UI
606
+ * can show as "visual no longer available". Order of `images` is not guaranteed; key by `id`. */
607
+ getVisualImages(visualIds: Array<UUID | string>, signal?: AbortSignal): Promise<{
608
+ images: VisualImage[];
609
+ missing: string[];
610
+ }>;
543
611
  /** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
544
612
  * to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
545
613
  * `query`/`queryStream` ONLY for programmatic one-shots (tools).
@@ -891,28 +959,15 @@ export declare class AdminClient extends HttpBase {
891
959
  revokeApiKey: (tenantId: UUID, keyId: UUID) => Promise<void>;
892
960
  };
893
961
  agents: {
894
- create: (b: {
962
+ create: (b: AgentWrite & {
895
963
  name: string;
896
- identity_prompt?: string;
897
- response_prompt?: string;
898
- generation_model?: string;
899
- generation_model_mode?: string;
900
- max_response_tokens?: number;
901
- top_k_retrieved_chunks?: number;
902
- top_k_reranked_chunks?: number;
903
- sibling_window?: number;
904
- rerank_instruction?: string;
905
- max_subqueries?: number;
906
- max_reasoning_rounds?: number;
907
- decomposition_model?: string;
908
- reasoning_inspect_model?: string;
909
- groundedness_verifier_model?: string;
910
- groundedness_threshold?: number;
911
- grounding_enabled?: boolean;
912
- citations_enabled?: boolean;
964
+ tenant_id?: UUID | null;
913
965
  }) => Promise<Agent>;
914
- update: (id: UUID, b: Partial<Omit<Agent, "id">>) => Promise<Agent>;
966
+ update: (id: UUID, b: AgentWrite) => Promise<Agent>;
915
967
  delete: (id: UUID) => Promise<void>;
968
+ /** The model catalog for an agent-config UI: supported models + default per field, per-model
969
+ * capabilities (`supports_reasoning`), and mode↔model dependencies. */
970
+ modelOptions: () => Promise<ModelOptions>;
916
971
  };
917
972
  }
918
973
  export interface ChatSendOptions extends StreamHandlers {
package/dist/index.js CHANGED
@@ -190,6 +190,21 @@ export class KnowledgeCoreClient extends HttpBase {
190
190
  }
191
191
  return await res.blob();
192
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
+ }
193
208
  /** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
194
209
  * to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
195
210
  * `query`/`queryStream` ONLY for programmatic one-shots (tools).
@@ -475,11 +490,15 @@ export class AdminClient extends HttpBase {
475
490
  listApiKeys: (tenantId, q) => this.request("GET", `/v1/tenants/${tenantId}/api-keys`, { query: q }),
476
491
  revokeApiKey: (tenantId, keyId) => this.request("DELETE", `/v1/tenants/${tenantId}/api-keys/${keyId}`),
477
492
  };
478
- // Agents are query agents, global for now.
493
+ // Agent provisioning (query agents). Pass `tenant_id` on create for a per-tenant agent; omit (or
494
+ // null) for a Babav-global one. Model fields are validated against the model registry server-side.
479
495
  agents = {
480
496
  create: (b) => this.request("POST", "/v1/agents", { json: b }),
481
497
  update: (id, b) => this.request("PATCH", `/v1/agents/${id}`, { json: b }),
482
498
  delete: (id) => this.request("DELETE", `/v1/agents/${id}`),
499
+ /** The model catalog for an agent-config UI: supported models + default per field, per-model
500
+ * capabilities (`supports_reasoning`), and mode↔model dependencies. */
501
+ modelOptions: () => this.request("GET", "/v1/agents/model-options"),
483
502
  };
484
503
  }
485
504
  /** A chat session bound to ONE conversation (created via `kc.chat(...)`). Every `send()` is ALWAYS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babav/knowledge-core-client",
3
- "version": "0.32.0",
3
+ "version": "0.34.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,24 +128,31 @@ export type VisualLayout =
128
128
  | "two-state"
129
129
  | "free";
130
130
 
131
- /** A visual attached to a response, anchored by char offsets into `answer` (SAME coordinate
132
- * system as citations).
131
+ /** A visual attached to a response.
133
132
  *
134
133
  * IDs-ONLY: the API never returns a URL. Every visual (chart / structural / conceptual / scenic) is
135
- * a PNG served by KC and identified by its `id`. To display it, fetch the bytes by id:
136
- * `getVisualImage(visual.id)` (or GET /v1/visuals/{id}/image with your API key). `image` carries only
137
- * the pixel DIMENSIONS, for layout. The image is authenticated + tenant-scoped exactly like every
138
- * other KC call; there is no URL, no signed GCS link, and nothing to expire. */
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. */
139
138
  export interface Visual {
140
139
  id: string;
141
- anchor: { start: number; end: number };
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 };
142
143
  register: "chart" | "structural" | "conceptual" | "scenic";
143
- priority: number;
144
+ /** Client display ordering (higher first). OPTIONAL — default to 0 / arrival order if absent. */
145
+ priority?: number;
144
146
  payload: Record<string, unknown>; // {kind: "grammar"|"vega_lite"|"image", ...}
145
147
  /** Declared spatial arrangement (meaningful for `conceptual`; "free" otherwise). */
146
148
  layout: VisualLayout;
147
- /** Pixel dimensions of the PNG (for layout). Fetch the bytes with getVisualImage(id). */
148
- image?: { width: number; height: number };
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;
149
156
  }
150
157
 
151
158
  /** Visual stage (streaming): generation has started. MAY be emitted twice — first with
@@ -156,8 +163,25 @@ export interface VisualsPending {
156
163
  }
157
164
 
158
165
  export interface VisualsMeta {
166
+ /** Visuals that shipped (authoritative — always matches the number of `visual` events). */
159
167
  count: number;
168
+ /** Concepts accepted by the vet but not shipped (render_failed + timeout). */
160
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;
161
185
  }
162
186
 
163
187
  export interface QueryResponse {
@@ -355,7 +379,7 @@ export interface Message {
355
379
  groundedness: Record<string, unknown> | null;
356
380
  retrieval_contents: unknown[] | null;
357
381
  usage: Record<string, unknown> | null;
358
- visuals?: { items: Visual[]; meta: VisualsMeta } | null; // post-generation visuals (re-signed URLs on read)
382
+ visuals?: { items: Visual[]; meta: VisualsMeta } | null; // persisted visuals; fetch bytes by id (getVisualImages)
359
383
  }
360
384
  export interface Attachment {
361
385
  id: UUID;
@@ -375,6 +399,7 @@ export interface Feedback {
375
399
  }
376
400
  export interface Agent {
377
401
  id: UUID;
402
+ tenant_id: UUID | null; // null => Babav-global agent; a tenant id => per-tenant
378
403
  name: string;
379
404
  identity_prompt: string | null; // answer-system: who/purpose (null => server default)
380
405
  response_prompt: string | null; // answer-system: output guidelines (null => server default)
@@ -393,6 +418,30 @@ export interface Agent {
393
418
  groundedness_threshold: number | null;
394
419
  grounding_enabled: boolean | null;
395
420
  citations_enabled: boolean | null;
421
+ // Visual pipeline defaults (null => server default; overridable per request).
422
+ visual_mode_default: string | null; // "off" | "on"
423
+ visual_concept_model: string | null;
424
+ visual_concept_vet_model: string | null;
425
+ visual_proposer_model: string | null; // authors the HTML figure + chart/structural/scene specs
426
+ visual_claims_check_model: string | null;
427
+ visual_vision_judge_model: string | null; // Vertex Gemini model
428
+ visual_max_revisions: number | null;
429
+ visual_combine_generation_and_concept: boolean | null;
430
+ concept_model_mode: string | null; // "reasoning" | "standard"; overrules gen mode when combining
431
+ }
432
+
433
+ /** Fields settable when creating/updating an agent. All optional (null/omit => server default); model
434
+ * fields must be one of `getModelOptions().fields[field].supported`. `tenant_id` is create-only. */
435
+ export type AgentWrite = Partial<Omit<Agent, "id" | "tenant_id">>;
436
+
437
+ /** Model catalog for the agent-config UI (GET /v1/agents/model-options). `models` maps id → its
438
+ * capabilities; `fields` gives each agent model-field its supported ids + default (+ usage metadata);
439
+ * `modes` says which model field governs each mode (reasoning is valid only if that model's
440
+ * supports_reasoning is true). KC provides the data; the UI decides presentation. */
441
+ export interface ModelOptions {
442
+ models: Record<string, { label: string; provider: "anthropic" | "vertex"; kind: "text" | "vision"; supports_reasoning: boolean }>;
443
+ fields: Record<string, { supported: string[]; default: string; applies_when?: string; applies_to?: string[]; note?: string }>;
444
+ modes: Record<string, { depends_on: string; values: string[] }>;
396
445
  }
397
446
  export interface Tenant {
398
447
  id: UUID;
@@ -664,6 +713,26 @@ export class KnowledgeCoreClient extends HttpBase {
664
713
  return await res.blob();
665
714
  }
666
715
 
716
+ /** Fetch MANY visual PNGs in ONE call — the way to load all of an answer's (or a conversation's)
717
+ * visuals without a per-visual round trip. Pass up to 32 ids; over that, split into chunks (the
718
+ * API returns 400 `too_many_ids`). Returns the found images (as Blobs, ready for
719
+ * `URL.createObjectURL`) plus `missing` — ids with no stored image (reaped/expired), which the UI
720
+ * can show as "visual no longer available". Order of `images` is not guaranteed; key by `id`. */
721
+ async getVisualImages(
722
+ visualIds: Array<UUID | string>,
723
+ signal?: AbortSignal,
724
+ ): Promise<{ images: VisualImage[]; missing: string[] }> {
725
+ if (visualIds.length === 0) return { images: [], missing: [] };
726
+ const r = await this.request<{ images: Array<{ id: string; png_base64: string; width: number; height: number }>; missing: string[] }>(
727
+ "POST", "/v1/visuals/images", { json: { ids: visualIds }, signal },
728
+ );
729
+ const images = r.images.map((im) => {
730
+ const bytes = Uint8Array.from(atob(im.png_base64), (c) => c.charCodeAt(0));
731
+ return { id: im.id, blob: new Blob([bytes], { type: "image/png" }), width: im.width, height: im.height };
732
+ });
733
+ return { images, missing: r.missing ?? [] };
734
+ }
735
+
667
736
  /** DUMMY-PROOF CHAT. Every message goes through a conversation — it is structurally impossible
668
737
  * to send a chat turn as a non-persisted one-shot. Use this for ANY chat UI. Use the low-level
669
738
  * `query`/`queryStream` ONLY for programmatic one-shots (tools).
@@ -1021,13 +1090,17 @@ export class AdminClient extends HttpBase {
1021
1090
  revokeApiKey: (tenantId: UUID, keyId: UUID) => this.request<void>("DELETE", `/v1/tenants/${tenantId}/api-keys/${keyId}`),
1022
1091
  };
1023
1092
 
1024
- // Agents are query agents, global for now.
1093
+ // Agent provisioning (query agents). Pass `tenant_id` on create for a per-tenant agent; omit (or
1094
+ // null) for a Babav-global one. Model fields are validated against the model registry server-side.
1025
1095
  agents = {
1026
- create: (b: { name: string; identity_prompt?: string; response_prompt?: string; generation_model?: string; generation_model_mode?: string; max_response_tokens?: number; top_k_retrieved_chunks?: number; top_k_reranked_chunks?: number; sibling_window?: number; rerank_instruction?: string; max_subqueries?: number; max_reasoning_rounds?: number; decomposition_model?: string; reasoning_inspect_model?: string; groundedness_verifier_model?: string; groundedness_threshold?: number; grounding_enabled?: boolean; citations_enabled?: boolean }) =>
1096
+ create: (b: AgentWrite & { name: string; tenant_id?: UUID | null }) =>
1027
1097
  this.request<Agent>("POST", "/v1/agents", { json: b }),
1028
- update: (id: UUID, b: Partial<Omit<Agent, "id">>) =>
1098
+ update: (id: UUID, b: AgentWrite) =>
1029
1099
  this.request<Agent>("PATCH", `/v1/agents/${id}`, { json: b }),
1030
1100
  delete: (id: UUID) => this.request<void>("DELETE", `/v1/agents/${id}`),
1101
+ /** The model catalog for an agent-config UI: supported models + default per field, per-model
1102
+ * capabilities (`supports_reasoning`), and mode↔model dependencies. */
1103
+ modelOptions: () => this.request<ModelOptions>("GET", "/v1/agents/model-options"),
1031
1104
  };
1032
1105
  }
1033
1106