@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.
@@ -829,7 +829,8 @@ ${context}`;
829
829
  stopSequences: options == null ? void 0 : options.stop
830
830
  }
831
831
  });
832
- return (_f = response.text) != null ? _f : "";
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 = "<!-- UI_PROTOCOL_V6 -->";
2263
+ const CHART_MARKER = "<!-- UI_PROTOCOL_V7 -->";
2263
2264
  const chartInstruction = `
2264
2265
 
2265
2266
  ${CHART_MARKER}
2266
- ### UNIVERSAL UI PROTOCOL
2267
- 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.
2268
-
2269
- 1. VIEW SELECTION
2270
- - 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").
2271
- - Use "chart" ONLY for numerical aggregations: distributions, percentages, counts, comparisons over time, or trends (e.g. "how many beauty products?").
2272
- - Use "table" for detailed technical specifications, row-heavy comparisons, or when the user explicitly asks for a list/table format.
2273
-
2274
- 2. REQUIRED JSON SHAPE
2275
- {
2276
- "view": "chart" | "carousel" | "table",
2277
- "title": "Short heading",
2278
- "description": "One sentence describing the view",
2279
- "chartType": "pie" | "bar" | "line", // Required if view is "chart"
2280
- "xAxisKey": "label",
2281
- "dataKeys": ["value"],
2282
- "columns": ["dynamicFieldKey1", "dynamicFieldKey2"],
2283
- "insights": ["Short takeaway 1", "Short takeaway 2"],
2284
- "data": []
2285
- }
2286
-
2287
- 3. DATA RULES
2288
- - Build the UI payload from retrieved context only. Do not invent products or values.
2289
- - For CAROUSEL: "data" must be a list of product objects (id, name, brand, price, image, link).
2290
- - For CHART: "data" must be aggregated counts or sums. Never put raw product lists in a chart view.
2291
- - If the user asks for "products in beauty", do NOT return a pie chart of categories; return a carousel of the beauty products themselves.
2292
-
2293
- 4. FORMAT RULES
2294
- - Return valid JSON inside the \`\`\`ui\`\`\` block.
2295
- - Put natural language explanation before or after the block, not inside.
2296
-
2297
- 5. EXAMPLES
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
- Assistant:
2395
+
2300
2396
  \`\`\`ui
2301
2397
  {
2302
2398
  "view": "carousel",
2303
2399
  "title": "Beauty Products",
2304
- "description": "Browse our latest skincare and makeup collection.",
2305
- "data": [
2306
- { "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "...", "link": "..." },
2307
- { "id": "2", "name": "Lipstick", "brand": "Chic", "price": "$12.99", "image": "...", "link": "..." }
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
- User: "breakdown of products by category"
2313
- Assistant:
2422
+ ---
2423
+
2424
+ User: "distribution of products across categories"
2425
+
2314
2426
  \`\`\`ui
2315
2427
  {
2316
2428
  "view": "chart",
2317
- "title": "Category Breakdown",
2318
- "chartType": "pie",
2319
- "xAxisKey": "label",
2320
- "dataKeys": ["value"],
2321
- "data": [
2322
- { "label": "Beauty", "value": 15 },
2323
- { "label": "Fragrances", "value": 8 }
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
- this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
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);
@@ -2437,7 +2437,8 @@ ${context}`;
2437
2437
  stopSequences: options == null ? void 0 : options.stop
2438
2438
  }
2439
2439
  });
2440
- return (_f = response.text) != null ? _f : "";
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 = "<!-- UI_PROTOCOL_V6 -->";
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
- 1. VIEW SELECTION
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
- 2. REQUIRED JSON SHAPE
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
- 3. DATA RULES
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
- 4. FORMAT RULES
3858
- - Return valid JSON inside the \`\`\`ui\`\`\` block.
3859
- - Put natural language explanation before or after the block, not inside.
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
- Assistant:
3959
+
3864
3960
  \`\`\`ui
3865
3961
  {
3866
3962
  "view": "carousel",
3867
3963
  "title": "Beauty Products",
3868
- "description": "Browse our latest skincare and makeup collection.",
3869
- "data": [
3870
- { "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "...", "link": "..." },
3871
- { "id": "2", "name": "Lipstick", "brand": "Chic", "price": "$12.99", "image": "...", "link": "..." }
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
- User: "breakdown of products by category"
3877
- Assistant:
3986
+ ---
3987
+
3988
+ User: "distribution of products across categories"
3989
+
3878
3990
  \`\`\`ui
3879
3991
  {
3880
3992
  "view": "chart",
3881
- "title": "Category Breakdown",
3882
- "chartType": "pie",
3883
- "xAxisKey": "label",
3884
- "dataKeys": ["value"],
3885
- "data": [
3886
- { "label": "Beauty", "value": 15 },
3887
- { "label": "Fragrances", "value": 8 }
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
- this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
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);
@@ -10,7 +10,7 @@ import {
10
10
  sseMetaFrame,
11
11
  sseTextFrame,
12
12
  sseUIFrame
13
- } from "../chunk-M32ZXLTT.mjs";
13
+ } from "../chunk-QOO37S2Z.mjs";
14
14
  import "../chunk-YLTMFW4M.mjs";
15
15
  import "../chunk-X4TOT24V.mjs";
16
16
  export {
package/dist/index.js CHANGED
@@ -405,7 +405,7 @@ function sanitizeJson(raw) {
405
405
  return `: ${result}`;
406
406
  }
407
407
  );
408
- s = s.replace(/\/\/[^\n]*/g, "");
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(/\/\/[^\n]*/g, "");
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"));