@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.mjs CHANGED
@@ -32,9 +32,9 @@ var ComponentRegistry = class _ComponentRegistry {
32
32
  * Register multiple components at once
33
33
  */
34
34
  registerBatch(components) {
35
- Object.entries(components).forEach(([type, renderer]) => {
35
+ for (const [type, renderer] of Object.entries(components)) {
36
36
  this.register(type, renderer);
37
- });
37
+ }
38
38
  }
39
39
  /**
40
40
  * Get a registered component renderer
@@ -147,12 +147,96 @@ function useToolHandlers() {
147
147
  }
148
148
 
149
149
  // src/hooks/useAgnoToolExecution.ts
150
+ function isRecord(value) {
151
+ return typeof value === "object" && value !== null;
152
+ }
153
+ function normalizeToolArgs(rawArgs) {
154
+ if (isRecord(rawArgs)) {
155
+ return rawArgs;
156
+ }
157
+ if (typeof rawArgs !== "string") {
158
+ return {};
159
+ }
160
+ try {
161
+ const parsed = JSON.parse(rawArgs);
162
+ if (isRecord(parsed)) {
163
+ return parsed;
164
+ }
165
+ } catch {
166
+ }
167
+ return { content: rawArgs };
168
+ }
169
+ function getCustomRenderFunction(value) {
170
+ if (value.type !== "custom") {
171
+ return void 0;
172
+ }
173
+ const maybeRender = value.render;
174
+ return typeof maybeRender === "function" ? maybeRender : void 0;
175
+ }
150
176
  var customRenderRegistry = /* @__PURE__ */ new Map();
151
177
  function registerCustomRender(renderFn) {
152
178
  const key = `custom-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
153
179
  customRenderRegistry.set(key, renderFn);
154
180
  return key;
155
181
  }
182
+ function toSerializableUIComponent(spec) {
183
+ const renderFn = getCustomRenderFunction(spec);
184
+ if (!renderFn) {
185
+ return spec;
186
+ }
187
+ const { render: _render, ...uiWithoutRender } = spec;
188
+ return {
189
+ ...uiWithoutRender,
190
+ renderKey: registerCustomRender(renderFn)
191
+ };
192
+ }
193
+ async function executeToolCall(tool, handlers) {
194
+ const handler = handlers[tool.tool_name];
195
+ if (!handler) {
196
+ return {
197
+ ...tool,
198
+ result: JSON.stringify({
199
+ error: `No handler registered for ${tool.tool_name}`
200
+ })
201
+ };
202
+ }
203
+ try {
204
+ const result = await handler(normalizeToolArgs(tool.tool_args));
205
+ const { resultData, uiComponent } = processToolResult(result, tool);
206
+ return {
207
+ ...tool,
208
+ result: resultData,
209
+ ui_component: uiComponent
210
+ };
211
+ } catch (error) {
212
+ return {
213
+ ...tool,
214
+ result: JSON.stringify({
215
+ error: error instanceof Error ? error.message : String(error)
216
+ })
217
+ };
218
+ }
219
+ }
220
+ async function hydrateToolUIForSession(tools, handlers, onHydrate) {
221
+ for (const tool of tools) {
222
+ if (tool.ui_component) {
223
+ continue;
224
+ }
225
+ const handler = handlers[tool.tool_name];
226
+ if (!handler) {
227
+ continue;
228
+ }
229
+ try {
230
+ const result = await handler(normalizeToolArgs(tool.tool_args));
231
+ const { uiComponent } = processToolResult(result, tool);
232
+ if (uiComponent) {
233
+ onHydrate(tool.tool_call_id, uiComponent);
234
+ }
235
+ } catch (error) {
236
+ console.error(`Failed to hydrate UI for ${tool.tool_name}:`, error);
237
+ }
238
+ }
239
+ }
156
240
  function getCustomRender(key) {
157
241
  return customRenderRegistry.get(key);
158
242
  }
@@ -160,27 +244,17 @@ function clearCustomRenderRegistry() {
160
244
  customRenderRegistry.clear();
161
245
  }
162
246
  function isToolHandlerResult(value) {
163
- return value && typeof value === "object" && ("data" in value || "ui" in value);
247
+ return isRecord(value) && ("data" in value || "ui" in value);
164
248
  }
165
249
  function isUIComponentSpec(value) {
166
- return value && typeof value === "object" && "type" in value;
250
+ return isRecord(value) && typeof value.type === "string";
167
251
  }
168
252
  function processToolResult(result, _tool) {
169
253
  if (isToolHandlerResult(result)) {
170
254
  const { data, ui } = result;
171
255
  let uiComponent;
172
256
  if (ui) {
173
- if (ui.type === "custom" && typeof ui.render === "function") {
174
- const renderKey = registerCustomRender(ui.render);
175
- uiComponent = {
176
- ...ui,
177
- renderKey,
178
- render: void 0
179
- // Don't store the function itself
180
- };
181
- } else {
182
- uiComponent = ui;
183
- }
257
+ uiComponent = toSerializableUIComponent(ui);
184
258
  }
185
259
  return {
186
260
  resultData: typeof data === "string" ? data : JSON.stringify(data),
@@ -188,17 +262,7 @@ function processToolResult(result, _tool) {
188
262
  };
189
263
  }
190
264
  if (isUIComponentSpec(result)) {
191
- let uiComponent;
192
- if (result.type === "custom" && typeof result.render === "function") {
193
- const renderKey = registerCustomRender(result.render);
194
- uiComponent = {
195
- ...result,
196
- renderKey,
197
- render: void 0
198
- };
199
- } else {
200
- uiComponent = result;
201
- }
265
+ const uiComponent = toSerializableUIComponent(result);
202
266
  return {
203
267
  resultData: JSON.stringify(result),
204
268
  uiComponent
@@ -259,35 +323,9 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
259
323
  setExecutionError(void 0);
260
324
  try {
261
325
  const updatedTools = await Promise.all(
262
- pendingTools.map(async (tool) => {
263
- const handler = mergedHandlers[tool.tool_name];
264
- if (!handler) {
265
- return {
266
- ...tool,
267
- result: JSON.stringify({
268
- error: `No handler registered for ${tool.tool_name}`
269
- })
270
- };
271
- }
272
- try {
273
- const result = await handler(tool.tool_args);
274
- const { resultData, uiComponent } = processToolResult(result, tool);
275
- return {
276
- ...tool,
277
- result: resultData,
278
- ui_component: uiComponent
279
- };
280
- } catch (error) {
281
- return {
282
- ...tool,
283
- result: JSON.stringify({
284
- error: error instanceof Error ? error.message : String(error)
285
- })
286
- };
287
- }
288
- })
326
+ pendingTools.map((tool) => executeToolCall(tool, mergedHandlers))
289
327
  );
290
- const toolsWithUI = updatedTools.filter((t) => t.ui_component);
328
+ const toolsWithUI = updatedTools.filter((tool) => tool.ui_component);
291
329
  if (toolsWithUI.length > 0) {
292
330
  client.emit("ui:render", {
293
331
  tools: updatedTools,
@@ -304,31 +342,20 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
304
342
  }
305
343
  }, [client, mergedHandlers, isPaused, pendingTools]);
306
344
  useEffect2(() => {
307
- const handleSessionLoaded = async (_sessionId) => {
308
- const messages = client.getMessages();
309
- for (const message of messages) {
310
- if (!message.tool_calls) {
311
- continue;
345
+ const handleSessionLoaded = (_sessionId) => {
346
+ const tools = client.getMessages().flatMap((message) => message.tool_calls || []);
347
+ hydrateToolUIForSession(
348
+ tools,
349
+ mergedHandlers,
350
+ (toolCallId, uiComponent) => {
351
+ client.hydrateToolCallUI(toolCallId, uiComponent);
312
352
  }
313
- for (const tool of message.tool_calls) {
314
- if (tool.ui_component) {
315
- continue;
316
- }
317
- const handler = mergedHandlers[tool.tool_name];
318
- if (!handler) {
319
- continue;
320
- }
321
- try {
322
- const result = await handler(tool.tool_args);
323
- const { uiComponent } = processToolResult(result, tool);
324
- if (uiComponent) {
325
- client.hydrateToolCallUI(tool.tool_call_id, uiComponent);
326
- }
327
- } catch (err) {
328
- console.error(`Failed to hydrate UI for ${tool.tool_name}:`, err);
329
- }
330
- }
331
- }
353
+ ).catch((error) => {
354
+ console.error(
355
+ "[useAgnoToolExecution] Failed to hydrate session UI:",
356
+ error
357
+ );
358
+ });
332
359
  };
333
360
  client.on("session:loaded", handleSessionLoaded);
334
361
  return () => {
@@ -336,30 +363,9 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
336
363
  };
337
364
  }, [client, mergedHandlers]);
338
365
  const executeTools = useCallback2(
339
- async (tools) => {
366
+ (tools) => {
340
367
  return Promise.all(
341
- tools.map(async (tool) => {
342
- const handler = mergedHandlers[tool.tool_name];
343
- if (!handler) {
344
- return tool;
345
- }
346
- try {
347
- const result = await handler(tool.tool_args);
348
- const { resultData, uiComponent } = processToolResult(result, tool);
349
- return {
350
- ...tool,
351
- result: resultData,
352
- ui_component: uiComponent
353
- };
354
- } catch (error) {
355
- return {
356
- ...tool,
357
- result: JSON.stringify({
358
- error: error instanceof Error ? error.message : String(error)
359
- })
360
- };
361
- }
362
- })
368
+ tools.map((tool) => executeToolCall(tool, mergedHandlers))
363
369
  );
364
370
  },
365
371
  [mergedHandlers]
@@ -380,13 +386,15 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
380
386
  [client, isPaused]
381
387
  );
382
388
  useEffect2(() => {
383
- if (autoExecute && isPaused && !isExecuting && pendingTools.length > 0) {
384
- executeAndContinue();
389
+ if (autoExecute && isPaused && !isExecuting && !executionError && pendingTools.length > 0) {
390
+ executeAndContinue().catch(() => {
391
+ });
385
392
  }
386
393
  }, [
387
394
  autoExecute,
388
395
  isPaused,
389
396
  isExecuting,
397
+ executionError,
390
398
  pendingTools.length,
391
399
  executeAndContinue
392
400
  ]);
@@ -409,7 +417,7 @@ function useAgnoToolExecution(handlers = {}, autoExecute = true) {
409
417
  }
410
418
 
411
419
  // src/components/GenerativeUIRenderer.tsx
412
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
420
+ import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
413
421
  var UIErrorBoundary = class extends React.Component {
414
422
  constructor(props) {
415
423
  super(props);
@@ -436,108 +444,183 @@ var UIErrorBoundary = class extends React.Component {
436
444
  return this.props.children;
437
445
  }
438
446
  };
439
- function GenerativeUIRenderer({
440
- spec,
441
- className,
442
- onError
443
- }) {
444
- const registry = getComponentRegistry();
445
- if (spec.type === "custom") {
446
- const customSpec = spec;
447
- if (customSpec.renderKey) {
448
- const renderFn = getCustomRender(customSpec.renderKey);
449
- if (renderFn) {
450
- return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsx3("div", { className, children: renderFn(customSpec.props || {}) }) });
451
- }
452
- }
453
- return /* @__PURE__ */ jsxs(
454
- "div",
455
- {
456
- className: `rounded-md border border-yellow-300 bg-yellow-50 p-4 text-yellow-800 ${className || ""}`,
457
- children: [
458
- /* @__PURE__ */ jsx3("p", { className: "font-semibold", children: "Custom component not available" }),
459
- /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm", children: "The custom render function for this component is not available." })
460
- ]
461
- }
462
- );
447
+ function joinClassNames(...classNames) {
448
+ return classNames.filter(Boolean).join(" ");
449
+ }
450
+ function renderHeader(title, description) {
451
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
452
+ title ? /* @__PURE__ */ jsx3("h3", { className: "mb-2 font-semibold", children: title }) : null,
453
+ description ? /* @__PURE__ */ jsx3("p", { className: "mb-4 text-gray-600 text-sm", children: description }) : null
454
+ ] });
455
+ }
456
+ function renderFromRegistry(renderer, props) {
457
+ if (!renderer) {
458
+ return void 0;
463
459
  }
464
- if (spec.type === "chart") {
465
- const chartSpec = spec;
466
- const chartType = `chart:${chartSpec.component}`;
467
- if (registry.has(chartType)) {
468
- const ChartRenderer = registry.get(chartType);
469
- return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className, children: [
470
- chartSpec.title && /* @__PURE__ */ jsx3("h3", { className: "mb-2 font-semibold", children: chartSpec.title }),
471
- chartSpec.description && /* @__PURE__ */ jsx3("p", { className: "mb-4 text-gray-600 text-sm", children: chartSpec.description }),
472
- /* @__PURE__ */ jsx3(ChartRenderer, { ...chartSpec.props })
473
- ] }) });
474
- }
475
- return /* @__PURE__ */ jsxs(
476
- "div",
477
- {
478
- className: `rounded-md border border-gray-300 p-4 ${className || ""}`,
479
- children: [
480
- /* @__PURE__ */ jsx3("p", { className: "mb-2 font-semibold", children: chartSpec.title || "Chart Data" }),
481
- chartSpec.description && /* @__PURE__ */ jsx3("p", { className: "mb-2 text-gray-600 text-sm", children: chartSpec.description }),
482
- /* @__PURE__ */ jsx3("pre", { className: "overflow-auto rounded bg-gray-100 p-2 text-xs", children: JSON.stringify(chartSpec.props.data, null, 2) })
483
- ]
484
- }
485
- );
460
+ return renderer(props);
461
+ }
462
+ function getSpecKey(spec) {
463
+ switch (spec.type) {
464
+ case "chart":
465
+ return `${spec.type}-${spec.component}-${spec.title ?? "untitled"}-${spec.props.data.length}`;
466
+ case "card-grid":
467
+ return `${spec.type}-${spec.title ?? "untitled"}-${spec.props.cards.map((card) => card.id).join("|")}`;
468
+ case "table":
469
+ return `${spec.type}-${spec.title ?? "untitled"}-${spec.props.columns.map((column) => column.key).join("|")}`;
470
+ case "markdown":
471
+ return `${spec.type}-${spec.props.content.slice(0, 48)}`;
472
+ case "custom":
473
+ return `${spec.type}-${spec.renderKey}`;
474
+ case "artifact":
475
+ return `${spec.type}-${spec.title ?? "untitled"}-${spec.props.content.length}`;
476
+ default:
477
+ return "unknown-spec";
486
478
  }
487
- if (spec.type === "card-grid") {
488
- const cardGridSpec = spec;
489
- if (registry.has("card-grid")) {
490
- const CardGridRenderer = registry.get("card-grid");
491
- return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className, children: [
492
- cardGridSpec.title && /* @__PURE__ */ jsx3("h3", { className: "mb-2 font-semibold", children: cardGridSpec.title }),
493
- cardGridSpec.description && /* @__PURE__ */ jsx3("p", { className: "mb-4 text-gray-600 text-sm", children: cardGridSpec.description }),
494
- /* @__PURE__ */ jsx3(CardGridRenderer, { ...cardGridSpec.props })
495
- ] }) });
496
- }
479
+ }
480
+ function renderCustomSpec(spec, className, onError) {
481
+ const renderFn = getCustomRender(spec.renderKey);
482
+ if (renderFn) {
483
+ const renderedContent = renderFn(spec.props || {});
484
+ return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsx3("div", { className, children: renderedContent }) });
497
485
  }
498
- if (spec.type === "table") {
499
- const tableSpec = spec;
500
- if (registry.has("table")) {
501
- const TableRenderer = registry.get("table");
502
- return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className, children: [
503
- tableSpec.title && /* @__PURE__ */ jsx3("h3", { className: "mb-2 font-semibold", children: tableSpec.title }),
504
- tableSpec.description && /* @__PURE__ */ jsx3("p", { className: "mb-4 text-gray-600 text-sm", children: tableSpec.description }),
505
- /* @__PURE__ */ jsx3(TableRenderer, { ...tableSpec.props })
506
- ] }) });
486
+ return /* @__PURE__ */ jsxs(
487
+ "div",
488
+ {
489
+ className: joinClassNames(
490
+ "rounded-md border border-yellow-300 bg-yellow-50 p-4 text-yellow-800",
491
+ className
492
+ ),
493
+ children: [
494
+ /* @__PURE__ */ jsx3("p", { className: "font-semibold", children: "Custom component not available" }),
495
+ /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm", children: "The custom render function for this component is not available." })
496
+ ]
507
497
  }
498
+ );
499
+ }
500
+ function renderChartSpec(spec, className, onError) {
501
+ const registry = getComponentRegistry();
502
+ const chartType = `chart:${spec.component}`;
503
+ const chartRenderer = registry.get(chartType);
504
+ const renderedChart = renderFromRegistry(
505
+ chartRenderer,
506
+ spec.props
507
+ );
508
+ if (renderedChart) {
509
+ return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className, children: [
510
+ renderHeader(spec.title, spec.description),
511
+ renderedChart
512
+ ] }) });
508
513
  }
509
- if (spec.type === "markdown") {
510
- const markdownSpec = spec;
511
- if (registry.has("markdown")) {
512
- const MarkdownRenderer = registry.get("markdown");
513
- return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsx3("div", { className, children: /* @__PURE__ */ jsx3(MarkdownRenderer, { ...markdownSpec.props }) }) });
514
+ return /* @__PURE__ */ jsxs(
515
+ "div",
516
+ {
517
+ className: joinClassNames(
518
+ "rounded-md border border-gray-300 p-4",
519
+ className
520
+ ),
521
+ children: [
522
+ /* @__PURE__ */ jsx3("p", { className: "mb-2 font-semibold", children: spec.title || "Chart Data" }),
523
+ spec.description ? /* @__PURE__ */ jsx3("p", { className: "mb-2 text-gray-600 text-sm", children: spec.description }) : null,
524
+ /* @__PURE__ */ jsx3("pre", { className: "overflow-auto rounded bg-gray-100 p-2 text-xs", children: JSON.stringify(spec.props.data, null, 2) })
525
+ ]
514
526
  }
515
- return /* @__PURE__ */ jsx3("div", { className, children: markdownSpec.props.content });
527
+ );
528
+ }
529
+ function renderCardGridSpec(spec, className, onError) {
530
+ const registry = getComponentRegistry();
531
+ const cardGridRenderer = registry.get("card-grid");
532
+ const renderedGrid = renderFromRegistry(
533
+ cardGridRenderer,
534
+ spec.props
535
+ );
536
+ if (!renderedGrid) {
537
+ return renderUnsupportedSpec(spec, className);
516
538
  }
517
- if (spec.type === "artifact") {
518
- const artifactSpec = spec;
519
- return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className: `rounded-md border p-4 ${className || ""}`, children: [
520
- artifactSpec.title && /* @__PURE__ */ jsx3("h3", { className: "mb-4 font-semibold", children: artifactSpec.title }),
521
- artifactSpec.description && /* @__PURE__ */ jsx3("p", { className: "mb-4 text-gray-600 text-sm", children: artifactSpec.description }),
522
- /* @__PURE__ */ jsx3("div", { className: "space-y-4", children: artifactSpec.props.content?.map(
523
- (childSpec, index) => /* @__PURE__ */ jsx3(
524
- GenerativeUIRenderer,
525
- {
526
- onError,
527
- spec: childSpec
528
- },
529
- index
530
- )
531
- ) })
532
- ] }) });
539
+ return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className, children: [
540
+ renderHeader(spec.title, spec.description),
541
+ renderedGrid
542
+ ] }) });
543
+ }
544
+ function renderTableSpec(spec, className, onError) {
545
+ const registry = getComponentRegistry();
546
+ const tableRenderer = registry.get("table");
547
+ const renderedTable = renderFromRegistry(
548
+ tableRenderer,
549
+ spec.props
550
+ );
551
+ if (!renderedTable) {
552
+ return renderUnsupportedSpec(spec, className);
553
+ }
554
+ return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className, children: [
555
+ renderHeader(spec.title, spec.description),
556
+ renderedTable
557
+ ] }) });
558
+ }
559
+ function renderMarkdownSpec(spec, className, onError) {
560
+ const registry = getComponentRegistry();
561
+ const markdownRenderer = registry.get("markdown");
562
+ const renderedMarkdown = renderFromRegistry(
563
+ markdownRenderer,
564
+ spec.props
565
+ );
566
+ if (!renderedMarkdown) {
567
+ return /* @__PURE__ */ jsx3("div", { className, children: spec.props.content });
568
+ }
569
+ return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsx3("div", { className, children: renderedMarkdown }) });
570
+ }
571
+ function renderArtifactSpec(spec, className, onError) {
572
+ return /* @__PURE__ */ jsx3(UIErrorBoundary, { onError, children: /* @__PURE__ */ jsxs("div", { className: joinClassNames("rounded-md border p-4", className), children: [
573
+ spec.title ? /* @__PURE__ */ jsx3("h3", { className: "mb-4 font-semibold", children: spec.title }) : null,
574
+ spec.description ? /* @__PURE__ */ jsx3("p", { className: "mb-4 text-gray-600 text-sm", children: spec.description }) : null,
575
+ /* @__PURE__ */ jsx3("div", { className: "space-y-4", children: spec.props.content.map((childSpec) => /* @__PURE__ */ jsx3(
576
+ GenerativeUIRenderer,
577
+ {
578
+ onError,
579
+ spec: childSpec
580
+ },
581
+ getSpecKey(childSpec)
582
+ )) })
583
+ ] }) });
584
+ }
585
+ function renderUnsupportedSpec(spec, className) {
586
+ return /* @__PURE__ */ jsxs(
587
+ "div",
588
+ {
589
+ className: joinClassNames(
590
+ "rounded-md border border-gray-300 p-4",
591
+ className
592
+ ),
593
+ children: [
594
+ /* @__PURE__ */ jsx3("p", { className: "font-semibold", children: "Unsupported UI component" }),
595
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-gray-600 text-sm", children: [
596
+ "Component type: ",
597
+ spec.type
598
+ ] })
599
+ ]
600
+ }
601
+ );
602
+ }
603
+ function GenerativeUIRenderer({
604
+ spec,
605
+ className,
606
+ onError
607
+ }) {
608
+ switch (spec.type) {
609
+ case "custom":
610
+ return renderCustomSpec(spec, className, onError);
611
+ case "chart":
612
+ return renderChartSpec(spec, className, onError);
613
+ case "card-grid":
614
+ return renderCardGridSpec(spec, className, onError);
615
+ case "table":
616
+ return renderTableSpec(spec, className, onError);
617
+ case "markdown":
618
+ return renderMarkdownSpec(spec, className, onError);
619
+ case "artifact":
620
+ return renderArtifactSpec(spec, className, onError);
621
+ default:
622
+ return renderUnsupportedSpec(spec, className);
533
623
  }
534
- return /* @__PURE__ */ jsxs("div", { className: `rounded-md border border-gray-300 p-4 ${className || ""}`, children: [
535
- /* @__PURE__ */ jsx3("p", { className: "font-semibold", children: "Unsupported UI component" }),
536
- /* @__PURE__ */ jsxs("p", { className: "mt-1 text-gray-600 text-sm", children: [
537
- "Component type: ",
538
- spec.type
539
- ] })
540
- ] });
541
624
  }
542
625
 
543
626
  // src/hooks/useAgnoActions.ts
@@ -646,10 +729,7 @@ function useAgnoChat() {
646
729
  const { tools } = event;
647
730
  for (const tool of tools) {
648
731
  if (tool.ui_component) {
649
- client.hydrateToolCallUI(
650
- tool.tool_call_id,
651
- tool.ui_component
652
- );
732
+ client.hydrateToolCallUI(tool.tool_call_id, tool.ui_component);
653
733
  }
654
734
  }
655
735
  };
@@ -792,6 +872,56 @@ function useAgnoSession() {
792
872
  };
793
873
  }
794
874
 
875
+ // src/utils/tool-handler-validation.ts
876
+ function toDefaultValidationError(failure, options) {
877
+ return {
878
+ success: false,
879
+ code: "INVALID_TOOL_ARGS",
880
+ error: failure.message ?? options?.errorMessage ?? "Invalid tool arguments",
881
+ ...failure.issues !== void 0 ? { issues: failure.issues } : {}
882
+ };
883
+ }
884
+ function createToolArgsValidatorFromSafeParse(safeParse, options) {
885
+ return async (args) => {
886
+ const parsed = await safeParse(args);
887
+ if (parsed.success) {
888
+ return {
889
+ success: true,
890
+ data: parsed.data
891
+ };
892
+ }
893
+ return {
894
+ success: false,
895
+ message: options?.getErrorMessage?.(parsed.error),
896
+ issues: parsed.error
897
+ };
898
+ };
899
+ }
900
+ function createValidatedToolHandler(validator, handler, options) {
901
+ return async (args) => {
902
+ let validationResult;
903
+ try {
904
+ validationResult = await validator(args);
905
+ } catch (error) {
906
+ const thrownFailure = {
907
+ success: false,
908
+ message: error instanceof Error ? error.message : "Tool arguments validation threw an unexpected error"
909
+ };
910
+ if (options?.mapValidationError) {
911
+ return options.mapValidationError(thrownFailure, args);
912
+ }
913
+ return toDefaultValidationError(thrownFailure, options);
914
+ }
915
+ if (!validationResult.success) {
916
+ if (options?.mapValidationError) {
917
+ return options.mapValidationError(validationResult, args);
918
+ }
919
+ return toDefaultValidationError(validationResult, options);
920
+ }
921
+ return handler(validationResult.data);
922
+ };
923
+ }
924
+
795
925
  // src/utils/ui-helpers.ts
796
926
  function createBarChart(data, xKey, bars, options) {
797
927
  return {
@@ -966,6 +1096,7 @@ function createSmartChart(data, options) {
966
1096
  (k) => k !== xKey && typeof firstItem[k] === "number"
967
1097
  );
968
1098
  const yKeys = options?.yKeys || numericKeys;
1099
+ const firstValueKey = yKeys[0] ?? numericKeys[0];
969
1100
  if (options?.preferredType) {
970
1101
  switch (options.preferredType) {
971
1102
  case "bar":
@@ -990,11 +1121,18 @@ function createSmartChart(data, options) {
990
1121
  options
991
1122
  );
992
1123
  case "pie":
993
- return createPieChart(data, yKeys[0], xKey, options);
1124
+ return createPieChart(data, firstValueKey ?? "value", xKey, options);
1125
+ default:
1126
+ return createBarChart(
1127
+ data,
1128
+ xKey,
1129
+ yKeys.map((key) => ({ key })),
1130
+ options
1131
+ );
994
1132
  }
995
1133
  }
996
- if (yKeys.length === 1 && typeof firstItem[xKey] === "string") {
997
- return createPieChart(data, yKeys[0], xKey, options);
1134
+ if (yKeys.length === 1 && firstValueKey && typeof firstItem[xKey] === "string") {
1135
+ return createPieChart(data, firstValueKey, xKey, options);
998
1136
  }
999
1137
  if (xKey.toLowerCase().includes("date") || xKey.toLowerCase().includes("time") || xKey.toLowerCase().includes("month") || xKey.toLowerCase().includes("year")) {
1000
1138
  return createLineChart(
@@ -1043,7 +1181,9 @@ export {
1043
1181
  createPieChart,
1044
1182
  createSmartChart,
1045
1183
  createTable,
1184
+ createToolArgsValidatorFromSafeParse,
1046
1185
  createToolResult,
1186
+ createValidatedToolHandler,
1047
1187
  getChartComponent,
1048
1188
  getComponentRegistry,
1049
1189
  getCustomRender,