@antipopp/agno-react 0.10.0 → 0.12.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.js CHANGED
@@ -46,7 +46,9 @@ __export(src_exports, {
46
46
  createPieChart: () => createPieChart,
47
47
  createSmartChart: () => createSmartChart,
48
48
  createTable: () => createTable,
49
+ createToolArgsValidatorFromSafeParse: () => createToolArgsValidatorFromSafeParse,
49
50
  createToolResult: () => createToolResult,
51
+ createValidatedToolHandler: () => createValidatedToolHandler,
50
52
  getChartComponent: () => getChartComponent,
51
53
  getComponentRegistry: () => getComponentRegistry,
52
54
  getCustomRender: () => getCustomRender,
@@ -98,9 +100,9 @@ var ComponentRegistry = class _ComponentRegistry {
98
100
  * Register multiple components at once
99
101
  */
100
102
  registerBatch(components) {
101
- Object.entries(components).forEach(([type, renderer]) => {
103
+ for (const [type, renderer] of Object.entries(components)) {
102
104
  this.register(type, renderer);
103
- });
105
+ }
104
106
  }
105
107
  /**
106
108
  * Get a registered component renderer
@@ -213,12 +215,96 @@ function useToolHandlers() {
213
215
  }
214
216
 
215
217
  // src/hooks/useAgnoToolExecution.ts
218
+ function isRecord(value) {
219
+ return typeof value === "object" && value !== null;
220
+ }
221
+ function normalizeToolArgs(rawArgs) {
222
+ if (isRecord(rawArgs)) {
223
+ return rawArgs;
224
+ }
225
+ if (typeof rawArgs !== "string") {
226
+ return {};
227
+ }
228
+ try {
229
+ const parsed = JSON.parse(rawArgs);
230
+ if (isRecord(parsed)) {
231
+ return parsed;
232
+ }
233
+ } catch {
234
+ }
235
+ return { content: rawArgs };
236
+ }
237
+ function getCustomRenderFunction(value) {
238
+ if (value.type !== "custom") {
239
+ return void 0;
240
+ }
241
+ const maybeRender = value.render;
242
+ return typeof maybeRender === "function" ? maybeRender : void 0;
243
+ }
216
244
  var customRenderRegistry = /* @__PURE__ */ new Map();
217
245
  function registerCustomRender(renderFn) {
218
246
  const key = `custom-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
219
247
  customRenderRegistry.set(key, renderFn);
220
248
  return key;
221
249
  }
250
+ function toSerializableUIComponent(spec) {
251
+ const renderFn = getCustomRenderFunction(spec);
252
+ if (!renderFn) {
253
+ return spec;
254
+ }
255
+ const { render: _render, ...uiWithoutRender } = spec;
256
+ return {
257
+ ...uiWithoutRender,
258
+ renderKey: registerCustomRender(renderFn)
259
+ };
260
+ }
261
+ async function executeToolCall(tool, handlers) {
262
+ const handler = handlers[tool.tool_name];
263
+ if (!handler) {
264
+ return {
265
+ ...tool,
266
+ result: JSON.stringify({
267
+ error: `No handler registered for ${tool.tool_name}`
268
+ })
269
+ };
270
+ }
271
+ try {
272
+ const result = await handler(normalizeToolArgs(tool.tool_args));
273
+ const { resultData, uiComponent } = processToolResult(result, tool);
274
+ return {
275
+ ...tool,
276
+ result: resultData,
277
+ ui_component: uiComponent
278
+ };
279
+ } catch (error) {
280
+ return {
281
+ ...tool,
282
+ result: JSON.stringify({
283
+ error: error instanceof Error ? error.message : String(error)
284
+ })
285
+ };
286
+ }
287
+ }
288
+ async function hydrateToolUIForSession(tools, handlers, onHydrate) {
289
+ for (const tool of tools) {
290
+ if (tool.ui_component) {
291
+ continue;
292
+ }
293
+ const handler = handlers[tool.tool_name];
294
+ if (!handler) {
295
+ continue;
296
+ }
297
+ try {
298
+ const result = await handler(normalizeToolArgs(tool.tool_args));
299
+ const { uiComponent } = processToolResult(result, tool);
300
+ if (uiComponent) {
301
+ onHydrate(tool.tool_call_id, uiComponent);
302
+ }
303
+ } catch (error) {
304
+ console.error(`Failed to hydrate UI for ${tool.tool_name}:`, error);
305
+ }
306
+ }
307
+ }
222
308
  function getCustomRender(key) {
223
309
  return customRenderRegistry.get(key);
224
310
  }
@@ -226,27 +312,17 @@ function clearCustomRenderRegistry() {
226
312
  customRenderRegistry.clear();
227
313
  }
228
314
  function isToolHandlerResult(value) {
229
- return value && typeof value === "object" && ("data" in value || "ui" in value);
315
+ return isRecord(value) && ("data" in value || "ui" in value);
230
316
  }
231
317
  function isUIComponentSpec(value) {
232
- return value && typeof value === "object" && "type" in value;
318
+ return isRecord(value) && typeof value.type === "string";
233
319
  }
234
320
  function processToolResult(result, _tool) {
235
321
  if (isToolHandlerResult(result)) {
236
322
  const { data, ui } = result;
237
323
  let uiComponent;
238
324
  if (ui) {
239
- if (ui.type === "custom" && typeof ui.render === "function") {
240
- const renderKey = registerCustomRender(ui.render);
241
- uiComponent = {
242
- ...ui,
243
- renderKey,
244
- render: void 0
245
- // Don't store the function itself
246
- };
247
- } else {
248
- uiComponent = ui;
249
- }
325
+ uiComponent = toSerializableUIComponent(ui);
250
326
  }
251
327
  return {
252
328
  resultData: typeof data === "string" ? data : JSON.stringify(data),
@@ -254,17 +330,7 @@ function processToolResult(result, _tool) {
254
330
  };
255
331
  }
256
332
  if (isUIComponentSpec(result)) {
257
- let uiComponent;
258
- if (result.type === "custom" && typeof result.render === "function") {
259
- const renderKey = registerCustomRender(result.render);
260
- uiComponent = {
261
- ...result,
262
- renderKey,
263
- render: void 0
264
- };
265
- } else {
266
- uiComponent = result;
267
- }
333
+ const uiComponent = toSerializableUIComponent(result);
268
334
  return {
269
335
  resultData: JSON.stringify(result),
270
336
  uiComponent
@@ -325,35 +391,9 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
325
391
  setExecutionError(void 0);
326
392
  try {
327
393
  const updatedTools = await Promise.all(
328
- pendingTools.map(async (tool) => {
329
- const handler = mergedHandlers[tool.tool_name];
330
- if (!handler) {
331
- return {
332
- ...tool,
333
- result: JSON.stringify({
334
- error: `No handler registered for ${tool.tool_name}`
335
- })
336
- };
337
- }
338
- try {
339
- const result = await handler(tool.tool_args);
340
- const { resultData, uiComponent } = processToolResult(result, tool);
341
- return {
342
- ...tool,
343
- result: resultData,
344
- ui_component: uiComponent
345
- };
346
- } catch (error) {
347
- return {
348
- ...tool,
349
- result: JSON.stringify({
350
- error: error instanceof Error ? error.message : String(error)
351
- })
352
- };
353
- }
354
- })
394
+ pendingTools.map((tool) => executeToolCall(tool, mergedHandlers))
355
395
  );
356
- const toolsWithUI = updatedTools.filter((t) => t.ui_component);
396
+ const toolsWithUI = updatedTools.filter((tool) => tool.ui_component);
357
397
  if (toolsWithUI.length > 0) {
358
398
  client.emit("ui:render", {
359
399
  tools: updatedTools,
@@ -370,31 +410,20 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
370
410
  }
371
411
  }, [client, mergedHandlers, isPaused, pendingTools]);
372
412
  (0, import_react3.useEffect)(() => {
373
- const handleSessionLoaded = async (_sessionId) => {
374
- const messages = client.getMessages();
375
- for (const message of messages) {
376
- if (!message.tool_calls) {
377
- continue;
413
+ const handleSessionLoaded = (_sessionId) => {
414
+ const tools = client.getMessages().flatMap((message) => message.tool_calls || []);
415
+ hydrateToolUIForSession(
416
+ tools,
417
+ mergedHandlers,
418
+ (toolCallId, uiComponent) => {
419
+ client.hydrateToolCallUI(toolCallId, uiComponent);
378
420
  }
379
- for (const tool of message.tool_calls) {
380
- if (tool.ui_component) {
381
- continue;
382
- }
383
- const handler = mergedHandlers[tool.tool_name];
384
- if (!handler) {
385
- continue;
386
- }
387
- try {
388
- const result = await handler(tool.tool_args);
389
- const { uiComponent } = processToolResult(result, tool);
390
- if (uiComponent) {
391
- client.hydrateToolCallUI(tool.tool_call_id, uiComponent);
392
- }
393
- } catch (err) {
394
- console.error(`Failed to hydrate UI for ${tool.tool_name}:`, err);
395
- }
396
- }
397
- }
421
+ ).catch((error) => {
422
+ console.error(
423
+ "[useAgnoToolExecution] Failed to hydrate session UI:",
424
+ error
425
+ );
426
+ });
398
427
  };
399
428
  client.on("session:loaded", handleSessionLoaded);
400
429
  return () => {
@@ -402,30 +431,9 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
402
431
  };
403
432
  }, [client, mergedHandlers]);
404
433
  const executeTools = (0, import_react3.useCallback)(
405
- async (tools) => {
434
+ (tools) => {
406
435
  return Promise.all(
407
- tools.map(async (tool) => {
408
- const handler = mergedHandlers[tool.tool_name];
409
- if (!handler) {
410
- return tool;
411
- }
412
- try {
413
- const result = await handler(tool.tool_args);
414
- const { resultData, uiComponent } = processToolResult(result, tool);
415
- return {
416
- ...tool,
417
- result: resultData,
418
- ui_component: uiComponent
419
- };
420
- } catch (error) {
421
- return {
422
- ...tool,
423
- result: JSON.stringify({
424
- error: error instanceof Error ? error.message : String(error)
425
- })
426
- };
427
- }
428
- })
436
+ tools.map((tool) => executeToolCall(tool, mergedHandlers))
429
437
  );
430
438
  },
431
439
  [mergedHandlers]
@@ -446,13 +454,15 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
446
454
  [client, isPaused]
447
455
  );
448
456
  (0, import_react3.useEffect)(() => {
449
- if (autoExecute && isPaused && !isExecuting && pendingTools.length > 0) {
450
- executeAndContinue();
457
+ if (autoExecute && isPaused && !isExecuting && !executionError && pendingTools.length > 0) {
458
+ executeAndContinue().catch(() => {
459
+ });
451
460
  }
452
461
  }, [
453
462
  autoExecute,
454
463
  isPaused,
455
464
  isExecuting,
465
+ executionError,
456
466
  pendingTools.length,
457
467
  executeAndContinue
458
468
  ]);
@@ -502,108 +512,183 @@ var UIErrorBoundary = class extends import_react4.default.Component {
502
512
  return this.props.children;
503
513
  }
504
514
  };
505
- function GenerativeUIRenderer({
506
- spec,
507
- className,
508
- onError
509
- }) {
510
- const registry = getComponentRegistry();
511
- if (spec.type === "custom") {
512
- const customSpec = spec;
513
- if (customSpec.renderKey) {
514
- const renderFn = getCustomRender(customSpec.renderKey);
515
- if (renderFn) {
516
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children: renderFn(customSpec.props || {}) }) });
517
- }
518
- }
519
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
520
- "div",
521
- {
522
- className: `rounded-md border border-yellow-300 bg-yellow-50 p-4 text-yellow-800 ${className || ""}`,
523
- children: [
524
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "font-semibold", children: "Custom component not available" }),
525
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mt-1 text-sm", children: "The custom render function for this component is not available." })
526
- ]
527
- }
528
- );
515
+ function joinClassNames(...classNames) {
516
+ return classNames.filter(Boolean).join(" ");
517
+ }
518
+ function renderHeader(title, description) {
519
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
520
+ title ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-2 font-semibold", children: title }) : null,
521
+ description ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-4 text-gray-600 text-sm", children: description }) : null
522
+ ] });
523
+ }
524
+ function renderFromRegistry(renderer, props) {
525
+ if (!renderer) {
526
+ return void 0;
529
527
  }
530
- if (spec.type === "chart") {
531
- const chartSpec = spec;
532
- const chartType = `chart:${chartSpec.component}`;
533
- if (registry.has(chartType)) {
534
- const ChartRenderer = registry.get(chartType);
535
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, children: [
536
- chartSpec.title && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-2 font-semibold", children: chartSpec.title }),
537
- chartSpec.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-4 text-gray-600 text-sm", children: chartSpec.description }),
538
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChartRenderer, { ...chartSpec.props })
539
- ] }) });
540
- }
541
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
542
- "div",
543
- {
544
- className: `rounded-md border border-gray-300 p-4 ${className || ""}`,
545
- children: [
546
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-2 font-semibold", children: chartSpec.title || "Chart Data" }),
547
- chartSpec.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-2 text-gray-600 text-sm", children: chartSpec.description }),
548
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { className: "overflow-auto rounded bg-gray-100 p-2 text-xs", children: JSON.stringify(chartSpec.props.data, null, 2) })
549
- ]
550
- }
551
- );
528
+ return renderer(props);
529
+ }
530
+ function getSpecKey(spec) {
531
+ switch (spec.type) {
532
+ case "chart":
533
+ return `${spec.type}-${spec.component}-${spec.title ?? "untitled"}-${spec.props.data.length}`;
534
+ case "card-grid":
535
+ return `${spec.type}-${spec.title ?? "untitled"}-${spec.props.cards.map((card) => card.id).join("|")}`;
536
+ case "table":
537
+ return `${spec.type}-${spec.title ?? "untitled"}-${spec.props.columns.map((column) => column.key).join("|")}`;
538
+ case "markdown":
539
+ return `${spec.type}-${spec.props.content.slice(0, 48)}`;
540
+ case "custom":
541
+ return `${spec.type}-${spec.renderKey}`;
542
+ case "artifact":
543
+ return `${spec.type}-${spec.title ?? "untitled"}-${spec.props.content.length}`;
544
+ default:
545
+ return "unknown-spec";
552
546
  }
553
- if (spec.type === "card-grid") {
554
- const cardGridSpec = spec;
555
- if (registry.has("card-grid")) {
556
- const CardGridRenderer = registry.get("card-grid");
557
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, children: [
558
- cardGridSpec.title && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-2 font-semibold", children: cardGridSpec.title }),
559
- cardGridSpec.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-4 text-gray-600 text-sm", children: cardGridSpec.description }),
560
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CardGridRenderer, { ...cardGridSpec.props })
561
- ] }) });
562
- }
547
+ }
548
+ function renderCustomSpec(spec, className, onError) {
549
+ const renderFn = getCustomRender(spec.renderKey);
550
+ if (renderFn) {
551
+ const renderedContent = renderFn(spec.props || {});
552
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children: renderedContent }) });
563
553
  }
564
- if (spec.type === "table") {
565
- const tableSpec = spec;
566
- if (registry.has("table")) {
567
- const TableRenderer = registry.get("table");
568
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, children: [
569
- tableSpec.title && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-2 font-semibold", children: tableSpec.title }),
570
- tableSpec.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-4 text-gray-600 text-sm", children: tableSpec.description }),
571
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TableRenderer, { ...tableSpec.props })
572
- ] }) });
554
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
555
+ "div",
556
+ {
557
+ className: joinClassNames(
558
+ "rounded-md border border-yellow-300 bg-yellow-50 p-4 text-yellow-800",
559
+ className
560
+ ),
561
+ children: [
562
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "font-semibold", children: "Custom component not available" }),
563
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mt-1 text-sm", children: "The custom render function for this component is not available." })
564
+ ]
573
565
  }
566
+ );
567
+ }
568
+ function renderChartSpec(spec, className, onError) {
569
+ const registry = getComponentRegistry();
570
+ const chartType = `chart:${spec.component}`;
571
+ const chartRenderer = registry.get(chartType);
572
+ const renderedChart = renderFromRegistry(
573
+ chartRenderer,
574
+ spec.props
575
+ );
576
+ if (renderedChart) {
577
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, children: [
578
+ renderHeader(spec.title, spec.description),
579
+ renderedChart
580
+ ] }) });
574
581
  }
575
- if (spec.type === "markdown") {
576
- const markdownSpec = spec;
577
- if (registry.has("markdown")) {
578
- const MarkdownRenderer = registry.get("markdown");
579
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MarkdownRenderer, { ...markdownSpec.props }) }) });
582
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
583
+ "div",
584
+ {
585
+ className: joinClassNames(
586
+ "rounded-md border border-gray-300 p-4",
587
+ className
588
+ ),
589
+ children: [
590
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-2 font-semibold", children: spec.title || "Chart Data" }),
591
+ spec.description ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-2 text-gray-600 text-sm", children: spec.description }) : null,
592
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { className: "overflow-auto rounded bg-gray-100 p-2 text-xs", children: JSON.stringify(spec.props.data, null, 2) })
593
+ ]
580
594
  }
581
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children: markdownSpec.props.content });
595
+ );
596
+ }
597
+ function renderCardGridSpec(spec, className, onError) {
598
+ const registry = getComponentRegistry();
599
+ const cardGridRenderer = registry.get("card-grid");
600
+ const renderedGrid = renderFromRegistry(
601
+ cardGridRenderer,
602
+ spec.props
603
+ );
604
+ if (!renderedGrid) {
605
+ return renderUnsupportedSpec(spec, className);
582
606
  }
583
- if (spec.type === "artifact") {
584
- const artifactSpec = spec;
585
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `rounded-md border p-4 ${className || ""}`, children: [
586
- artifactSpec.title && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-4 font-semibold", children: artifactSpec.title }),
587
- artifactSpec.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-4 text-gray-600 text-sm", children: artifactSpec.description }),
588
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "space-y-4", children: artifactSpec.props.content?.map(
589
- (childSpec, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
590
- GenerativeUIRenderer,
591
- {
592
- onError,
593
- spec: childSpec
594
- },
595
- index
596
- )
597
- ) })
598
- ] }) });
607
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, children: [
608
+ renderHeader(spec.title, spec.description),
609
+ renderedGrid
610
+ ] }) });
611
+ }
612
+ function renderTableSpec(spec, className, onError) {
613
+ const registry = getComponentRegistry();
614
+ const tableRenderer = registry.get("table");
615
+ const renderedTable = renderFromRegistry(
616
+ tableRenderer,
617
+ spec.props
618
+ );
619
+ if (!renderedTable) {
620
+ return renderUnsupportedSpec(spec, className);
621
+ }
622
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, children: [
623
+ renderHeader(spec.title, spec.description),
624
+ renderedTable
625
+ ] }) });
626
+ }
627
+ function renderMarkdownSpec(spec, className, onError) {
628
+ const registry = getComponentRegistry();
629
+ const markdownRenderer = registry.get("markdown");
630
+ const renderedMarkdown = renderFromRegistry(
631
+ markdownRenderer,
632
+ spec.props
633
+ );
634
+ if (!renderedMarkdown) {
635
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children: spec.props.content });
636
+ }
637
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className, children: renderedMarkdown }) });
638
+ }
639
+ function renderArtifactSpec(spec, className, onError) {
640
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(UIErrorBoundary, { onError, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: joinClassNames("rounded-md border p-4", className), children: [
641
+ spec.title ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-4 font-semibold", children: spec.title }) : null,
642
+ spec.description ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "mb-4 text-gray-600 text-sm", children: spec.description }) : null,
643
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "space-y-4", children: spec.props.content.map((childSpec) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
644
+ GenerativeUIRenderer,
645
+ {
646
+ onError,
647
+ spec: childSpec
648
+ },
649
+ getSpecKey(childSpec)
650
+ )) })
651
+ ] }) });
652
+ }
653
+ function renderUnsupportedSpec(spec, className) {
654
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
655
+ "div",
656
+ {
657
+ className: joinClassNames(
658
+ "rounded-md border border-gray-300 p-4",
659
+ className
660
+ ),
661
+ children: [
662
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "font-semibold", children: "Unsupported UI component" }),
663
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "mt-1 text-gray-600 text-sm", children: [
664
+ "Component type: ",
665
+ spec.type
666
+ ] })
667
+ ]
668
+ }
669
+ );
670
+ }
671
+ function GenerativeUIRenderer({
672
+ spec,
673
+ className,
674
+ onError
675
+ }) {
676
+ switch (spec.type) {
677
+ case "custom":
678
+ return renderCustomSpec(spec, className, onError);
679
+ case "chart":
680
+ return renderChartSpec(spec, className, onError);
681
+ case "card-grid":
682
+ return renderCardGridSpec(spec, className, onError);
683
+ case "table":
684
+ return renderTableSpec(spec, className, onError);
685
+ case "markdown":
686
+ return renderMarkdownSpec(spec, className, onError);
687
+ case "artifact":
688
+ return renderArtifactSpec(spec, className, onError);
689
+ default:
690
+ return renderUnsupportedSpec(spec, className);
599
691
  }
600
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `rounded-md border border-gray-300 p-4 ${className || ""}`, children: [
601
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "font-semibold", children: "Unsupported UI component" }),
602
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "mt-1 text-gray-600 text-sm", children: [
603
- "Component type: ",
604
- spec.type
605
- ] })
606
- ] });
607
692
  }
608
693
 
609
694
  // src/hooks/useAgnoActions.ts
@@ -712,10 +797,7 @@ function useAgnoChat() {
712
797
  const { tools } = event;
713
798
  for (const tool of tools) {
714
799
  if (tool.ui_component) {
715
- client.hydrateToolCallUI(
716
- tool.tool_call_id,
717
- tool.ui_component
718
- );
800
+ client.hydrateToolCallUI(tool.tool_call_id, tool.ui_component);
719
801
  }
720
802
  }
721
803
  };
@@ -858,6 +940,56 @@ function useAgnoSession() {
858
940
  };
859
941
  }
860
942
 
943
+ // src/utils/tool-handler-validation.ts
944
+ function toDefaultValidationError(failure, options) {
945
+ return {
946
+ success: false,
947
+ code: "INVALID_TOOL_ARGS",
948
+ error: failure.message ?? options?.errorMessage ?? "Invalid tool arguments",
949
+ ...failure.issues !== void 0 ? { issues: failure.issues } : {}
950
+ };
951
+ }
952
+ function createToolArgsValidatorFromSafeParse(safeParse, options) {
953
+ return async (args) => {
954
+ const parsed = await safeParse(args);
955
+ if (parsed.success) {
956
+ return {
957
+ success: true,
958
+ data: parsed.data
959
+ };
960
+ }
961
+ return {
962
+ success: false,
963
+ message: options?.getErrorMessage?.(parsed.error),
964
+ issues: parsed.error
965
+ };
966
+ };
967
+ }
968
+ function createValidatedToolHandler(validator, handler, options) {
969
+ return async (args) => {
970
+ let validationResult;
971
+ try {
972
+ validationResult = await validator(args);
973
+ } catch (error) {
974
+ const thrownFailure = {
975
+ success: false,
976
+ message: error instanceof Error ? error.message : "Tool arguments validation threw an unexpected error"
977
+ };
978
+ if (options?.mapValidationError) {
979
+ return options.mapValidationError(thrownFailure, args);
980
+ }
981
+ return toDefaultValidationError(thrownFailure, options);
982
+ }
983
+ if (!validationResult.success) {
984
+ if (options?.mapValidationError) {
985
+ return options.mapValidationError(validationResult, args);
986
+ }
987
+ return toDefaultValidationError(validationResult, options);
988
+ }
989
+ return handler(validationResult.data);
990
+ };
991
+ }
992
+
861
993
  // src/utils/ui-helpers.ts
862
994
  function createBarChart(data, xKey, bars, options) {
863
995
  return {
@@ -1032,6 +1164,7 @@ function createSmartChart(data, options) {
1032
1164
  (k) => k !== xKey && typeof firstItem[k] === "number"
1033
1165
  );
1034
1166
  const yKeys = options?.yKeys || numericKeys;
1167
+ const firstValueKey = yKeys[0] ?? numericKeys[0];
1035
1168
  if (options?.preferredType) {
1036
1169
  switch (options.preferredType) {
1037
1170
  case "bar":
@@ -1056,11 +1189,18 @@ function createSmartChart(data, options) {
1056
1189
  options
1057
1190
  );
1058
1191
  case "pie":
1059
- return createPieChart(data, yKeys[0], xKey, options);
1192
+ return createPieChart(data, firstValueKey ?? "value", xKey, options);
1193
+ default:
1194
+ return createBarChart(
1195
+ data,
1196
+ xKey,
1197
+ yKeys.map((key) => ({ key })),
1198
+ options
1199
+ );
1060
1200
  }
1061
1201
  }
1062
- if (yKeys.length === 1 && typeof firstItem[xKey] === "string") {
1063
- return createPieChart(data, yKeys[0], xKey, options);
1202
+ if (yKeys.length === 1 && firstValueKey && typeof firstItem[xKey] === "string") {
1203
+ return createPieChart(data, firstValueKey, xKey, options);
1064
1204
  }
1065
1205
  if (xKey.toLowerCase().includes("date") || xKey.toLowerCase().includes("time") || xKey.toLowerCase().includes("month") || xKey.toLowerCase().includes("year")) {
1066
1206
  return createLineChart(
@@ -1110,7 +1250,9 @@ function resultWithTable(data, columns, options) {
1110
1250
  createPieChart,
1111
1251
  createSmartChart,
1112
1252
  createTable,
1253
+ createToolArgsValidatorFromSafeParse,
1113
1254
  createToolResult,
1255
+ createValidatedToolHandler,
1114
1256
  getChartComponent,
1115
1257
  getComponentRegistry,
1116
1258
  getCustomRender,