@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.mjs
CHANGED
|
@@ -32,9 +32,9 @@ var ComponentRegistry = class _ComponentRegistry {
|
|
|
32
32
|
* Register multiple components at once
|
|
33
33
|
*/
|
|
34
34
|
registerBatch(components) {
|
|
35
|
-
|
|
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 &&
|
|
247
|
+
return isRecord(value) && ("data" in value || "ui" in value);
|
|
164
248
|
}
|
|
165
249
|
function isUIComponentSpec(value) {
|
|
166
|
-
return value && typeof 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
|
-
|
|
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
|
-
|
|
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(
|
|
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((
|
|
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 =
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
366
|
+
(tools) => {
|
|
340
367
|
return Promise.all(
|
|
341
|
-
tools.map(
|
|
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
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
return
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
{
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
|
|
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
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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,
|
|
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,
|
|
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,
|