@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/README.md +63 -1
- package/dist/index.d.mts +75 -38
- package/dist/index.d.ts +75 -38
- package/dist/index.js +346 -204
- package/dist/index.mjs +345 -205
- package/package.json +3 -3
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
|
-
|
|
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 &&
|
|
315
|
+
return isRecord(value) && ("data" in value || "ui" in value);
|
|
230
316
|
}
|
|
231
317
|
function isUIComponentSpec(value) {
|
|
232
|
-
return value && typeof 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
|
-
|
|
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
|
-
|
|
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(
|
|
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((
|
|
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 =
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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
|
-
|
|
434
|
+
(tools) => {
|
|
406
435
|
return Promise.all(
|
|
407
|
-
tools.map(
|
|
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
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
return
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
{
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
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
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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
|
-
|
|
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
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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,
|
|
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,
|
|
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,
|