@retrivora-ai/rag-engine 1.7.3 → 1.7.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/{chunk-M32ZXLTT.mjs → chunk-QOO37S2Z.mjs} +177 -53
- package/dist/handlers/index.js +172 -48
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.js +17 -3
- package/dist/index.mjs +17 -3
- package/dist/server.js +179 -51
- package/dist/server.mjs +8 -4
- package/package.json +1 -1
- package/src/components/MessageBubble.tsx +58 -5
- package/src/core/Pipeline.ts +179 -53
- package/src/llm/providers/GeminiProvider.ts +7 -2
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +13 -3
|
@@ -829,7 +829,8 @@ ${context}`;
|
|
|
829
829
|
stopSequences: options == null ? void 0 : options.stop
|
|
830
830
|
}
|
|
831
831
|
});
|
|
832
|
-
|
|
832
|
+
const text = typeof response.text === "function" ? response.text() : (_f = response.text) != null ? _f : "";
|
|
833
|
+
return text;
|
|
833
834
|
}
|
|
834
835
|
chatStream(messages, context, options) {
|
|
835
836
|
return __asyncGenerator(this, null, function* () {
|
|
@@ -863,7 +864,7 @@ ${context}`;
|
|
|
863
864
|
try {
|
|
864
865
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
865
866
|
const chunk = temp.value;
|
|
866
|
-
const text = chunk.text;
|
|
867
|
+
const text = typeof chunk.text === "function" ? chunk.text() : chunk.text;
|
|
867
868
|
if (text) yield text;
|
|
868
869
|
}
|
|
869
870
|
} catch (temp) {
|
|
@@ -2259,73 +2260,196 @@ var Pipeline = class {
|
|
|
2259
2260
|
async initialize() {
|
|
2260
2261
|
var _a, _b;
|
|
2261
2262
|
if (this.initialised) return;
|
|
2262
|
-
const CHART_MARKER = "<!--
|
|
2263
|
+
const CHART_MARKER = "<!-- UI_PROTOCOL_V7 -->";
|
|
2263
2264
|
const chartInstruction = `
|
|
2264
2265
|
|
|
2265
2266
|
${CHART_MARKER}
|
|
2266
|
-
### UNIVERSAL UI PROTOCOL
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2267
|
+
### UNIVERSAL UI PROTOCOL V7 (STRICT MODE)
|
|
2268
|
+
|
|
2269
|
+
You are responsible for returning a SINGLE structured UI block when visualization is required.
|
|
2270
|
+
|
|
2271
|
+
---
|
|
2272
|
+
|
|
2273
|
+
## 1. INTENT CLASSIFICATION (MANDATORY)
|
|
2274
|
+
|
|
2275
|
+
Classify the query into ONE of the following intents:
|
|
2276
|
+
|
|
2277
|
+
- "explore" \u2192 user wants to browse items (e.g., "show me products")
|
|
2278
|
+
- "analyze" \u2192 user wants aggregation/distribution (e.g., "distribution of products")
|
|
2279
|
+
- "compare" \u2192 user wants side-by-side comparison
|
|
2280
|
+
- "detail" \u2192 user wants structured/tabular data
|
|
2281
|
+
|
|
2282
|
+
---
|
|
2283
|
+
|
|
2284
|
+
## 2. VIEW MAPPING (STRICT)
|
|
2285
|
+
|
|
2286
|
+
| Intent | View |
|
|
2287
|
+
|----------|-----------|
|
|
2288
|
+
| explore | carousel |
|
|
2289
|
+
| analyze | chart |
|
|
2290
|
+
| compare | table |
|
|
2291
|
+
| detail | table |
|
|
2292
|
+
|
|
2293
|
+
\u26A0\uFE0F Override Rules:
|
|
2294
|
+
- If query contains "distribution", "percentage", "ratio" \u2192 ALWAYS chart
|
|
2295
|
+
- If query contains "show products", "list items" \u2192 ALWAYS carousel
|
|
2296
|
+
- NEVER mix views
|
|
2297
|
+
|
|
2298
|
+
---
|
|
2299
|
+
|
|
2300
|
+
## 3. RESPONSE FORMAT (STRICT JSON ONLY INSIDE BLOCK)
|
|
2301
|
+
|
|
2302
|
+
\`\`\`ui
|
|
2303
|
+
{
|
|
2304
|
+
"view": "carousel" | "chart" | "table",
|
|
2305
|
+
"title": "string",
|
|
2306
|
+
"description": "string",
|
|
2307
|
+
"metadata": {
|
|
2308
|
+
"intent": "explore" | "analyze" | "compare" | "detail",
|
|
2309
|
+
"confidence": 0.0-1.0
|
|
2310
|
+
},
|
|
2311
|
+
|
|
2312
|
+
// CHART ONLY
|
|
2313
|
+
"chart": {
|
|
2314
|
+
"type": "pie" | "bar" | "line",
|
|
2315
|
+
"xKey": "label",
|
|
2316
|
+
"yKeys": ["value"],
|
|
2317
|
+
"data": []
|
|
2318
|
+
},
|
|
2319
|
+
|
|
2320
|
+
// TABLE ONLY
|
|
2321
|
+
"table": {
|
|
2322
|
+
"columns": [],
|
|
2323
|
+
"rows": []
|
|
2324
|
+
},
|
|
2325
|
+
|
|
2326
|
+
// CAROUSEL ONLY
|
|
2327
|
+
"carousel": {
|
|
2328
|
+
"items": []
|
|
2329
|
+
},
|
|
2330
|
+
|
|
2331
|
+
"insights": []
|
|
2332
|
+
}
|
|
2333
|
+
\`\`\`
|
|
2334
|
+
|
|
2335
|
+
---
|
|
2336
|
+
|
|
2337
|
+
## 4. DATA CONTRACT (CRITICAL)
|
|
2338
|
+
|
|
2339
|
+
### \u{1F539} CAROUSEL ITEM FORMAT
|
|
2340
|
+
{
|
|
2341
|
+
"id": "string",
|
|
2342
|
+
"name": "string",
|
|
2343
|
+
"brand": "string",
|
|
2344
|
+
"price": number,
|
|
2345
|
+
"image": "url",
|
|
2346
|
+
"link": "url",
|
|
2347
|
+
"inStock": boolean
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
### \u{1F539} CHART DATA FORMAT
|
|
2351
|
+
{
|
|
2352
|
+
"label": "string",
|
|
2353
|
+
"value": number,
|
|
2354
|
+
"inStock": boolean (optional)
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
### \u{1F539} TABLE FORMAT
|
|
2358
|
+
- columns MUST match row keys
|
|
2359
|
+
- rows MUST be flat objects
|
|
2360
|
+
|
|
2361
|
+
---
|
|
2362
|
+
|
|
2363
|
+
## 5. DATA RULES
|
|
2364
|
+
|
|
2365
|
+
- NEVER hallucinate fields
|
|
2366
|
+
- ONLY use retrieved vector DB data
|
|
2367
|
+
- NO placeholders ("...", "N/A")
|
|
2368
|
+
- If image/link missing \u2192 REMOVE FIELD
|
|
2369
|
+
- Aggregate BEFORE rendering chart
|
|
2370
|
+
|
|
2371
|
+
---
|
|
2372
|
+
|
|
2373
|
+
## 6. SMART RULES (IMPORTANT)
|
|
2374
|
+
|
|
2375
|
+
- If user asks BOTH:
|
|
2376
|
+
"show products AND distribution"
|
|
2377
|
+
\u2192 PRIORITIZE "explore" \u2192 carousel
|
|
2378
|
+
|
|
2379
|
+
- If dataset size > 20:
|
|
2380
|
+
\u2192 aggregate \u2192 chart or table
|
|
2381
|
+
|
|
2382
|
+
---
|
|
2383
|
+
|
|
2384
|
+
## 7. OUTPUT RULES
|
|
2385
|
+
|
|
2386
|
+
- ALWAYS return EXACTLY ONE \`\`\`ui\`\`\` block
|
|
2387
|
+
- JSON must be VALID
|
|
2388
|
+
- No explanation inside block
|
|
2389
|
+
|
|
2390
|
+
---
|
|
2391
|
+
|
|
2392
|
+
## 8. EXAMPLES
|
|
2393
|
+
|
|
2298
2394
|
User: "show me beauty products"
|
|
2299
|
-
|
|
2395
|
+
|
|
2300
2396
|
\`\`\`ui
|
|
2301
2397
|
{
|
|
2302
2398
|
"view": "carousel",
|
|
2303
2399
|
"title": "Beauty Products",
|
|
2304
|
-
"description": "Browse
|
|
2305
|
-
"
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2400
|
+
"description": "Browse available beauty items",
|
|
2401
|
+
"metadata": {
|
|
2402
|
+
"intent": "explore",
|
|
2403
|
+
"confidence": 0.95
|
|
2404
|
+
},
|
|
2405
|
+
"carousel": {
|
|
2406
|
+
"items": [
|
|
2407
|
+
{
|
|
2408
|
+
"id": "1",
|
|
2409
|
+
"name": "Mascara",
|
|
2410
|
+
"brand": "Essence",
|
|
2411
|
+
"price": 9.99,
|
|
2412
|
+
"image": "https://example.com/mascara.jpg",
|
|
2413
|
+
"link": "https://example.com/p1",
|
|
2414
|
+
"inStock": true
|
|
2415
|
+
}
|
|
2416
|
+
]
|
|
2417
|
+
},
|
|
2418
|
+
"insights": ["Most products are affordable"]
|
|
2309
2419
|
}
|
|
2310
2420
|
\`\`\`
|
|
2311
2421
|
|
|
2312
|
-
|
|
2313
|
-
|
|
2422
|
+
---
|
|
2423
|
+
|
|
2424
|
+
User: "distribution of products across categories"
|
|
2425
|
+
|
|
2314
2426
|
\`\`\`ui
|
|
2315
2427
|
{
|
|
2316
2428
|
"view": "chart",
|
|
2317
|
-
"title": "
|
|
2318
|
-
"
|
|
2319
|
-
"
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2429
|
+
"title": "Product Distribution",
|
|
2430
|
+
"description": "Category-wise product distribution",
|
|
2431
|
+
"metadata": {
|
|
2432
|
+
"intent": "analyze",
|
|
2433
|
+
"confidence": 0.98
|
|
2434
|
+
},
|
|
2435
|
+
"chart": {
|
|
2436
|
+
"type": "pie",
|
|
2437
|
+
"xKey": "label",
|
|
2438
|
+
"yKeys": ["value"],
|
|
2439
|
+
"data": [
|
|
2440
|
+
{ "label": "Beauty", "value": 15 },
|
|
2441
|
+
{ "label": "Electronics", "value": 10 }
|
|
2442
|
+
]
|
|
2443
|
+
},
|
|
2444
|
+
"insights": ["Beauty dominates inventory"]
|
|
2325
2445
|
}
|
|
2326
|
-
|
|
2446
|
+
\`\`\`
|
|
2447
|
+
`;
|
|
2327
2448
|
if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
|
|
2328
|
-
|
|
2449
|
+
let cleanPrompt = this.config.llm.systemPrompt || "";
|
|
2450
|
+
cleanPrompt = cleanPrompt.replace(/\n\n### UNIVERSAL UI PROTOCOL[\s\S]*?(?=\n\n|$)/g, "");
|
|
2451
|
+
cleanPrompt = cleanPrompt.replace(/<!-- UI_PROTOCOL_V\d+ -->[\s\S]*?(?=\n\n|$)/g, "");
|
|
2452
|
+
this.config.llm.systemPrompt = cleanPrompt.trim() + chartInstruction;
|
|
2329
2453
|
}
|
|
2330
2454
|
console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
|
|
2331
2455
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
package/dist/handlers/index.js
CHANGED
|
@@ -2437,7 +2437,8 @@ ${context}`;
|
|
|
2437
2437
|
stopSequences: options == null ? void 0 : options.stop
|
|
2438
2438
|
}
|
|
2439
2439
|
});
|
|
2440
|
-
|
|
2440
|
+
const text = typeof response.text === "function" ? response.text() : (_f = response.text) != null ? _f : "";
|
|
2441
|
+
return text;
|
|
2441
2442
|
}
|
|
2442
2443
|
chatStream(messages, context, options) {
|
|
2443
2444
|
return __asyncGenerator(this, null, function* () {
|
|
@@ -2471,7 +2472,7 @@ ${context}`;
|
|
|
2471
2472
|
try {
|
|
2472
2473
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2473
2474
|
const chunk = temp.value;
|
|
2474
|
-
const text = chunk.text;
|
|
2475
|
+
const text = typeof chunk.text === "function" ? chunk.text() : chunk.text;
|
|
2475
2476
|
if (text) yield text;
|
|
2476
2477
|
}
|
|
2477
2478
|
} catch (temp) {
|
|
@@ -3823,73 +3824,196 @@ var Pipeline = class {
|
|
|
3823
3824
|
async initialize() {
|
|
3824
3825
|
var _a, _b;
|
|
3825
3826
|
if (this.initialised) return;
|
|
3826
|
-
const CHART_MARKER = "<!--
|
|
3827
|
+
const CHART_MARKER = "<!-- UI_PROTOCOL_V7 -->";
|
|
3827
3828
|
const chartInstruction = `
|
|
3828
3829
|
|
|
3829
3830
|
${CHART_MARKER}
|
|
3830
|
-
### UNIVERSAL UI PROTOCOL
|
|
3831
|
-
When the user asks for a visual representation, comparison, distribution, breakdown, table, list, catalog, products, carousel, stock view, or category summary, you MUST include exactly one \`\`\`ui\`\`\` block.
|
|
3831
|
+
### UNIVERSAL UI PROTOCOL V7 (STRICT MODE)
|
|
3832
3832
|
|
|
3833
|
-
|
|
3834
|
-
- Use "carousel" for browsing specific products, items, or a catalog. This is the DEFAULT for "show me", "what are", or "find me" requests for a specific category (e.g. "beauty").
|
|
3835
|
-
- Use "chart" ONLY for numerical aggregations: distributions, percentages, counts, comparisons over time, or trends (e.g. "how many beauty products?").
|
|
3836
|
-
- Use "table" for detailed technical specifications, row-heavy comparisons, or when the user explicitly asks for a list/table format.
|
|
3833
|
+
You are responsible for returning a SINGLE structured UI block when visualization is required.
|
|
3837
3834
|
|
|
3838
|
-
|
|
3839
|
-
{
|
|
3840
|
-
"view": "chart" | "carousel" | "table",
|
|
3841
|
-
"title": "Short heading",
|
|
3842
|
-
"description": "One sentence describing the view",
|
|
3843
|
-
"chartType": "pie" | "bar" | "line", // Required if view is "chart"
|
|
3844
|
-
"xAxisKey": "label",
|
|
3845
|
-
"dataKeys": ["value"],
|
|
3846
|
-
"columns": ["dynamicFieldKey1", "dynamicFieldKey2"],
|
|
3847
|
-
"insights": ["Short takeaway 1", "Short takeaway 2"],
|
|
3848
|
-
"data": []
|
|
3849
|
-
}
|
|
3835
|
+
---
|
|
3850
3836
|
|
|
3851
|
-
|
|
3852
|
-
- Build the UI payload from retrieved context only. Do not invent products or values.
|
|
3853
|
-
- For CAROUSEL: "data" must be a list of product objects (id, name, brand, price, image, link).
|
|
3854
|
-
- For CHART: "data" must be aggregated counts or sums. Never put raw product lists in a chart view.
|
|
3855
|
-
- If the user asks for "products in beauty", do NOT return a pie chart of categories; return a carousel of the beauty products themselves.
|
|
3837
|
+
## 1. INTENT CLASSIFICATION (MANDATORY)
|
|
3856
3838
|
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3839
|
+
Classify the query into ONE of the following intents:
|
|
3840
|
+
|
|
3841
|
+
- "explore" \u2192 user wants to browse items (e.g., "show me products")
|
|
3842
|
+
- "analyze" \u2192 user wants aggregation/distribution (e.g., "distribution of products")
|
|
3843
|
+
- "compare" \u2192 user wants side-by-side comparison
|
|
3844
|
+
- "detail" \u2192 user wants structured/tabular data
|
|
3845
|
+
|
|
3846
|
+
---
|
|
3847
|
+
|
|
3848
|
+
## 2. VIEW MAPPING (STRICT)
|
|
3849
|
+
|
|
3850
|
+
| Intent | View |
|
|
3851
|
+
|----------|-----------|
|
|
3852
|
+
| explore | carousel |
|
|
3853
|
+
| analyze | chart |
|
|
3854
|
+
| compare | table |
|
|
3855
|
+
| detail | table |
|
|
3856
|
+
|
|
3857
|
+
\u26A0\uFE0F Override Rules:
|
|
3858
|
+
- If query contains "distribution", "percentage", "ratio" \u2192 ALWAYS chart
|
|
3859
|
+
- If query contains "show products", "list items" \u2192 ALWAYS carousel
|
|
3860
|
+
- NEVER mix views
|
|
3861
|
+
|
|
3862
|
+
---
|
|
3863
|
+
|
|
3864
|
+
## 3. RESPONSE FORMAT (STRICT JSON ONLY INSIDE BLOCK)
|
|
3865
|
+
|
|
3866
|
+
\`\`\`ui
|
|
3867
|
+
{
|
|
3868
|
+
"view": "carousel" | "chart" | "table",
|
|
3869
|
+
"title": "string",
|
|
3870
|
+
"description": "string",
|
|
3871
|
+
"metadata": {
|
|
3872
|
+
"intent": "explore" | "analyze" | "compare" | "detail",
|
|
3873
|
+
"confidence": 0.0-1.0
|
|
3874
|
+
},
|
|
3875
|
+
|
|
3876
|
+
// CHART ONLY
|
|
3877
|
+
"chart": {
|
|
3878
|
+
"type": "pie" | "bar" | "line",
|
|
3879
|
+
"xKey": "label",
|
|
3880
|
+
"yKeys": ["value"],
|
|
3881
|
+
"data": []
|
|
3882
|
+
},
|
|
3883
|
+
|
|
3884
|
+
// TABLE ONLY
|
|
3885
|
+
"table": {
|
|
3886
|
+
"columns": [],
|
|
3887
|
+
"rows": []
|
|
3888
|
+
},
|
|
3889
|
+
|
|
3890
|
+
// CAROUSEL ONLY
|
|
3891
|
+
"carousel": {
|
|
3892
|
+
"items": []
|
|
3893
|
+
},
|
|
3894
|
+
|
|
3895
|
+
"insights": []
|
|
3896
|
+
}
|
|
3897
|
+
\`\`\`
|
|
3898
|
+
|
|
3899
|
+
---
|
|
3900
|
+
|
|
3901
|
+
## 4. DATA CONTRACT (CRITICAL)
|
|
3902
|
+
|
|
3903
|
+
### \u{1F539} CAROUSEL ITEM FORMAT
|
|
3904
|
+
{
|
|
3905
|
+
"id": "string",
|
|
3906
|
+
"name": "string",
|
|
3907
|
+
"brand": "string",
|
|
3908
|
+
"price": number,
|
|
3909
|
+
"image": "url",
|
|
3910
|
+
"link": "url",
|
|
3911
|
+
"inStock": boolean
|
|
3912
|
+
}
|
|
3913
|
+
|
|
3914
|
+
### \u{1F539} CHART DATA FORMAT
|
|
3915
|
+
{
|
|
3916
|
+
"label": "string",
|
|
3917
|
+
"value": number,
|
|
3918
|
+
"inStock": boolean (optional)
|
|
3919
|
+
}
|
|
3920
|
+
|
|
3921
|
+
### \u{1F539} TABLE FORMAT
|
|
3922
|
+
- columns MUST match row keys
|
|
3923
|
+
- rows MUST be flat objects
|
|
3924
|
+
|
|
3925
|
+
---
|
|
3926
|
+
|
|
3927
|
+
## 5. DATA RULES
|
|
3928
|
+
|
|
3929
|
+
- NEVER hallucinate fields
|
|
3930
|
+
- ONLY use retrieved vector DB data
|
|
3931
|
+
- NO placeholders ("...", "N/A")
|
|
3932
|
+
- If image/link missing \u2192 REMOVE FIELD
|
|
3933
|
+
- Aggregate BEFORE rendering chart
|
|
3934
|
+
|
|
3935
|
+
---
|
|
3936
|
+
|
|
3937
|
+
## 6. SMART RULES (IMPORTANT)
|
|
3938
|
+
|
|
3939
|
+
- If user asks BOTH:
|
|
3940
|
+
"show products AND distribution"
|
|
3941
|
+
\u2192 PRIORITIZE "explore" \u2192 carousel
|
|
3942
|
+
|
|
3943
|
+
- If dataset size > 20:
|
|
3944
|
+
\u2192 aggregate \u2192 chart or table
|
|
3945
|
+
|
|
3946
|
+
---
|
|
3947
|
+
|
|
3948
|
+
## 7. OUTPUT RULES
|
|
3949
|
+
|
|
3950
|
+
- ALWAYS return EXACTLY ONE \`\`\`ui\`\`\` block
|
|
3951
|
+
- JSON must be VALID
|
|
3952
|
+
- No explanation inside block
|
|
3953
|
+
|
|
3954
|
+
---
|
|
3955
|
+
|
|
3956
|
+
## 8. EXAMPLES
|
|
3860
3957
|
|
|
3861
|
-
5. EXAMPLES
|
|
3862
3958
|
User: "show me beauty products"
|
|
3863
|
-
|
|
3959
|
+
|
|
3864
3960
|
\`\`\`ui
|
|
3865
3961
|
{
|
|
3866
3962
|
"view": "carousel",
|
|
3867
3963
|
"title": "Beauty Products",
|
|
3868
|
-
"description": "Browse
|
|
3869
|
-
"
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3964
|
+
"description": "Browse available beauty items",
|
|
3965
|
+
"metadata": {
|
|
3966
|
+
"intent": "explore",
|
|
3967
|
+
"confidence": 0.95
|
|
3968
|
+
},
|
|
3969
|
+
"carousel": {
|
|
3970
|
+
"items": [
|
|
3971
|
+
{
|
|
3972
|
+
"id": "1",
|
|
3973
|
+
"name": "Mascara",
|
|
3974
|
+
"brand": "Essence",
|
|
3975
|
+
"price": 9.99,
|
|
3976
|
+
"image": "https://example.com/mascara.jpg",
|
|
3977
|
+
"link": "https://example.com/p1",
|
|
3978
|
+
"inStock": true
|
|
3979
|
+
}
|
|
3980
|
+
]
|
|
3981
|
+
},
|
|
3982
|
+
"insights": ["Most products are affordable"]
|
|
3873
3983
|
}
|
|
3874
3984
|
\`\`\`
|
|
3875
3985
|
|
|
3876
|
-
|
|
3877
|
-
|
|
3986
|
+
---
|
|
3987
|
+
|
|
3988
|
+
User: "distribution of products across categories"
|
|
3989
|
+
|
|
3878
3990
|
\`\`\`ui
|
|
3879
3991
|
{
|
|
3880
3992
|
"view": "chart",
|
|
3881
|
-
"title": "
|
|
3882
|
-
"
|
|
3883
|
-
"
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3993
|
+
"title": "Product Distribution",
|
|
3994
|
+
"description": "Category-wise product distribution",
|
|
3995
|
+
"metadata": {
|
|
3996
|
+
"intent": "analyze",
|
|
3997
|
+
"confidence": 0.98
|
|
3998
|
+
},
|
|
3999
|
+
"chart": {
|
|
4000
|
+
"type": "pie",
|
|
4001
|
+
"xKey": "label",
|
|
4002
|
+
"yKeys": ["value"],
|
|
4003
|
+
"data": [
|
|
4004
|
+
{ "label": "Beauty", "value": 15 },
|
|
4005
|
+
{ "label": "Electronics", "value": 10 }
|
|
4006
|
+
]
|
|
4007
|
+
},
|
|
4008
|
+
"insights": ["Beauty dominates inventory"]
|
|
3889
4009
|
}
|
|
3890
|
-
|
|
4010
|
+
\`\`\`
|
|
4011
|
+
`;
|
|
3891
4012
|
if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
|
|
3892
|
-
|
|
4013
|
+
let cleanPrompt = this.config.llm.systemPrompt || "";
|
|
4014
|
+
cleanPrompt = cleanPrompt.replace(/\n\n### UNIVERSAL UI PROTOCOL[\s\S]*?(?=\n\n|$)/g, "");
|
|
4015
|
+
cleanPrompt = cleanPrompt.replace(/<!-- UI_PROTOCOL_V\d+ -->[\s\S]*?(?=\n\n|$)/g, "");
|
|
4016
|
+
this.config.llm.systemPrompt = cleanPrompt.trim() + chartInstruction;
|
|
3893
4017
|
}
|
|
3894
4018
|
console.log(`[Pipeline] Initializing with provider: ${this.config.vectorDb.provider}...`);
|
|
3895
4019
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
package/dist/handlers/index.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -405,7 +405,7 @@ function sanitizeJson(raw) {
|
|
|
405
405
|
return `: ${result}`;
|
|
406
406
|
}
|
|
407
407
|
);
|
|
408
|
-
s = s.replace(
|
|
408
|
+
s = s.replace(/("(?:\\.|[^\\"])*")|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, (m, g1) => g1 || "");
|
|
409
409
|
s = s.replace(/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)\s*:/g, '$1"$2":');
|
|
410
410
|
s = s.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
|
|
411
411
|
s = s.replace(/,\s*([}\]])/g, "$1");
|
|
@@ -535,11 +535,12 @@ function isLikelyUiOnlyMessage(text) {
|
|
|
535
535
|
return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary)\s*:?\s*$/i.test(trimmed);
|
|
536
536
|
}
|
|
537
537
|
function resolveImage(data) {
|
|
538
|
+
const isPlaceholder = (val) => typeof val === "string" && (val === "..." || val === "" || val.toLowerCase() === "null" || val.toLowerCase() === "undefined");
|
|
538
539
|
for (const key of ["image", "img", "thumbnail"]) {
|
|
539
540
|
const v = data[key];
|
|
540
|
-
if (typeof v === "string" && v) return v;
|
|
541
|
+
if (typeof v === "string" && v && !isPlaceholder(v)) return v;
|
|
541
542
|
}
|
|
542
|
-
if (Array.isArray(data.images) && typeof data.images[0] === "string") {
|
|
543
|
+
if (Array.isArray(data.images) && typeof data.images[0] === "string" && !isPlaceholder(data.images[0])) {
|
|
543
544
|
return data.images[0];
|
|
544
545
|
}
|
|
545
546
|
return void 0;
|
|
@@ -636,6 +637,11 @@ function normalizeTabularRows(rows, columns) {
|
|
|
636
637
|
}).filter((row) => Object.keys(row).length > 0);
|
|
637
638
|
}
|
|
638
639
|
function resolveStructuredRows(config) {
|
|
640
|
+
var _a, _b, _c, _d;
|
|
641
|
+
if (((_a = config.carousel) == null ? void 0 : _a.items) && Array.isArray(config.carousel.items)) return config.carousel.items;
|
|
642
|
+
if (((_b = config.chart) == null ? void 0 : _b.data) && Array.isArray(config.chart.data)) return config.chart.data;
|
|
643
|
+
if (((_c = config.table) == null ? void 0 : _c.rows) && Array.isArray(config.table.rows)) return config.table.rows;
|
|
644
|
+
if (((_d = config.table) == null ? void 0 : _d.data) && Array.isArray(config.table.data)) return config.table.data;
|
|
639
645
|
if (Array.isArray(config.data) && config.data.length > 0) return config.data;
|
|
640
646
|
if (Array.isArray(config.items) && config.items.length > 0) return config.items;
|
|
641
647
|
if (Array.isArray(config.products) && config.products.length > 0) return config.products;
|
|
@@ -651,6 +657,14 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
651
657
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
652
658
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
653
659
|
const config2 = __spreadValues({}, parsed);
|
|
660
|
+
if (config2.chart) {
|
|
661
|
+
if (!config2.chartType) config2.chartType = config2.chart.type;
|
|
662
|
+
if (!config2.xAxisKey) config2.xAxisKey = config2.chart.xKey;
|
|
663
|
+
if (!config2.dataKeys) config2.dataKeys = config2.chart.yKeys;
|
|
664
|
+
}
|
|
665
|
+
if (config2.table) {
|
|
666
|
+
if (!config2.columns) config2.columns = config2.table.columns;
|
|
667
|
+
}
|
|
654
668
|
const resolvedRows = resolveStructuredRows(config2);
|
|
655
669
|
const hasProductLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["price", "brand", "image", "link", "thumbnail"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length >= 4);
|
|
656
670
|
const hasAggregationLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["value", "count", "total", "percentage"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length <= 3 && Object.values(resolvedRows[0]).some((v) => typeof v === "number"));
|
package/dist/index.mjs
CHANGED
|
@@ -368,7 +368,7 @@ function sanitizeJson(raw) {
|
|
|
368
368
|
return `: ${result}`;
|
|
369
369
|
}
|
|
370
370
|
);
|
|
371
|
-
s = s.replace(
|
|
371
|
+
s = s.replace(/("(?:\\.|[^\\"])*")|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, (m, g1) => g1 || "");
|
|
372
372
|
s = s.replace(/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)\s*:/g, '$1"$2":');
|
|
373
373
|
s = s.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
|
|
374
374
|
s = s.replace(/,\s*([}\]])/g, "$1");
|
|
@@ -498,11 +498,12 @@ function isLikelyUiOnlyMessage(text) {
|
|
|
498
498
|
return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary)\s*:?\s*$/i.test(trimmed);
|
|
499
499
|
}
|
|
500
500
|
function resolveImage(data) {
|
|
501
|
+
const isPlaceholder = (val) => typeof val === "string" && (val === "..." || val === "" || val.toLowerCase() === "null" || val.toLowerCase() === "undefined");
|
|
501
502
|
for (const key of ["image", "img", "thumbnail"]) {
|
|
502
503
|
const v = data[key];
|
|
503
|
-
if (typeof v === "string" && v) return v;
|
|
504
|
+
if (typeof v === "string" && v && !isPlaceholder(v)) return v;
|
|
504
505
|
}
|
|
505
|
-
if (Array.isArray(data.images) && typeof data.images[0] === "string") {
|
|
506
|
+
if (Array.isArray(data.images) && typeof data.images[0] === "string" && !isPlaceholder(data.images[0])) {
|
|
506
507
|
return data.images[0];
|
|
507
508
|
}
|
|
508
509
|
return void 0;
|
|
@@ -599,6 +600,11 @@ function normalizeTabularRows(rows, columns) {
|
|
|
599
600
|
}).filter((row) => Object.keys(row).length > 0);
|
|
600
601
|
}
|
|
601
602
|
function resolveStructuredRows(config) {
|
|
603
|
+
var _a, _b, _c, _d;
|
|
604
|
+
if (((_a = config.carousel) == null ? void 0 : _a.items) && Array.isArray(config.carousel.items)) return config.carousel.items;
|
|
605
|
+
if (((_b = config.chart) == null ? void 0 : _b.data) && Array.isArray(config.chart.data)) return config.chart.data;
|
|
606
|
+
if (((_c = config.table) == null ? void 0 : _c.rows) && Array.isArray(config.table.rows)) return config.table.rows;
|
|
607
|
+
if (((_d = config.table) == null ? void 0 : _d.data) && Array.isArray(config.table.data)) return config.table.data;
|
|
602
608
|
if (Array.isArray(config.data) && config.data.length > 0) return config.data;
|
|
603
609
|
if (Array.isArray(config.items) && config.items.length > 0) return config.items;
|
|
604
610
|
if (Array.isArray(config.products) && config.products.length > 0) return config.products;
|
|
@@ -614,6 +620,14 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
614
620
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
615
621
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
616
622
|
const config2 = __spreadValues({}, parsed);
|
|
623
|
+
if (config2.chart) {
|
|
624
|
+
if (!config2.chartType) config2.chartType = config2.chart.type;
|
|
625
|
+
if (!config2.xAxisKey) config2.xAxisKey = config2.chart.xKey;
|
|
626
|
+
if (!config2.dataKeys) config2.dataKeys = config2.chart.yKeys;
|
|
627
|
+
}
|
|
628
|
+
if (config2.table) {
|
|
629
|
+
if (!config2.columns) config2.columns = config2.table.columns;
|
|
630
|
+
}
|
|
617
631
|
const resolvedRows = resolveStructuredRows(config2);
|
|
618
632
|
const hasProductLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["price", "brand", "image", "link", "thumbnail"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length >= 4);
|
|
619
633
|
const hasAggregationLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["value", "count", "total", "percentage"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length <= 3 && Object.values(resolvedRows[0]).some((v) => typeof v === "number"));
|