@infuro/cms-core 1.0.19 → 1.0.20
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/admin.cjs +534 -11
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.js +564 -23
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +727 -36
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +705 -18
- package/dist/api.js.map +1 -1
- package/dist/{index-GMn7-9PX.d.ts → index--GBYw5JE.d.ts} +84 -2
- package/dist/{index-D2C1O9b4.d.cts → index-DGtM2Gsk.d.cts} +84 -2
- package/dist/index.cjs +1701 -713
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -13
- package/dist/index.d.ts +99 -13
- package/dist/index.js +1554 -574
- package/dist/index.js.map +1 -1
- package/dist/migrations/1775300000000-LlmAgents.ts +57 -0
- package/dist/migrations/1775300000001-LlmAgentsValidationRulesText.ts +43 -0
- package/dist/migrations/1775300000002-SeedLlmAgentsPermissions.ts +33 -0
- package/dist/migrations/1775300000003-LlmAgentKnowledgeDocuments.ts +50 -0
- package/dist/migrations/1775400000000-KnowledgeBaseVectorDimension384.ts +32 -0
- package/package.json +8 -6
package/dist/admin.cjs
CHANGED
|
@@ -401,7 +401,7 @@ var defaultValue = {
|
|
|
401
401
|
var AdminConfigContext = (0, import_react4.createContext)(defaultValue);
|
|
402
402
|
|
|
403
403
|
// src/lib/cms-version.ts
|
|
404
|
-
var CMS_VERSION = true ? "1.0.
|
|
404
|
+
var CMS_VERSION = true ? "1.0.20" : "0.0.0";
|
|
405
405
|
|
|
406
406
|
// src/components/Admin/Sidebar.tsx
|
|
407
407
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -546,6 +546,10 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
546
546
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.Shield, { className: `h-4 w-4 mr-2 ${isActive("/admin/roles") ? iconActive : iconInactive}` }),
|
|
547
547
|
"Roles"
|
|
548
548
|
] }) }),
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_link2.default, { href: "/admin/llm_agents", className: `${linkCls} ${isActive("/admin/llm_agents") ? linkActive : linkInactive}`, children: [
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.Bot, { className: `h-4 w-4 mr-2 ${isActive("/admin/llm_agents") ? iconActive : iconInactive}` }),
|
|
551
|
+
"LLM agents"
|
|
552
|
+
] }) }),
|
|
549
553
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_link2.default, { href: "/admin/plugins", className: `${linkCls} ${isActive("/admin/plugins") ? linkActive : linkInactive}`, children: [
|
|
550
554
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.Puzzle, { className: `h-4 w-4 mr-2 ${isActive("/admin/plugins") ? iconActive : iconInactive}` }),
|
|
551
555
|
"Plugins"
|
|
@@ -1404,7 +1408,9 @@ function CreateEditForm({ isOpen, onClose, apiEndpoint, columns, existingData })
|
|
|
1404
1408
|
if (existingData) {
|
|
1405
1409
|
setFormData(existingData);
|
|
1406
1410
|
} else {
|
|
1407
|
-
setFormData(
|
|
1411
|
+
setFormData(
|
|
1412
|
+
columns.filter((col) => !col.hideInForm).reduce((acc, col) => ({ ...acc, [col.field]: col.defaultValue || "" }), {})
|
|
1413
|
+
);
|
|
1408
1414
|
}
|
|
1409
1415
|
}, [existingData, columns]);
|
|
1410
1416
|
const handleChange = (e, field) => {
|
|
@@ -1418,7 +1424,7 @@ function CreateEditForm({ isOpen, onClose, apiEndpoint, columns, existingData })
|
|
|
1418
1424
|
};
|
|
1419
1425
|
const validateForm = () => {
|
|
1420
1426
|
let newErrors = {};
|
|
1421
|
-
columns.forEach((col) => {
|
|
1427
|
+
columns.filter((col) => !col.hideInForm).forEach((col) => {
|
|
1422
1428
|
if (col.validation?.required && !formData[col.field]) {
|
|
1423
1429
|
newErrors[col.field] = `${col.displayName} is required`;
|
|
1424
1430
|
}
|
|
@@ -1458,7 +1464,7 @@ Note: ${result.note}`);
|
|
|
1458
1464
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { type: "button", variant: "ghost", size: "icon", onClick: onClose, className: "h-8 w-8", "aria-label": "Close", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react8.X, { className: "h-5 w-5" }) })
|
|
1459
1465
|
] }),
|
|
1460
1466
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("form", { onSubmit: handleSubmit, className: "flex flex-col flex-1 min-h-0", children: [
|
|
1461
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-4", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
1467
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-4", children: columns.filter((col) => !col.hideInForm).map((col) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
1462
1468
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label3, { className: "block text-sm font-medium mb-1", children: col.displayName }),
|
|
1463
1469
|
col.relationApi ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1464
1470
|
RelationAutocomplete,
|
|
@@ -1470,10 +1476,35 @@ Note: ${result.note}`);
|
|
|
1470
1476
|
valueField: col.relationValueField ?? "id",
|
|
1471
1477
|
placeholder: `Select ${col.displayName}`
|
|
1472
1478
|
}
|
|
1473
|
-
) : col.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1479
|
+
) : col.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1480
|
+
Textarea,
|
|
1481
|
+
{
|
|
1482
|
+
rows: typeof col.textareaRows === "number" ? col.textareaRows : 4,
|
|
1483
|
+
className: "min-h-[80px] font-mono text-sm",
|
|
1484
|
+
value: formData[col.field] ?? "",
|
|
1485
|
+
onChange: (e) => handleChange(e, col.field),
|
|
1486
|
+
placeholder: col.placeholder
|
|
1487
|
+
}
|
|
1488
|
+
) : col.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Select, { onValueChange: (value) => setFormData({ ...formData, [col.field]: value }), children: [
|
|
1474
1489
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectValue, { placeholder: formData[col.field] || "Select an option" }) }),
|
|
1475
1490
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectContent, { children: col.options?.map((option) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectItem, { value: option.value, children: option.label }, option.value)) })
|
|
1476
|
-
] }) : col.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Switch, { checked: formData[col.field] || false, onCheckedChange: () => handleToggleChange(col.field) }) : col.type === "date" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Input, { type: "date", value: formData[col.field] || "", onChange: (e) => handleChange(e, col.field) }) : col.type === "password" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Input, { type: "password", value: formData[col.field] || "", onChange: (e) => handleChange(e, col.field) }) : col.type === "number" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1491
|
+
] }) : col.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Switch, { checked: formData[col.field] || false, onCheckedChange: () => handleToggleChange(col.field) }) : col.type === "date" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Input, { type: "date", value: formData[col.field] || "", onChange: (e) => handleChange(e, col.field) }) : col.type === "password" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Input, { type: "password", value: formData[col.field] || "", onChange: (e) => handleChange(e, col.field) }) : col.type === "number" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1492
|
+
Input,
|
|
1493
|
+
{
|
|
1494
|
+
type: "number",
|
|
1495
|
+
placeholder: col.placeholder,
|
|
1496
|
+
value: formData[col.field] ?? "",
|
|
1497
|
+
onChange: (e) => handleChange(e, col.field)
|
|
1498
|
+
}
|
|
1499
|
+
) : col.type === "file" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FileUpload, { onUploadSuccess: (url) => handleFileUpload(col.field, url) }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1500
|
+
Input,
|
|
1501
|
+
{
|
|
1502
|
+
type: col.type || "text",
|
|
1503
|
+
placeholder: col.placeholder,
|
|
1504
|
+
value: formData[col.field] ?? "",
|
|
1505
|
+
onChange: (e) => handleChange(e, col.field)
|
|
1506
|
+
}
|
|
1507
|
+
),
|
|
1477
1508
|
errors[col.field] && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-red-500 text-sm mt-1", children: errors[col.field] })
|
|
1478
1509
|
] }, col.field)) }),
|
|
1479
1510
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2 p-4 border-t border-gray-200 shrink-0 bg-white", children: [
|
|
@@ -2076,6 +2107,10 @@ function AdminCRUD({
|
|
|
2076
2107
|
const hasLoadedRef = (0, import_react13.useRef)(false);
|
|
2077
2108
|
const isMobile = useIsMobile();
|
|
2078
2109
|
const showGroupColumn = !!manageUserGroups && roleOptions.length > 0;
|
|
2110
|
+
const listColumns = (0, import_react13.useMemo)(
|
|
2111
|
+
() => Array.isArray(columns) ? columns.filter((c) => !c.hideInTable) : [],
|
|
2112
|
+
[columns]
|
|
2113
|
+
);
|
|
2079
2114
|
(0, import_react13.useEffect)(() => {
|
|
2080
2115
|
const timeoutId = setTimeout(() => {
|
|
2081
2116
|
if (searchInput !== searchQuery) {
|
|
@@ -2526,7 +2561,7 @@ function AdminCRUD({
|
|
|
2526
2561
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ml-2", children: "Refreshing list..." })
|
|
2527
2562
|
] }),
|
|
2528
2563
|
isMobile ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex flex-col gap-2 min-w-0", children: data && data.length > 0 ? data.map((item, index) => {
|
|
2529
|
-
const displayCols =
|
|
2564
|
+
const displayCols = listColumns?.slice(0, 4) ?? [];
|
|
2530
2565
|
const primary = displayCols[0];
|
|
2531
2566
|
const primaryVal = primary ? getNestedValue(item, primary.field || primary.key) : null;
|
|
2532
2567
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
@@ -2600,7 +2635,7 @@ function AdminCRUD({
|
|
|
2600
2635
|
);
|
|
2601
2636
|
}) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "rounded-md border border-gray-200 p-6 text-center text-gray-500", children: "No data found" }) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "overflow-x-auto min-w-0 rounded-md border border-gray-200", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Table, { children: [
|
|
2602
2637
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(TableRow, { children: [
|
|
2603
|
-
|
|
2638
|
+
listColumns && listColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2604
2639
|
TableHead,
|
|
2605
2640
|
{
|
|
2606
2641
|
className: "cursor-pointer",
|
|
@@ -2622,7 +2657,7 @@ function AdminCRUD({
|
|
|
2622
2657
|
className: "cursor-pointer",
|
|
2623
2658
|
onClick: () => handleRowClick(item),
|
|
2624
2659
|
children: [
|
|
2625
|
-
|
|
2660
|
+
listColumns && listColumns.map((col, colIndex) => {
|
|
2626
2661
|
const fieldKey = col.field || col.key;
|
|
2627
2662
|
const value = getNestedValue(item, fieldKey);
|
|
2628
2663
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { children: formatCellValue(value, col) }, `${item.id}-${colIndex}-${fieldKey}`);
|
|
@@ -2706,7 +2741,7 @@ function AdminCRUD({
|
|
|
2706
2741
|
)) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2707
2742
|
TableCell,
|
|
2708
2743
|
{
|
|
2709
|
-
colSpan:
|
|
2744
|
+
colSpan: listColumns.length ? listColumns.length + 1 + (showGroupColumn ? 1 : 0) : 1,
|
|
2710
2745
|
className: "text-center py-8",
|
|
2711
2746
|
children: "No data found"
|
|
2712
2747
|
}
|
|
@@ -9270,6 +9305,10 @@ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
|
9270
9305
|
// src/admin/pages/PluginsPage.tsx
|
|
9271
9306
|
var import_sonner7 = require("sonner");
|
|
9272
9307
|
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
9308
|
+
function slugifyAgentKey(name) {
|
|
9309
|
+
const s = name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
9310
|
+
return s || "agent";
|
|
9311
|
+
}
|
|
9273
9312
|
function normalizeChatMode(raw) {
|
|
9274
9313
|
if (raw === "external" || raw === "llm") return raw;
|
|
9275
9314
|
return "whatsapp";
|
|
@@ -9429,6 +9468,25 @@ function PluginSettingsPanel({
|
|
|
9429
9468
|
const [chatMode, setChatMode] = (0, import_react41.useState)("whatsapp");
|
|
9430
9469
|
const [whatsappPhone, setWhatsappPhone] = (0, import_react41.useState)("");
|
|
9431
9470
|
const [externalChatSnippet, setExternalChatSnippet] = (0, import_react41.useState)("");
|
|
9471
|
+
const [attachedAgentSlug, setAttachedAgentSlug] = (0, import_react41.useState)("");
|
|
9472
|
+
const [llmAgents, setLlmAgents] = (0, import_react41.useState)([]);
|
|
9473
|
+
const [agentId, setAgentId] = (0, import_react41.useState)(null);
|
|
9474
|
+
const [agentName, setAgentName] = (0, import_react41.useState)("");
|
|
9475
|
+
const [agentSlug, setAgentSlug] = (0, import_react41.useState)("");
|
|
9476
|
+
const [agentSystem, setAgentSystem] = (0, import_react41.useState)("");
|
|
9477
|
+
const [agentModel, setAgentModel] = (0, import_react41.useState)("");
|
|
9478
|
+
const [agentTemp, setAgentTemp] = (0, import_react41.useState)("");
|
|
9479
|
+
const [agentMaxTokens, setAgentMaxTokens] = (0, import_react41.useState)("");
|
|
9480
|
+
const [agentValidationJson, setAgentValidationJson] = (0, import_react41.useState)("");
|
|
9481
|
+
const [agentLoading, setAgentLoading] = (0, import_react41.useState)(false);
|
|
9482
|
+
const [agentSaving, setAgentSaving] = (0, import_react41.useState)(false);
|
|
9483
|
+
const [kbCatalog, setKbCatalog] = (0, import_react41.useState)([]);
|
|
9484
|
+
const [attachedAgentKnowledge, setAttachedAgentKnowledge] = (0, import_react41.useState)([]);
|
|
9485
|
+
const [attachedKbLoading, setAttachedKbLoading] = (0, import_react41.useState)(false);
|
|
9486
|
+
const [attachExistingDocId, setAttachExistingDocId] = (0, import_react41.useState)("__none__");
|
|
9487
|
+
const [uploadingAttachedKbFile, setUploadingAttachedKbFile] = (0, import_react41.useState)(false);
|
|
9488
|
+
const [uploadingAttachedKbLink, setUploadingAttachedKbLink] = (0, import_react41.useState)(false);
|
|
9489
|
+
const [attachedKbInputKey, setAttachedKbInputKey] = (0, import_react41.useState)(0);
|
|
9432
9490
|
const [erpPipelineName, setErpPipelineName] = (0, import_react41.useState)("");
|
|
9433
9491
|
const [erpPipelineStageName, setErpPipelineStageName] = (0, import_react41.useState)("");
|
|
9434
9492
|
const [erpFormsCatalog, setErpFormsCatalog] = (0, import_react41.useState)([]);
|
|
@@ -9452,6 +9510,7 @@ function PluginSettingsPanel({
|
|
|
9452
9510
|
setIconImageUrl(data.iconImageUrl ?? "");
|
|
9453
9511
|
setIconBackgroundColor(data.iconBackgroundColor ?? "#6366f1");
|
|
9454
9512
|
setHeaderColor(data.headerColor ?? "#6366f1");
|
|
9513
|
+
setAttachedAgentSlug(data.attachedAgentSlug ?? "");
|
|
9455
9514
|
}
|
|
9456
9515
|
if (isErp) {
|
|
9457
9516
|
setErpPipelineName(data.pipelineName ?? data.pipelineId ?? "");
|
|
@@ -9506,6 +9565,116 @@ function PluginSettingsPanel({
|
|
|
9506
9565
|
setErpFormsCatalog(rows);
|
|
9507
9566
|
}).catch(() => setErpFormsCatalog([]));
|
|
9508
9567
|
}, [isErp, loading]);
|
|
9568
|
+
const fetchLlmAgents = (0, import_react41.useCallback)(async () => {
|
|
9569
|
+
const res = await fetch("/api/llm_agents?limit=100&sortField=name&sortOrder=asc");
|
|
9570
|
+
if (!res.ok) {
|
|
9571
|
+
setLlmAgents([]);
|
|
9572
|
+
return;
|
|
9573
|
+
}
|
|
9574
|
+
const j = await res.json();
|
|
9575
|
+
const list = (j.data ?? []).map((r) => ({
|
|
9576
|
+
id: r.id,
|
|
9577
|
+
name: String(r.name ?? ""),
|
|
9578
|
+
slug: String(r.slug ?? ""),
|
|
9579
|
+
enabled: r.enabled !== false
|
|
9580
|
+
}));
|
|
9581
|
+
setLlmAgents(list);
|
|
9582
|
+
const pick = list.find((a) => a.enabled) ?? list[0];
|
|
9583
|
+
const fullRow = (j.data ?? []).find((r) => r.id === pick?.id);
|
|
9584
|
+
if (pick && fullRow) {
|
|
9585
|
+
setAgentId(pick.id);
|
|
9586
|
+
setAgentName(pick.name);
|
|
9587
|
+
setAgentSlug(pick.slug);
|
|
9588
|
+
setAgentSystem(String(fullRow.systemInstruction ?? ""));
|
|
9589
|
+
setAgentModel(String(fullRow.model ?? ""));
|
|
9590
|
+
setAgentTemp(fullRow.temperature != null ? String(fullRow.temperature) : "");
|
|
9591
|
+
setAgentMaxTokens(fullRow.maxTokens != null ? String(fullRow.maxTokens) : "");
|
|
9592
|
+
setAgentValidationJson(String(fullRow.validationRules ?? ""));
|
|
9593
|
+
setAttachedAgentSlug(pick.slug);
|
|
9594
|
+
}
|
|
9595
|
+
}, []);
|
|
9596
|
+
const fetchKbCatalog = (0, import_react41.useCallback)(async () => {
|
|
9597
|
+
try {
|
|
9598
|
+
const res = await fetch("/api/knowledge_base_documents?limit=300&sortField=name&sortOrder=asc");
|
|
9599
|
+
if (!res.ok) {
|
|
9600
|
+
setKbCatalog([]);
|
|
9601
|
+
return;
|
|
9602
|
+
}
|
|
9603
|
+
const j = await res.json();
|
|
9604
|
+
setKbCatalog(
|
|
9605
|
+
(j.data ?? []).map((r) => ({
|
|
9606
|
+
id: typeof r.id === "number" ? r.id : Number(r.id),
|
|
9607
|
+
name: String(r.name ?? "")
|
|
9608
|
+
})).filter((r) => Number.isInteger(r.id) && r.id > 0)
|
|
9609
|
+
);
|
|
9610
|
+
} catch {
|
|
9611
|
+
setKbCatalog([]);
|
|
9612
|
+
}
|
|
9613
|
+
}, []);
|
|
9614
|
+
const fetchAttachedKnowledge = (0, import_react41.useCallback)(async (slug) => {
|
|
9615
|
+
if (!slug.trim()) {
|
|
9616
|
+
setAttachedAgentKnowledge([]);
|
|
9617
|
+
return;
|
|
9618
|
+
}
|
|
9619
|
+
setAttachedKbLoading(true);
|
|
9620
|
+
try {
|
|
9621
|
+
const res = await fetch(`/api/llm_agents/${encodeURIComponent(slug.trim())}/knowledge`);
|
|
9622
|
+
if (!res.ok) {
|
|
9623
|
+
setAttachedAgentKnowledge([]);
|
|
9624
|
+
return;
|
|
9625
|
+
}
|
|
9626
|
+
const j = await res.json();
|
|
9627
|
+
setAttachedAgentKnowledge(
|
|
9628
|
+
(j.documents ?? []).map((d) => ({
|
|
9629
|
+
id: typeof d.id === "number" ? d.id : Number(d.id),
|
|
9630
|
+
name: String(d.name ?? "")
|
|
9631
|
+
}))
|
|
9632
|
+
);
|
|
9633
|
+
} catch {
|
|
9634
|
+
setAttachedAgentKnowledge([]);
|
|
9635
|
+
} finally {
|
|
9636
|
+
setAttachedKbLoading(false);
|
|
9637
|
+
}
|
|
9638
|
+
}, []);
|
|
9639
|
+
(0, import_react41.useEffect)(() => {
|
|
9640
|
+
if (!isLlm || loading || chatMode !== "llm") return;
|
|
9641
|
+
setAgentLoading(true);
|
|
9642
|
+
void (async () => {
|
|
9643
|
+
try {
|
|
9644
|
+
await fetchLlmAgents();
|
|
9645
|
+
const listRes = await fetch("/api/llm_agents?limit=1");
|
|
9646
|
+
const listJ = listRes.ok ? await listRes.json() : { data: [] };
|
|
9647
|
+
if (!listJ.data?.length) {
|
|
9648
|
+
const defaultName = botName.trim() || "Assistant";
|
|
9649
|
+
const defaultSlug = slugifyAgentKey(defaultName);
|
|
9650
|
+
const createRes = await fetch("/api/llm_agents", {
|
|
9651
|
+
method: "POST",
|
|
9652
|
+
headers: { "Content-Type": "application/json" },
|
|
9653
|
+
body: JSON.stringify({ name: defaultName, slug: defaultSlug, systemInstruction: "", enabled: true })
|
|
9654
|
+
});
|
|
9655
|
+
if (createRes.ok) {
|
|
9656
|
+
await fetchLlmAgents();
|
|
9657
|
+
}
|
|
9658
|
+
}
|
|
9659
|
+
} finally {
|
|
9660
|
+
setAgentLoading(false);
|
|
9661
|
+
}
|
|
9662
|
+
})();
|
|
9663
|
+
}, [isLlm, loading, chatMode]);
|
|
9664
|
+
(0, import_react41.useEffect)(() => {
|
|
9665
|
+
if (!isLlm || loading || chatMode !== "llm") return;
|
|
9666
|
+
void fetchKbCatalog();
|
|
9667
|
+
}, [isLlm, loading, chatMode, fetchKbCatalog]);
|
|
9668
|
+
(0, import_react41.useEffect)(() => {
|
|
9669
|
+
if (!isLlm || loading || chatMode !== "llm" || !attachedAgentSlug.trim()) {
|
|
9670
|
+
setAttachedAgentKnowledge([]);
|
|
9671
|
+
return;
|
|
9672
|
+
}
|
|
9673
|
+
void fetchAttachedKnowledge(attachedAgentSlug);
|
|
9674
|
+
}, [isLlm, loading, chatMode, attachedAgentSlug, fetchAttachedKnowledge]);
|
|
9675
|
+
(0, import_react41.useEffect)(() => {
|
|
9676
|
+
setAttachExistingDocId("__none__");
|
|
9677
|
+
}, [attachedAgentSlug]);
|
|
9509
9678
|
const buildPayload = () => {
|
|
9510
9679
|
if (isErp) {
|
|
9511
9680
|
const sortedIds = [...new Set(erpOpportunityFormIds.filter((n) => Number.isInteger(n) && n > 0))].sort(
|
|
@@ -9540,6 +9709,7 @@ function PluginSettingsPanel({
|
|
|
9540
9709
|
payload.iconImageUrl = { value: iconImageUrl, type: "public" };
|
|
9541
9710
|
payload.iconBackgroundColor = { value: iconBackgroundColor, type: "public" };
|
|
9542
9711
|
payload.headerColor = { value: headerColor, type: "public" };
|
|
9712
|
+
payload.attachedAgentSlug = { value: attachedAgentSlug.trim(), type: "public" };
|
|
9543
9713
|
}
|
|
9544
9714
|
if (isEmail) {
|
|
9545
9715
|
payload.salesTeamEmails = { value: serializeEmailRecipients(salesTeamEmails), type: "public" };
|
|
@@ -9555,6 +9725,56 @@ function PluginSettingsPanel({
|
|
|
9555
9725
|
}
|
|
9556
9726
|
return payload;
|
|
9557
9727
|
};
|
|
9728
|
+
const handleSaveAgent = async () => {
|
|
9729
|
+
if (!agentId) {
|
|
9730
|
+
import_sonner7.toast.error("No agent to save");
|
|
9731
|
+
return;
|
|
9732
|
+
}
|
|
9733
|
+
const name = agentName.trim();
|
|
9734
|
+
if (!name) {
|
|
9735
|
+
import_sonner7.toast.error("Agent name is required");
|
|
9736
|
+
return;
|
|
9737
|
+
}
|
|
9738
|
+
const tempRaw = agentTemp.trim();
|
|
9739
|
+
const maxRaw = agentMaxTokens.trim();
|
|
9740
|
+
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
9741
|
+
const maxTokens = maxRaw === "" ? null : parseInt(maxRaw, 10);
|
|
9742
|
+
if (tempRaw !== "" && !Number.isFinite(temperature)) {
|
|
9743
|
+
import_sonner7.toast.error("Temperature must be a number");
|
|
9744
|
+
return;
|
|
9745
|
+
}
|
|
9746
|
+
if (maxRaw !== "" && (!Number.isFinite(maxTokens) || maxTokens < 1)) {
|
|
9747
|
+
import_sonner7.toast.error("Max tokens must be a positive integer");
|
|
9748
|
+
return;
|
|
9749
|
+
}
|
|
9750
|
+
setAgentSaving(true);
|
|
9751
|
+
try {
|
|
9752
|
+
const res = await fetch(`/api/llm_agents/${agentId}`, {
|
|
9753
|
+
method: "PUT",
|
|
9754
|
+
headers: { "Content-Type": "application/json" },
|
|
9755
|
+
body: JSON.stringify({
|
|
9756
|
+
name,
|
|
9757
|
+
systemInstruction: agentSystem.trim(),
|
|
9758
|
+
model: agentModel.trim() || null,
|
|
9759
|
+
temperature,
|
|
9760
|
+
maxTokens,
|
|
9761
|
+
validationRules: agentValidationJson.trim() || null,
|
|
9762
|
+
enabled: true
|
|
9763
|
+
})
|
|
9764
|
+
});
|
|
9765
|
+
if (!res.ok) {
|
|
9766
|
+
const err = await res.json().catch(() => ({}));
|
|
9767
|
+
import_sonner7.toast.error(err.error || "Failed to update agent");
|
|
9768
|
+
return;
|
|
9769
|
+
}
|
|
9770
|
+
setAttachedAgentSlug(agentSlug);
|
|
9771
|
+
import_sonner7.toast.success("Agent saved");
|
|
9772
|
+
} catch {
|
|
9773
|
+
import_sonner7.toast.error("Failed to update agent");
|
|
9774
|
+
} finally {
|
|
9775
|
+
setAgentSaving(false);
|
|
9776
|
+
}
|
|
9777
|
+
};
|
|
9558
9778
|
const handleSave = async () => {
|
|
9559
9779
|
setSaving(true);
|
|
9560
9780
|
try {
|
|
@@ -9588,6 +9808,78 @@ function PluginSettingsPanel({
|
|
|
9588
9808
|
setSaving(false);
|
|
9589
9809
|
}
|
|
9590
9810
|
};
|
|
9811
|
+
const uploadKbFileToAttached = async (file) => {
|
|
9812
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9813
|
+
if (!slug) {
|
|
9814
|
+
import_sonner7.toast.error("No agent configured");
|
|
9815
|
+
return;
|
|
9816
|
+
}
|
|
9817
|
+
setUploadingAttachedKbFile(true);
|
|
9818
|
+
try {
|
|
9819
|
+
const fd = new FormData();
|
|
9820
|
+
const stem = file.name.replace(/\.[^/.]+$/, "").trim() || "Upload";
|
|
9821
|
+
fd.append("name", stem);
|
|
9822
|
+
fd.append("file", file);
|
|
9823
|
+
const r = await fetch(`/api/llm_agents/${encodeURIComponent(slug)}/knowledge`, { method: "POST", body: fd });
|
|
9824
|
+
if (!r.ok) {
|
|
9825
|
+
const err = await r.json().catch(() => ({}));
|
|
9826
|
+
import_sonner7.toast.error(err.error || "Upload failed");
|
|
9827
|
+
return;
|
|
9828
|
+
}
|
|
9829
|
+
import_sonner7.toast.success("Knowledge added and linked");
|
|
9830
|
+
setAttachedKbInputKey((k) => k + 1);
|
|
9831
|
+
await fetchAttachedKnowledge(slug);
|
|
9832
|
+
await fetchKbCatalog();
|
|
9833
|
+
} finally {
|
|
9834
|
+
setUploadingAttachedKbFile(false);
|
|
9835
|
+
}
|
|
9836
|
+
};
|
|
9837
|
+
const onAttachedKbFileChange = (e) => {
|
|
9838
|
+
const file = e.target.files?.[0];
|
|
9839
|
+
if (!file) return;
|
|
9840
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9841
|
+
if (!slug) {
|
|
9842
|
+
import_sonner7.toast.error("No agent configured");
|
|
9843
|
+
e.target.value = "";
|
|
9844
|
+
return;
|
|
9845
|
+
}
|
|
9846
|
+
void uploadKbFileToAttached(file);
|
|
9847
|
+
};
|
|
9848
|
+
const handleAttachExistingToAttached = async () => {
|
|
9849
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9850
|
+
if (!slug || attachExistingDocId === "__none__") return;
|
|
9851
|
+
const docId = parseInt(attachExistingDocId, 10);
|
|
9852
|
+
if (!Number.isFinite(docId)) return;
|
|
9853
|
+
setUploadingAttachedKbLink(true);
|
|
9854
|
+
try {
|
|
9855
|
+
const r = await fetch(`/api/llm_agents/${encodeURIComponent(slug)}/knowledge`, {
|
|
9856
|
+
method: "POST",
|
|
9857
|
+
headers: { "Content-Type": "application/json" },
|
|
9858
|
+
body: JSON.stringify({ documentId: docId })
|
|
9859
|
+
});
|
|
9860
|
+
if (!r.ok) {
|
|
9861
|
+
const err = await r.json().catch(() => ({}));
|
|
9862
|
+
import_sonner7.toast.error(err.error || "Attach failed");
|
|
9863
|
+
return;
|
|
9864
|
+
}
|
|
9865
|
+
import_sonner7.toast.success("Document attached");
|
|
9866
|
+
setAttachExistingDocId("__none__");
|
|
9867
|
+
await fetchAttachedKnowledge(slug);
|
|
9868
|
+
} finally {
|
|
9869
|
+
setUploadingAttachedKbLink(false);
|
|
9870
|
+
}
|
|
9871
|
+
};
|
|
9872
|
+
const handleUnlinkKbDoc = async (docId) => {
|
|
9873
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9874
|
+
if (!slug) return;
|
|
9875
|
+
const r = await fetch(`/api/llm_agents/${encodeURIComponent(slug)}/knowledge/${docId}`, { method: "DELETE" });
|
|
9876
|
+
if (!r.ok) {
|
|
9877
|
+
import_sonner7.toast.error("Could not remove link");
|
|
9878
|
+
return;
|
|
9879
|
+
}
|
|
9880
|
+
import_sonner7.toast.success("Removed from agent");
|
|
9881
|
+
await fetchAttachedKnowledge(slug);
|
|
9882
|
+
};
|
|
9591
9883
|
if (loading) return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Loading..." });
|
|
9592
9884
|
if (isErp) {
|
|
9593
9885
|
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-4", children: [
|
|
@@ -10029,8 +10321,206 @@ function PluginSettingsPanel({
|
|
|
10029
10321
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Only paste code from sources you trust." })
|
|
10030
10322
|
] }),
|
|
10031
10323
|
chatMode === "llm" && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10324
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50/80 dark:bg-gray-800/40 p-3 space-y-3", children: [
|
|
10325
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white", children: [
|
|
10326
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Bot, { className: "h-4 w-4" }),
|
|
10327
|
+
"Chat assistant agent"
|
|
10328
|
+
] }),
|
|
10329
|
+
agentLoading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
|
|
10330
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
10331
|
+
"Loading agent\u2026"
|
|
10332
|
+
] }) : !agentId ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "No agent found. Save settings to auto-create one." }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10333
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10334
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-name", className: "text-sm", children: "Name" }),
|
|
10335
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10336
|
+
Input,
|
|
10337
|
+
{
|
|
10338
|
+
id: "agent-name",
|
|
10339
|
+
value: agentName,
|
|
10340
|
+
onChange: (e) => setAgentName(e.target.value),
|
|
10341
|
+
placeholder: "e.g. Sales assistant",
|
|
10342
|
+
className: "h-8 text-sm"
|
|
10343
|
+
}
|
|
10344
|
+
)
|
|
10345
|
+
] }),
|
|
10346
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10347
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-slug", className: "text-sm", children: "Slug" }),
|
|
10348
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10349
|
+
Input,
|
|
10350
|
+
{
|
|
10351
|
+
id: "agent-slug",
|
|
10352
|
+
value: agentSlug,
|
|
10353
|
+
disabled: true,
|
|
10354
|
+
className: "h-8 text-sm font-mono bg-gray-100 dark:bg-gray-700"
|
|
10355
|
+
}
|
|
10356
|
+
),
|
|
10357
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-[11px] text-gray-500", children: "Auto-generated. Used in API routes." })
|
|
10358
|
+
] }),
|
|
10359
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10360
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-system", className: "text-sm", children: "System instruction" }),
|
|
10361
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10362
|
+
Textarea,
|
|
10363
|
+
{
|
|
10364
|
+
id: "agent-system",
|
|
10365
|
+
value: agentSystem,
|
|
10366
|
+
onChange: (e) => setAgentSystem(e.target.value),
|
|
10367
|
+
rows: 5,
|
|
10368
|
+
placeholder: "How the model should behave\u2026",
|
|
10369
|
+
className: "text-sm"
|
|
10370
|
+
}
|
|
10371
|
+
)
|
|
10372
|
+
] }),
|
|
10373
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
10374
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10375
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-model", className: "text-sm", children: "Model (optional)" }),
|
|
10376
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10377
|
+
Input,
|
|
10378
|
+
{
|
|
10379
|
+
id: "agent-model",
|
|
10380
|
+
value: agentModel,
|
|
10381
|
+
onChange: (e) => setAgentModel(e.target.value),
|
|
10382
|
+
placeholder: "Gateway model id",
|
|
10383
|
+
className: "h-8 text-sm font-mono"
|
|
10384
|
+
}
|
|
10385
|
+
)
|
|
10386
|
+
] }),
|
|
10387
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10388
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-temp", className: "text-sm", children: "Temperature" }),
|
|
10389
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10390
|
+
Input,
|
|
10391
|
+
{
|
|
10392
|
+
id: "agent-temp",
|
|
10393
|
+
value: agentTemp,
|
|
10394
|
+
onChange: (e) => setAgentTemp(e.target.value),
|
|
10395
|
+
placeholder: "e.g. 0.7",
|
|
10396
|
+
className: "h-8 text-sm"
|
|
10397
|
+
}
|
|
10398
|
+
)
|
|
10399
|
+
] })
|
|
10400
|
+
] }),
|
|
10401
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10402
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-max", className: "text-sm", children: "Max tokens" }),
|
|
10403
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10404
|
+
Input,
|
|
10405
|
+
{
|
|
10406
|
+
id: "agent-max",
|
|
10407
|
+
value: agentMaxTokens,
|
|
10408
|
+
onChange: (e) => setAgentMaxTokens(e.target.value.replace(/\D/g, "")),
|
|
10409
|
+
placeholder: "e.g. 1024",
|
|
10410
|
+
className: "h-8 text-sm"
|
|
10411
|
+
}
|
|
10412
|
+
)
|
|
10413
|
+
] }),
|
|
10414
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10415
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-validation", className: "text-sm", children: "Validation & output guardrails" }),
|
|
10416
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10417
|
+
Textarea,
|
|
10418
|
+
{
|
|
10419
|
+
id: "agent-validation",
|
|
10420
|
+
value: agentValidationJson,
|
|
10421
|
+
onChange: (e) => setAgentValidationJson(e.target.value),
|
|
10422
|
+
rows: 4,
|
|
10423
|
+
placeholder: 'Plain text or JSON: {"guardrails":"Never promise refunds.","maxUserChars":2000}',
|
|
10424
|
+
className: "text-xs font-mono"
|
|
10425
|
+
}
|
|
10426
|
+
)
|
|
10427
|
+
] }),
|
|
10428
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10429
|
+
Button,
|
|
10430
|
+
{
|
|
10431
|
+
type: "button",
|
|
10432
|
+
size: "sm",
|
|
10433
|
+
className: "gap-1",
|
|
10434
|
+
disabled: agentSaving,
|
|
10435
|
+
onClick: () => void handleSaveAgent(),
|
|
10436
|
+
children: agentSaving ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
10437
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
10438
|
+
"Saving\u2026"
|
|
10439
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10440
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Save, { className: "h-3.5 w-3.5" }),
|
|
10441
|
+
"Save agent"
|
|
10442
|
+
] })
|
|
10443
|
+
}
|
|
10444
|
+
)
|
|
10445
|
+
] }),
|
|
10446
|
+
agentId && agentSlug.trim() ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "rounded-md border border-dashed border-gray-300 dark:border-gray-600 bg-white/60 dark:bg-gray-900/30 p-3 space-y-3", children: [
|
|
10447
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800 dark:text-gray-200", children: [
|
|
10448
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.FileUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
10449
|
+
"Knowledge for this agent"
|
|
10450
|
+
] }),
|
|
10451
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Upload text (.txt, .md, .json) or PDF (.pdf), or link documents already in the knowledge base." }),
|
|
10452
|
+
attachedKbLoading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Loading linked documents\u2026" }) : attachedAgentKnowledge.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "No documents linked yet." }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("ul", { className: "max-h-32 space-y-1.5 overflow-y-auto", children: attachedAgentKnowledge.map((d) => /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("li", { className: "flex items-center justify-between gap-2 text-sm", children: [
|
|
10453
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "min-w-0 truncate", title: d.name, children: d.name }),
|
|
10454
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10455
|
+
Button,
|
|
10456
|
+
{
|
|
10457
|
+
type: "button",
|
|
10458
|
+
variant: "ghost",
|
|
10459
|
+
size: "sm",
|
|
10460
|
+
className: "h-7 shrink-0 text-xs text-red-600 hover:text-red-700 dark:text-red-400",
|
|
10461
|
+
onClick: () => void handleUnlinkKbDoc(d.id),
|
|
10462
|
+
children: "Remove"
|
|
10463
|
+
}
|
|
10464
|
+
)
|
|
10465
|
+
] }, d.id)) }),
|
|
10466
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "min-w-[180px] space-y-1", children: [
|
|
10467
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { className: "text-xs", children: "Upload file" }),
|
|
10468
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "relative", children: [
|
|
10469
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10470
|
+
Input,
|
|
10471
|
+
{
|
|
10472
|
+
type: "file",
|
|
10473
|
+
accept: ".txt,.md,.json,.pdf,text/plain,text/markdown,application/json,application/pdf",
|
|
10474
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink,
|
|
10475
|
+
className: "h-8 cursor-pointer text-xs disabled:opacity-60",
|
|
10476
|
+
onChange: onAttachedKbFileChange
|
|
10477
|
+
},
|
|
10478
|
+
attachedKbInputKey
|
|
10479
|
+
),
|
|
10480
|
+
uploadingAttachedKbFile ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
10481
|
+
"div",
|
|
10482
|
+
{
|
|
10483
|
+
className: "pointer-events-none absolute inset-0 flex items-center justify-center gap-2 rounded-md bg-background/85 text-xs font-medium text-gray-700 dark:text-gray-200",
|
|
10484
|
+
"aria-live": "polite",
|
|
10485
|
+
children: [
|
|
10486
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-4 w-4 shrink-0 animate-spin" }),
|
|
10487
|
+
"Saving & linking\u2026"
|
|
10488
|
+
]
|
|
10489
|
+
}
|
|
10490
|
+
) : null
|
|
10491
|
+
] }),
|
|
10492
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Pick a file to upload immediately (chunking, embeddings if configured, then link to this agent)." })
|
|
10493
|
+
] }),
|
|
10494
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex flex-wrap items-end gap-2", children: [
|
|
10495
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "min-w-[200px] flex-1 space-y-1", children: [
|
|
10496
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { className: "text-xs", children: "Attach existing document" }),
|
|
10497
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Select, { value: attachExistingDocId, onValueChange: setAttachExistingDocId, children: [
|
|
10498
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SelectValue, { placeholder: "Choose a document" }) }),
|
|
10499
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(SelectContent, { children: [
|
|
10500
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SelectItem, { value: "__none__", children: "\u2014 Select \u2014" }),
|
|
10501
|
+
kbCatalog.filter((d) => !attachedAgentKnowledge.some((a) => a.id === d.id)).map((d) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SelectItem, { value: String(d.id), children: d.name }, d.id))
|
|
10502
|
+
] })
|
|
10503
|
+
] })
|
|
10504
|
+
] }),
|
|
10505
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10506
|
+
Button,
|
|
10507
|
+
{
|
|
10508
|
+
type: "button",
|
|
10509
|
+
size: "sm",
|
|
10510
|
+
className: "h-8",
|
|
10511
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink || attachExistingDocId === "__none__",
|
|
10512
|
+
onClick: () => void handleAttachExistingToAttached(),
|
|
10513
|
+
children: uploadingAttachedKbLink ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
10514
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
10515
|
+
"Linking\u2026"
|
|
10516
|
+
] }) : "Attach"
|
|
10517
|
+
}
|
|
10518
|
+
)
|
|
10519
|
+
] })
|
|
10520
|
+
] }) : null
|
|
10521
|
+
] }),
|
|
10032
10522
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10033
|
-
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "
|
|
10523
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
|
|
10034
10524
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10035
10525
|
Input,
|
|
10036
10526
|
{
|
|
@@ -12366,6 +12856,39 @@ var CRUD_CONFIGS = {
|
|
|
12366
12856
|
{ field: "createdAt", displayName: "Created", type: "date" }
|
|
12367
12857
|
],
|
|
12368
12858
|
addEditPageUrl: ""
|
|
12859
|
+
},
|
|
12860
|
+
llm_agents: {
|
|
12861
|
+
title: "LLM agents",
|
|
12862
|
+
apiEndpoint: "/api/llm_agents",
|
|
12863
|
+
defaultSortField: "name",
|
|
12864
|
+
defaultSortOrder: "asc",
|
|
12865
|
+
columns: [
|
|
12866
|
+
{ field: "name", displayName: "Name" },
|
|
12867
|
+
{ field: "slug", displayName: "Slug" },
|
|
12868
|
+
{
|
|
12869
|
+
field: "systemInstruction",
|
|
12870
|
+
displayName: "System instruction",
|
|
12871
|
+
type: "textarea",
|
|
12872
|
+
hideInTable: true,
|
|
12873
|
+
textareaRows: 10,
|
|
12874
|
+
placeholder: "How the model should behave for this agent (sent as system prompt to the LLM)."
|
|
12875
|
+
},
|
|
12876
|
+
{ field: "model", displayName: "Model", placeholder: "Optional gateway model id" },
|
|
12877
|
+
{ field: "temperature", displayName: "Temperature", type: "number" },
|
|
12878
|
+
{ field: "maxTokens", displayName: "Max tokens", type: "number" },
|
|
12879
|
+
{
|
|
12880
|
+
field: "validationRules",
|
|
12881
|
+
displayName: "Validation & output guardrails",
|
|
12882
|
+
type: "textarea",
|
|
12883
|
+
hideInTable: true,
|
|
12884
|
+
textareaRows: 8,
|
|
12885
|
+
placeholder: "Plain text: rules appended to the system prompt. Or JSON: guardrails, maxUserChars, blockedSubstrings, etc."
|
|
12886
|
+
},
|
|
12887
|
+
{ field: "enabled", displayName: "Enabled", type: "boolean" },
|
|
12888
|
+
{ field: "createdAt", displayName: "Created", type: "date", hideInForm: true },
|
|
12889
|
+
{ field: "updatedAt", displayName: "Updated", type: "datetime", hideInForm: true }
|
|
12890
|
+
],
|
|
12891
|
+
addEditPageUrl: ""
|
|
12369
12892
|
}
|
|
12370
12893
|
};
|
|
12371
12894
|
function BlogEditorWrapper({ blogId }) {
|