@infuro/cms-core 1.0.19 → 1.0.21
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 +661 -19
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.js +681 -22
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +3745 -101
- 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 +3732 -83
- package/dist/api.js.map +1 -1
- package/dist/{index-D2C1O9b4.d.cts → index-BGAh4fPQ.d.cts} +102 -3
- package/dist/{index-GMn7-9PX.d.ts → index-Cnwh7B3r.d.ts} +102 -3
- package/dist/index.cjs +2301 -787
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +124 -13
- package/dist/index.d.ts +124 -13
- package/dist/index.js +2154 -648
- 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 +9 -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.21" : "0.0.0";
|
|
405
405
|
|
|
406
406
|
// src/components/Admin/Sidebar.tsx
|
|
407
407
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -1404,7 +1404,9 @@ function CreateEditForm({ isOpen, onClose, apiEndpoint, columns, existingData })
|
|
|
1404
1404
|
if (existingData) {
|
|
1405
1405
|
setFormData(existingData);
|
|
1406
1406
|
} else {
|
|
1407
|
-
setFormData(
|
|
1407
|
+
setFormData(
|
|
1408
|
+
columns.filter((col) => !col.hideInForm).reduce((acc, col) => ({ ...acc, [col.field]: col.defaultValue || "" }), {})
|
|
1409
|
+
);
|
|
1408
1410
|
}
|
|
1409
1411
|
}, [existingData, columns]);
|
|
1410
1412
|
const handleChange = (e, field) => {
|
|
@@ -1418,7 +1420,7 @@ function CreateEditForm({ isOpen, onClose, apiEndpoint, columns, existingData })
|
|
|
1418
1420
|
};
|
|
1419
1421
|
const validateForm = () => {
|
|
1420
1422
|
let newErrors = {};
|
|
1421
|
-
columns.forEach((col) => {
|
|
1423
|
+
columns.filter((col) => !col.hideInForm).forEach((col) => {
|
|
1422
1424
|
if (col.validation?.required && !formData[col.field]) {
|
|
1423
1425
|
newErrors[col.field] = `${col.displayName} is required`;
|
|
1424
1426
|
}
|
|
@@ -1458,7 +1460,7 @@ Note: ${result.note}`);
|
|
|
1458
1460
|
/* @__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
1461
|
] }),
|
|
1460
1462
|
/* @__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: [
|
|
1463
|
+
/* @__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
1464
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label3, { className: "block text-sm font-medium mb-1", children: col.displayName }),
|
|
1463
1465
|
col.relationApi ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1464
1466
|
RelationAutocomplete,
|
|
@@ -1470,10 +1472,35 @@ Note: ${result.note}`);
|
|
|
1470
1472
|
valueField: col.relationValueField ?? "id",
|
|
1471
1473
|
placeholder: `Select ${col.displayName}`
|
|
1472
1474
|
}
|
|
1473
|
-
) : col.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1475
|
+
) : col.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1476
|
+
Textarea,
|
|
1477
|
+
{
|
|
1478
|
+
rows: typeof col.textareaRows === "number" ? col.textareaRows : 4,
|
|
1479
|
+
className: "min-h-[80px] font-mono text-sm",
|
|
1480
|
+
value: formData[col.field] ?? "",
|
|
1481
|
+
onChange: (e) => handleChange(e, col.field),
|
|
1482
|
+
placeholder: col.placeholder
|
|
1483
|
+
}
|
|
1484
|
+
) : col.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Select, { onValueChange: (value) => setFormData({ ...formData, [col.field]: value }), children: [
|
|
1474
1485
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectValue, { placeholder: formData[col.field] || "Select an option" }) }),
|
|
1475
1486
|
/* @__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)(
|
|
1487
|
+
] }) : 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)(
|
|
1488
|
+
Input,
|
|
1489
|
+
{
|
|
1490
|
+
type: "number",
|
|
1491
|
+
placeholder: col.placeholder,
|
|
1492
|
+
value: formData[col.field] ?? "",
|
|
1493
|
+
onChange: (e) => handleChange(e, col.field)
|
|
1494
|
+
}
|
|
1495
|
+
) : col.type === "file" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FileUpload, { onUploadSuccess: (url) => handleFileUpload(col.field, url) }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1496
|
+
Input,
|
|
1497
|
+
{
|
|
1498
|
+
type: col.type || "text",
|
|
1499
|
+
placeholder: col.placeholder,
|
|
1500
|
+
value: formData[col.field] ?? "",
|
|
1501
|
+
onChange: (e) => handleChange(e, col.field)
|
|
1502
|
+
}
|
|
1503
|
+
),
|
|
1477
1504
|
errors[col.field] && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-red-500 text-sm mt-1", children: errors[col.field] })
|
|
1478
1505
|
] }, col.field)) }),
|
|
1479
1506
|
/* @__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 +2103,10 @@ function AdminCRUD({
|
|
|
2076
2103
|
const hasLoadedRef = (0, import_react13.useRef)(false);
|
|
2077
2104
|
const isMobile = useIsMobile();
|
|
2078
2105
|
const showGroupColumn = !!manageUserGroups && roleOptions.length > 0;
|
|
2106
|
+
const listColumns = (0, import_react13.useMemo)(
|
|
2107
|
+
() => Array.isArray(columns) ? columns.filter((c) => !c.hideInTable) : [],
|
|
2108
|
+
[columns]
|
|
2109
|
+
);
|
|
2079
2110
|
(0, import_react13.useEffect)(() => {
|
|
2080
2111
|
const timeoutId = setTimeout(() => {
|
|
2081
2112
|
if (searchInput !== searchQuery) {
|
|
@@ -2526,7 +2557,7 @@ function AdminCRUD({
|
|
|
2526
2557
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ml-2", children: "Refreshing list..." })
|
|
2527
2558
|
] }),
|
|
2528
2559
|
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 =
|
|
2560
|
+
const displayCols = listColumns?.slice(0, 4) ?? [];
|
|
2530
2561
|
const primary = displayCols[0];
|
|
2531
2562
|
const primaryVal = primary ? getNestedValue(item, primary.field || primary.key) : null;
|
|
2532
2563
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
@@ -2600,7 +2631,7 @@ function AdminCRUD({
|
|
|
2600
2631
|
);
|
|
2601
2632
|
}) : /* @__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
2633
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(TableRow, { children: [
|
|
2603
|
-
|
|
2634
|
+
listColumns && listColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2604
2635
|
TableHead,
|
|
2605
2636
|
{
|
|
2606
2637
|
className: "cursor-pointer",
|
|
@@ -2622,7 +2653,7 @@ function AdminCRUD({
|
|
|
2622
2653
|
className: "cursor-pointer",
|
|
2623
2654
|
onClick: () => handleRowClick(item),
|
|
2624
2655
|
children: [
|
|
2625
|
-
|
|
2656
|
+
listColumns && listColumns.map((col, colIndex) => {
|
|
2626
2657
|
const fieldKey = col.field || col.key;
|
|
2627
2658
|
const value = getNestedValue(item, fieldKey);
|
|
2628
2659
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableCell, { children: formatCellValue(value, col) }, `${item.id}-${colIndex}-${fieldKey}`);
|
|
@@ -2706,7 +2737,7 @@ function AdminCRUD({
|
|
|
2706
2737
|
)) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2707
2738
|
TableCell,
|
|
2708
2739
|
{
|
|
2709
|
-
colSpan:
|
|
2740
|
+
colSpan: listColumns.length ? listColumns.length + 1 + (showGroupColumn ? 1 : 0) : 1,
|
|
2710
2741
|
className: "text-center py-8",
|
|
2711
2742
|
children: "No data found"
|
|
2712
2743
|
}
|
|
@@ -6492,7 +6523,7 @@ function DashboardPage() {
|
|
|
6492
6523
|
|
|
6493
6524
|
// src/admin/pages/AdminPageResolver.tsx
|
|
6494
6525
|
var import_react48 = require("react");
|
|
6495
|
-
var
|
|
6526
|
+
var import_navigation22 = require("next/navigation");
|
|
6496
6527
|
|
|
6497
6528
|
// src/admin/pages/SubmissionDetailPage.tsx
|
|
6498
6529
|
var import_react33 = require("react");
|
|
@@ -9221,6 +9252,7 @@ function PageBuilderPage({ pageId }) {
|
|
|
9221
9252
|
|
|
9222
9253
|
// src/admin/pages/PluginsPage.tsx
|
|
9223
9254
|
var import_react41 = require("react");
|
|
9255
|
+
var import_navigation18 = require("next/navigation");
|
|
9224
9256
|
var import_lucide_react32 = require("lucide-react");
|
|
9225
9257
|
|
|
9226
9258
|
// src/lib/email-recipients.ts
|
|
@@ -9270,6 +9302,10 @@ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
|
9270
9302
|
// src/admin/pages/PluginsPage.tsx
|
|
9271
9303
|
var import_sonner7 = require("sonner");
|
|
9272
9304
|
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
9305
|
+
function slugifyAgentKey(name) {
|
|
9306
|
+
const s = name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
9307
|
+
return s || "agent";
|
|
9308
|
+
}
|
|
9273
9309
|
function normalizeChatMode(raw) {
|
|
9274
9310
|
if (raw === "external" || raw === "llm") return raw;
|
|
9275
9311
|
return "whatsapp";
|
|
@@ -9429,6 +9465,26 @@ function PluginSettingsPanel({
|
|
|
9429
9465
|
const [chatMode, setChatMode] = (0, import_react41.useState)("whatsapp");
|
|
9430
9466
|
const [whatsappPhone, setWhatsappPhone] = (0, import_react41.useState)("");
|
|
9431
9467
|
const [externalChatSnippet, setExternalChatSnippet] = (0, import_react41.useState)("");
|
|
9468
|
+
const [attachedAgentSlug, setAttachedAgentSlug] = (0, import_react41.useState)("");
|
|
9469
|
+
const [llmAgents, setLlmAgents] = (0, import_react41.useState)([]);
|
|
9470
|
+
const [agentId, setAgentId] = (0, import_react41.useState)(null);
|
|
9471
|
+
const [agentName, setAgentName] = (0, import_react41.useState)("");
|
|
9472
|
+
const [agentSlug, setAgentSlug] = (0, import_react41.useState)("");
|
|
9473
|
+
const [agentSystem, setAgentSystem] = (0, import_react41.useState)("");
|
|
9474
|
+
const [agentModel, setAgentModel] = (0, import_react41.useState)("");
|
|
9475
|
+
const [agentTemp, setAgentTemp] = (0, import_react41.useState)("");
|
|
9476
|
+
const [agentMaxTokens, setAgentMaxTokens] = (0, import_react41.useState)("");
|
|
9477
|
+
const [agentValidationJson, setAgentValidationJson] = (0, import_react41.useState)("");
|
|
9478
|
+
const [agentLoading, setAgentLoading] = (0, import_react41.useState)(false);
|
|
9479
|
+
const [agentSaving, setAgentSaving] = (0, import_react41.useState)(false);
|
|
9480
|
+
const [agentProvisionError, setAgentProvisionError] = (0, import_react41.useState)(null);
|
|
9481
|
+
const [kbCatalog, setKbCatalog] = (0, import_react41.useState)([]);
|
|
9482
|
+
const [attachedAgentKnowledge, setAttachedAgentKnowledge] = (0, import_react41.useState)([]);
|
|
9483
|
+
const [attachedKbLoading, setAttachedKbLoading] = (0, import_react41.useState)(false);
|
|
9484
|
+
const [attachExistingDocId, setAttachExistingDocId] = (0, import_react41.useState)("__none__");
|
|
9485
|
+
const [uploadingAttachedKbFile, setUploadingAttachedKbFile] = (0, import_react41.useState)(false);
|
|
9486
|
+
const [uploadingAttachedKbLink, setUploadingAttachedKbLink] = (0, import_react41.useState)(false);
|
|
9487
|
+
const [attachedKbInputKey, setAttachedKbInputKey] = (0, import_react41.useState)(0);
|
|
9432
9488
|
const [erpPipelineName, setErpPipelineName] = (0, import_react41.useState)("");
|
|
9433
9489
|
const [erpPipelineStageName, setErpPipelineStageName] = (0, import_react41.useState)("");
|
|
9434
9490
|
const [erpFormsCatalog, setErpFormsCatalog] = (0, import_react41.useState)([]);
|
|
@@ -9452,6 +9508,7 @@ function PluginSettingsPanel({
|
|
|
9452
9508
|
setIconImageUrl(data.iconImageUrl ?? "");
|
|
9453
9509
|
setIconBackgroundColor(data.iconBackgroundColor ?? "#6366f1");
|
|
9454
9510
|
setHeaderColor(data.headerColor ?? "#6366f1");
|
|
9511
|
+
setAttachedAgentSlug(data.attachedAgentSlug ?? "");
|
|
9455
9512
|
}
|
|
9456
9513
|
if (isErp) {
|
|
9457
9514
|
setErpPipelineName(data.pipelineName ?? data.pipelineId ?? "");
|
|
@@ -9506,6 +9563,203 @@ function PluginSettingsPanel({
|
|
|
9506
9563
|
setErpFormsCatalog(rows);
|
|
9507
9564
|
}).catch(() => setErpFormsCatalog([]));
|
|
9508
9565
|
}, [isErp, loading]);
|
|
9566
|
+
const fetchLlmAgents = (0, import_react41.useCallback)(async () => {
|
|
9567
|
+
const res = await fetch("/api/llm_agents?limit=100&sortField=name&sortOrder=asc");
|
|
9568
|
+
if (!res.ok) {
|
|
9569
|
+
setLlmAgents([]);
|
|
9570
|
+
return;
|
|
9571
|
+
}
|
|
9572
|
+
const j = await res.json();
|
|
9573
|
+
const list = (j.data ?? []).map((r) => ({
|
|
9574
|
+
id: r.id,
|
|
9575
|
+
name: String(r.name ?? ""),
|
|
9576
|
+
slug: String(r.slug ?? ""),
|
|
9577
|
+
enabled: r.enabled !== false
|
|
9578
|
+
}));
|
|
9579
|
+
setLlmAgents(list);
|
|
9580
|
+
const pick = list.find((a) => a.enabled) ?? list[0];
|
|
9581
|
+
const fullRow = (j.data ?? []).find((r) => r.id === pick?.id);
|
|
9582
|
+
if (pick && fullRow) {
|
|
9583
|
+
setAgentId(pick.id);
|
|
9584
|
+
setAgentName(pick.name);
|
|
9585
|
+
setAgentSlug(pick.slug);
|
|
9586
|
+
setAgentSystem(String(fullRow.systemInstruction ?? ""));
|
|
9587
|
+
setAgentModel(String(fullRow.model ?? ""));
|
|
9588
|
+
setAgentTemp(fullRow.temperature != null ? String(fullRow.temperature) : "");
|
|
9589
|
+
setAgentMaxTokens(fullRow.maxTokens != null ? String(fullRow.maxTokens) : "");
|
|
9590
|
+
setAgentValidationJson(String(fullRow.validationRules ?? ""));
|
|
9591
|
+
setAttachedAgentSlug(pick.slug);
|
|
9592
|
+
}
|
|
9593
|
+
}, []);
|
|
9594
|
+
const fetchKbCatalog = (0, import_react41.useCallback)(async () => {
|
|
9595
|
+
try {
|
|
9596
|
+
const res = await fetch("/api/knowledge_base_documents?limit=300&sortField=name&sortOrder=asc");
|
|
9597
|
+
if (!res.ok) {
|
|
9598
|
+
setKbCatalog([]);
|
|
9599
|
+
return;
|
|
9600
|
+
}
|
|
9601
|
+
const j = await res.json();
|
|
9602
|
+
setKbCatalog(
|
|
9603
|
+
(j.data ?? []).map((r) => ({
|
|
9604
|
+
id: typeof r.id === "number" ? r.id : Number(r.id),
|
|
9605
|
+
name: String(r.name ?? "")
|
|
9606
|
+
})).filter((r) => Number.isInteger(r.id) && r.id > 0)
|
|
9607
|
+
);
|
|
9608
|
+
} catch {
|
|
9609
|
+
setKbCatalog([]);
|
|
9610
|
+
}
|
|
9611
|
+
}, []);
|
|
9612
|
+
const fetchAttachedKnowledge = (0, import_react41.useCallback)(async (slug) => {
|
|
9613
|
+
if (!slug.trim()) {
|
|
9614
|
+
setAttachedAgentKnowledge([]);
|
|
9615
|
+
return;
|
|
9616
|
+
}
|
|
9617
|
+
setAttachedKbLoading(true);
|
|
9618
|
+
try {
|
|
9619
|
+
const res = await fetch(`/api/llm_agents/${encodeURIComponent(slug.trim())}/knowledge`);
|
|
9620
|
+
if (!res.ok) {
|
|
9621
|
+
setAttachedAgentKnowledge([]);
|
|
9622
|
+
return;
|
|
9623
|
+
}
|
|
9624
|
+
const j = await res.json();
|
|
9625
|
+
setAttachedAgentKnowledge(
|
|
9626
|
+
(j.documents ?? []).map((d) => ({
|
|
9627
|
+
id: typeof d.id === "number" ? d.id : Number(d.id),
|
|
9628
|
+
name: String(d.name ?? "")
|
|
9629
|
+
}))
|
|
9630
|
+
);
|
|
9631
|
+
} catch {
|
|
9632
|
+
setAttachedAgentKnowledge([]);
|
|
9633
|
+
} finally {
|
|
9634
|
+
setAttachedKbLoading(false);
|
|
9635
|
+
}
|
|
9636
|
+
}, []);
|
|
9637
|
+
const bootstrapLlmAgentForPlugins = (0, import_react41.useCallback)(async () => {
|
|
9638
|
+
setAgentProvisionError(null);
|
|
9639
|
+
const listRes = await fetch("/api/llm_agents?limit=100&sortField=name&sortOrder=asc");
|
|
9640
|
+
if (!listRes.ok) {
|
|
9641
|
+
const errBody = await listRes.json().catch(() => ({}));
|
|
9642
|
+
const message = errBody.error ?? `Could not load agents (HTTP ${listRes.status}). Ensure your app uses the latest @infuro/cms-core and your admin user can read entity "llm_agents".`;
|
|
9643
|
+
setAgentProvisionError(message);
|
|
9644
|
+
await fetchLlmAgents();
|
|
9645
|
+
return { ok: false, message };
|
|
9646
|
+
}
|
|
9647
|
+
const listJ = await listRes.json();
|
|
9648
|
+
if (listJ.data?.length) {
|
|
9649
|
+
await fetchLlmAgents();
|
|
9650
|
+
return { ok: true };
|
|
9651
|
+
}
|
|
9652
|
+
const defaultName = botName.trim() || "Assistant";
|
|
9653
|
+
const defaultSlug = slugifyAgentKey(defaultName);
|
|
9654
|
+
const createRes = await fetch("/api/llm_agents", {
|
|
9655
|
+
method: "POST",
|
|
9656
|
+
headers: { "Content-Type": "application/json" },
|
|
9657
|
+
body: JSON.stringify({ name: defaultName, slug: defaultSlug, systemInstruction: "", enabled: true })
|
|
9658
|
+
});
|
|
9659
|
+
if (!createRes.ok) {
|
|
9660
|
+
const errBody = await createRes.json().catch(() => ({}));
|
|
9661
|
+
const message = errBody.error ?? `Could not create default agent (HTTP ${createRes.status}). Check create permission for "llm_agents".`;
|
|
9662
|
+
setAgentProvisionError(message);
|
|
9663
|
+
await fetchLlmAgents();
|
|
9664
|
+
return { ok: false, message };
|
|
9665
|
+
}
|
|
9666
|
+
await fetchLlmAgents();
|
|
9667
|
+
return { ok: true };
|
|
9668
|
+
}, [botName, fetchLlmAgents]);
|
|
9669
|
+
const handleRetryBootstrapAgent = async () => {
|
|
9670
|
+
setAgentLoading(true);
|
|
9671
|
+
try {
|
|
9672
|
+
const r = await bootstrapLlmAgentForPlugins();
|
|
9673
|
+
if (r.ok) {
|
|
9674
|
+
import_sonner7.toast.success("Assistant agent ready \u2014 you can upload knowledge files below.");
|
|
9675
|
+
} else {
|
|
9676
|
+
import_sonner7.toast.error(r.message);
|
|
9677
|
+
}
|
|
9678
|
+
} finally {
|
|
9679
|
+
setAgentLoading(false);
|
|
9680
|
+
}
|
|
9681
|
+
};
|
|
9682
|
+
const handleCreateAssistantFromForm = async () => {
|
|
9683
|
+
const name = agentName.trim() || botName.trim();
|
|
9684
|
+
if (!name) {
|
|
9685
|
+
import_sonner7.toast.error("Enter an assistant name");
|
|
9686
|
+
return;
|
|
9687
|
+
}
|
|
9688
|
+
const tempRaw = agentTemp.trim();
|
|
9689
|
+
const maxRaw = agentMaxTokens.trim();
|
|
9690
|
+
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
9691
|
+
const maxTokens = maxRaw === "" ? null : parseInt(maxRaw, 10);
|
|
9692
|
+
if (tempRaw !== "" && !Number.isFinite(temperature)) {
|
|
9693
|
+
import_sonner7.toast.error("Temperature must be a number");
|
|
9694
|
+
return;
|
|
9695
|
+
}
|
|
9696
|
+
if (maxRaw !== "" && (!Number.isFinite(maxTokens) || maxTokens < 1)) {
|
|
9697
|
+
import_sonner7.toast.error("Max tokens must be a positive integer");
|
|
9698
|
+
return;
|
|
9699
|
+
}
|
|
9700
|
+
const slug = slugifyAgentKey(name);
|
|
9701
|
+
setAgentSaving(true);
|
|
9702
|
+
try {
|
|
9703
|
+
const res = await fetch("/api/llm_agents", {
|
|
9704
|
+
method: "POST",
|
|
9705
|
+
headers: { "Content-Type": "application/json" },
|
|
9706
|
+
body: JSON.stringify({
|
|
9707
|
+
name,
|
|
9708
|
+
slug,
|
|
9709
|
+
systemInstruction: agentSystem.trim(),
|
|
9710
|
+
model: agentModel.trim() || null,
|
|
9711
|
+
temperature,
|
|
9712
|
+
maxTokens,
|
|
9713
|
+
validationRules: agentValidationJson.trim() || null,
|
|
9714
|
+
enabled: true
|
|
9715
|
+
})
|
|
9716
|
+
});
|
|
9717
|
+
if (!res.ok) {
|
|
9718
|
+
const err = await res.json().catch(() => ({}));
|
|
9719
|
+
import_sonner7.toast.error(err.error || "Failed to create assistant");
|
|
9720
|
+
return;
|
|
9721
|
+
}
|
|
9722
|
+
setAgentProvisionError(null);
|
|
9723
|
+
setAttachedAgentSlug(slug);
|
|
9724
|
+
await fetchLlmAgents();
|
|
9725
|
+
import_sonner7.toast.success("Assistant created \u2014 add knowledge files below.");
|
|
9726
|
+
} catch {
|
|
9727
|
+
import_sonner7.toast.error("Failed to create assistant");
|
|
9728
|
+
} finally {
|
|
9729
|
+
setAgentSaving(false);
|
|
9730
|
+
}
|
|
9731
|
+
};
|
|
9732
|
+
(0, import_react41.useEffect)(() => {
|
|
9733
|
+
if (!isLlm || loading || chatMode !== "llm") return;
|
|
9734
|
+
setAgentLoading(true);
|
|
9735
|
+
void (async () => {
|
|
9736
|
+
try {
|
|
9737
|
+
await bootstrapLlmAgentForPlugins();
|
|
9738
|
+
} finally {
|
|
9739
|
+
setAgentLoading(false);
|
|
9740
|
+
}
|
|
9741
|
+
})();
|
|
9742
|
+
}, [isLlm, loading, chatMode, bootstrapLlmAgentForPlugins]);
|
|
9743
|
+
(0, import_react41.useEffect)(() => {
|
|
9744
|
+
if (!isLlm || loading || chatMode !== "llm") return;
|
|
9745
|
+
void fetchKbCatalog();
|
|
9746
|
+
}, [isLlm, loading, chatMode, fetchKbCatalog]);
|
|
9747
|
+
(0, import_react41.useEffect)(() => {
|
|
9748
|
+
if (!isLlm || loading || chatMode !== "llm" || !attachedAgentSlug.trim()) {
|
|
9749
|
+
setAttachedAgentKnowledge([]);
|
|
9750
|
+
return;
|
|
9751
|
+
}
|
|
9752
|
+
void fetchAttachedKnowledge(attachedAgentSlug);
|
|
9753
|
+
}, [isLlm, loading, chatMode, attachedAgentSlug, fetchAttachedKnowledge]);
|
|
9754
|
+
(0, import_react41.useEffect)(() => {
|
|
9755
|
+
setAttachExistingDocId("__none__");
|
|
9756
|
+
}, [attachedAgentSlug]);
|
|
9757
|
+
(0, import_react41.useEffect)(() => {
|
|
9758
|
+
if (!isLlm || loading || chatMode !== "llm" || agentLoading || agentId) return;
|
|
9759
|
+
if (!agentName.trim() && botName.trim()) {
|
|
9760
|
+
setAgentName(botName.trim());
|
|
9761
|
+
}
|
|
9762
|
+
}, [isLlm, loading, chatMode, agentLoading, agentId, agentName, botName]);
|
|
9509
9763
|
const buildPayload = () => {
|
|
9510
9764
|
if (isErp) {
|
|
9511
9765
|
const sortedIds = [...new Set(erpOpportunityFormIds.filter((n) => Number.isInteger(n) && n > 0))].sort(
|
|
@@ -9540,6 +9794,7 @@ function PluginSettingsPanel({
|
|
|
9540
9794
|
payload.iconImageUrl = { value: iconImageUrl, type: "public" };
|
|
9541
9795
|
payload.iconBackgroundColor = { value: iconBackgroundColor, type: "public" };
|
|
9542
9796
|
payload.headerColor = { value: headerColor, type: "public" };
|
|
9797
|
+
payload.attachedAgentSlug = { value: attachedAgentSlug.trim(), type: "public" };
|
|
9543
9798
|
}
|
|
9544
9799
|
if (isEmail) {
|
|
9545
9800
|
payload.salesTeamEmails = { value: serializeEmailRecipients(salesTeamEmails), type: "public" };
|
|
@@ -9555,6 +9810,56 @@ function PluginSettingsPanel({
|
|
|
9555
9810
|
}
|
|
9556
9811
|
return payload;
|
|
9557
9812
|
};
|
|
9813
|
+
const handleSaveAgent = async () => {
|
|
9814
|
+
if (!agentId) {
|
|
9815
|
+
import_sonner7.toast.error("No agent to save");
|
|
9816
|
+
return;
|
|
9817
|
+
}
|
|
9818
|
+
const name = agentName.trim();
|
|
9819
|
+
if (!name) {
|
|
9820
|
+
import_sonner7.toast.error("Agent name is required");
|
|
9821
|
+
return;
|
|
9822
|
+
}
|
|
9823
|
+
const tempRaw = agentTemp.trim();
|
|
9824
|
+
const maxRaw = agentMaxTokens.trim();
|
|
9825
|
+
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
9826
|
+
const maxTokens = maxRaw === "" ? null : parseInt(maxRaw, 10);
|
|
9827
|
+
if (tempRaw !== "" && !Number.isFinite(temperature)) {
|
|
9828
|
+
import_sonner7.toast.error("Temperature must be a number");
|
|
9829
|
+
return;
|
|
9830
|
+
}
|
|
9831
|
+
if (maxRaw !== "" && (!Number.isFinite(maxTokens) || maxTokens < 1)) {
|
|
9832
|
+
import_sonner7.toast.error("Max tokens must be a positive integer");
|
|
9833
|
+
return;
|
|
9834
|
+
}
|
|
9835
|
+
setAgentSaving(true);
|
|
9836
|
+
try {
|
|
9837
|
+
const res = await fetch(`/api/llm_agents/${agentId}`, {
|
|
9838
|
+
method: "PUT",
|
|
9839
|
+
headers: { "Content-Type": "application/json" },
|
|
9840
|
+
body: JSON.stringify({
|
|
9841
|
+
name,
|
|
9842
|
+
systemInstruction: agentSystem.trim(),
|
|
9843
|
+
model: agentModel.trim() || null,
|
|
9844
|
+
temperature,
|
|
9845
|
+
maxTokens,
|
|
9846
|
+
validationRules: agentValidationJson.trim() || null,
|
|
9847
|
+
enabled: true
|
|
9848
|
+
})
|
|
9849
|
+
});
|
|
9850
|
+
if (!res.ok) {
|
|
9851
|
+
const err = await res.json().catch(() => ({}));
|
|
9852
|
+
import_sonner7.toast.error(err.error || "Failed to update agent");
|
|
9853
|
+
return;
|
|
9854
|
+
}
|
|
9855
|
+
setAttachedAgentSlug(agentSlug);
|
|
9856
|
+
import_sonner7.toast.success("Agent saved");
|
|
9857
|
+
} catch {
|
|
9858
|
+
import_sonner7.toast.error("Failed to update agent");
|
|
9859
|
+
} finally {
|
|
9860
|
+
setAgentSaving(false);
|
|
9861
|
+
}
|
|
9862
|
+
};
|
|
9558
9863
|
const handleSave = async () => {
|
|
9559
9864
|
setSaving(true);
|
|
9560
9865
|
try {
|
|
@@ -9588,6 +9893,96 @@ function PluginSettingsPanel({
|
|
|
9588
9893
|
setSaving(false);
|
|
9589
9894
|
}
|
|
9590
9895
|
};
|
|
9896
|
+
const uploadKbFileToAttached = async (file) => {
|
|
9897
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9898
|
+
if (!slug) {
|
|
9899
|
+
import_sonner7.toast.error("No agent configured");
|
|
9900
|
+
return;
|
|
9901
|
+
}
|
|
9902
|
+
setUploadingAttachedKbFile(true);
|
|
9903
|
+
try {
|
|
9904
|
+
const fd = new FormData();
|
|
9905
|
+
const stem = file.name.replace(/\.[^/.]+$/, "").trim() || "Upload";
|
|
9906
|
+
fd.append("name", stem);
|
|
9907
|
+
fd.append("file", file);
|
|
9908
|
+
const r = await fetch(`/api/llm_agents/${encodeURIComponent(slug)}/knowledge`, { method: "POST", body: fd });
|
|
9909
|
+
if (!r.ok) {
|
|
9910
|
+
const err = await r.json().catch(() => ({}));
|
|
9911
|
+
import_sonner7.toast.error(err.error || "Upload failed");
|
|
9912
|
+
return;
|
|
9913
|
+
}
|
|
9914
|
+
const ingest = await r.json().catch(() => ({}));
|
|
9915
|
+
if (ingest.warning) {
|
|
9916
|
+
import_sonner7.toast.warning(ingest.detail ? `${ingest.warning} (${ingest.detail})` : ingest.warning);
|
|
9917
|
+
} else if (ingest.embeddingAttempted && (ingest.embeddingsWritten ?? 0) === 0 && (ingest.chunkCount ?? 0) > 0) {
|
|
9918
|
+
import_sonner7.toast.warning(
|
|
9919
|
+
"Document saved but no embeddings were written. Set LLM_GATEWAY_URL + LLM_API_KEY, and ensure EMBEDDING_PROVIDER / EMBEDDING_MODEL match knowledge_base_chunks.embedding dimensions (see server logs)."
|
|
9920
|
+
);
|
|
9921
|
+
} else {
|
|
9922
|
+
import_sonner7.toast.success("Knowledge added and linked");
|
|
9923
|
+
}
|
|
9924
|
+
setAttachedKbInputKey((k) => k + 1);
|
|
9925
|
+
await fetchAttachedKnowledge(slug);
|
|
9926
|
+
await fetchKbCatalog();
|
|
9927
|
+
} finally {
|
|
9928
|
+
setUploadingAttachedKbFile(false);
|
|
9929
|
+
}
|
|
9930
|
+
};
|
|
9931
|
+
const onAttachedKbFileChange = (e) => {
|
|
9932
|
+
const file = e.target.files?.[0];
|
|
9933
|
+
if (!file) return;
|
|
9934
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9935
|
+
if (!slug) {
|
|
9936
|
+
import_sonner7.toast.error("No agent configured");
|
|
9937
|
+
e.target.value = "";
|
|
9938
|
+
return;
|
|
9939
|
+
}
|
|
9940
|
+
void uploadKbFileToAttached(file);
|
|
9941
|
+
};
|
|
9942
|
+
const handleAttachExistingToAttached = async () => {
|
|
9943
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9944
|
+
if (!slug || attachExistingDocId === "__none__") return;
|
|
9945
|
+
const docId = parseInt(attachExistingDocId, 10);
|
|
9946
|
+
if (!Number.isFinite(docId)) return;
|
|
9947
|
+
setUploadingAttachedKbLink(true);
|
|
9948
|
+
try {
|
|
9949
|
+
const r = await fetch(`/api/llm_agents/${encodeURIComponent(slug)}/knowledge`, {
|
|
9950
|
+
method: "POST",
|
|
9951
|
+
headers: { "Content-Type": "application/json" },
|
|
9952
|
+
body: JSON.stringify({ documentId: docId })
|
|
9953
|
+
});
|
|
9954
|
+
if (!r.ok) {
|
|
9955
|
+
const err = await r.json().catch(() => ({}));
|
|
9956
|
+
import_sonner7.toast.error(err.error || "Attach failed");
|
|
9957
|
+
return;
|
|
9958
|
+
}
|
|
9959
|
+
const ingest = await r.json().catch(() => ({}));
|
|
9960
|
+
if (ingest.warning) {
|
|
9961
|
+
import_sonner7.toast.warning(ingest.detail ? `${ingest.warning} (${ingest.detail})` : ingest.warning);
|
|
9962
|
+
} else if (ingest.embeddingAttempted && (ingest.embeddingsWritten ?? 0) === 0 && ((ingest.chunksQueuedForEmbedding ?? 0) > 0 || (ingest.chunkCount ?? 0) > 0)) {
|
|
9963
|
+
import_sonner7.toast.warning(
|
|
9964
|
+
"Document attached but no embeddings were written. Configure the LLM/embed gateway, then attach again to fill NULL embeddings."
|
|
9965
|
+
);
|
|
9966
|
+
} else {
|
|
9967
|
+
import_sonner7.toast.success("Document attached");
|
|
9968
|
+
}
|
|
9969
|
+
setAttachExistingDocId("__none__");
|
|
9970
|
+
await fetchAttachedKnowledge(slug);
|
|
9971
|
+
} finally {
|
|
9972
|
+
setUploadingAttachedKbLink(false);
|
|
9973
|
+
}
|
|
9974
|
+
};
|
|
9975
|
+
const handleUnlinkKbDoc = async (docId) => {
|
|
9976
|
+
const slug = agentSlug.trim() || attachedAgentSlug.trim();
|
|
9977
|
+
if (!slug) return;
|
|
9978
|
+
const r = await fetch(`/api/llm_agents/${encodeURIComponent(slug)}/knowledge/${docId}`, { method: "DELETE" });
|
|
9979
|
+
if (!r.ok) {
|
|
9980
|
+
import_sonner7.toast.error("Could not remove link");
|
|
9981
|
+
return;
|
|
9982
|
+
}
|
|
9983
|
+
import_sonner7.toast.success("Removed from agent");
|
|
9984
|
+
await fetchAttachedKnowledge(slug);
|
|
9985
|
+
};
|
|
9591
9986
|
if (loading) return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Loading..." });
|
|
9592
9987
|
if (isErp) {
|
|
9593
9988
|
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-4", children: [
|
|
@@ -10029,8 +10424,240 @@ function PluginSettingsPanel({
|
|
|
10029
10424
|
/* @__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
10425
|
] }),
|
|
10031
10426
|
chatMode === "llm" && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10427
|
+
/* @__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: [
|
|
10428
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10429
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white", children: [
|
|
10430
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Bot, { className: "h-4 w-4" }),
|
|
10431
|
+
"Chat assistant (single agent)"
|
|
10432
|
+
] }),
|
|
10433
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Configure one assistant for this site here. After it exists, attach knowledge files in the section below." })
|
|
10434
|
+
] }),
|
|
10435
|
+
agentLoading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
|
|
10436
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
10437
|
+
"Loading assistant\u2026"
|
|
10438
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10439
|
+
agentProvisionError ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "rounded border border-amber-200 bg-amber-50 p-2 text-xs text-amber-900 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-100", children: agentProvisionError }) : null,
|
|
10440
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10441
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-name", className: "text-sm", children: "Assistant name" }),
|
|
10442
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10443
|
+
Input,
|
|
10444
|
+
{
|
|
10445
|
+
id: "agent-name",
|
|
10446
|
+
value: agentName,
|
|
10447
|
+
onChange: (e) => setAgentName(e.target.value),
|
|
10448
|
+
placeholder: "e.g. JM Buddy",
|
|
10449
|
+
className: "h-8 text-sm"
|
|
10450
|
+
}
|
|
10451
|
+
)
|
|
10452
|
+
] }),
|
|
10453
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10454
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-slug", className: "text-sm", children: "Slug" }),
|
|
10455
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10456
|
+
Input,
|
|
10457
|
+
{
|
|
10458
|
+
id: "agent-slug",
|
|
10459
|
+
value: agentId ? agentSlug : slugifyAgentKey((agentName || botName).trim() || "assistant"),
|
|
10460
|
+
disabled: true,
|
|
10461
|
+
className: "h-8 text-sm font-mono bg-gray-100 dark:bg-gray-700"
|
|
10462
|
+
}
|
|
10463
|
+
),
|
|
10464
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-[11px] text-gray-500", children: "Derived from the name. Used in API routes." })
|
|
10465
|
+
] }),
|
|
10466
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10467
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-system", className: "text-sm", children: "System instruction" }),
|
|
10468
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10469
|
+
Textarea,
|
|
10470
|
+
{
|
|
10471
|
+
id: "agent-system",
|
|
10472
|
+
value: agentSystem,
|
|
10473
|
+
onChange: (e) => setAgentSystem(e.target.value),
|
|
10474
|
+
rows: 5,
|
|
10475
|
+
placeholder: "How the model should behave\u2026",
|
|
10476
|
+
className: "text-sm"
|
|
10477
|
+
}
|
|
10478
|
+
)
|
|
10479
|
+
] }),
|
|
10480
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
10481
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10482
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-model", className: "text-sm", children: "Model (optional)" }),
|
|
10483
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10484
|
+
Input,
|
|
10485
|
+
{
|
|
10486
|
+
id: "agent-model",
|
|
10487
|
+
value: agentModel,
|
|
10488
|
+
onChange: (e) => setAgentModel(e.target.value),
|
|
10489
|
+
placeholder: "Gateway model id",
|
|
10490
|
+
className: "h-8 text-sm font-mono"
|
|
10491
|
+
}
|
|
10492
|
+
)
|
|
10493
|
+
] }),
|
|
10494
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10495
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-temp", className: "text-sm", children: "Temperature" }),
|
|
10496
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10497
|
+
Input,
|
|
10498
|
+
{
|
|
10499
|
+
id: "agent-temp",
|
|
10500
|
+
value: agentTemp,
|
|
10501
|
+
onChange: (e) => setAgentTemp(e.target.value),
|
|
10502
|
+
placeholder: "e.g. 0.7",
|
|
10503
|
+
className: "h-8 text-sm"
|
|
10504
|
+
}
|
|
10505
|
+
)
|
|
10506
|
+
] })
|
|
10507
|
+
] }),
|
|
10508
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10509
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-max", className: "text-sm", children: "Max tokens" }),
|
|
10510
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10511
|
+
Input,
|
|
10512
|
+
{
|
|
10513
|
+
id: "agent-max",
|
|
10514
|
+
value: agentMaxTokens,
|
|
10515
|
+
onChange: (e) => setAgentMaxTokens(e.target.value.replace(/\D/g, "")),
|
|
10516
|
+
placeholder: "e.g. 1024",
|
|
10517
|
+
className: "h-8 text-sm"
|
|
10518
|
+
}
|
|
10519
|
+
)
|
|
10520
|
+
] }),
|
|
10521
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-1", children: [
|
|
10522
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: "agent-validation", className: "text-sm", children: "Validation & output guardrails" }),
|
|
10523
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10524
|
+
Textarea,
|
|
10525
|
+
{
|
|
10526
|
+
id: "agent-validation",
|
|
10527
|
+
value: agentValidationJson,
|
|
10528
|
+
onChange: (e) => setAgentValidationJson(e.target.value),
|
|
10529
|
+
rows: 4,
|
|
10530
|
+
placeholder: 'Plain text or JSON: {"guardrails":"Never promise refunds.","maxUserChars":2000}',
|
|
10531
|
+
className: "text-xs font-mono"
|
|
10532
|
+
}
|
|
10533
|
+
)
|
|
10534
|
+
] }),
|
|
10535
|
+
!agentId ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
10536
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10537
|
+
Button,
|
|
10538
|
+
{
|
|
10539
|
+
type: "button",
|
|
10540
|
+
size: "sm",
|
|
10541
|
+
className: "gap-1",
|
|
10542
|
+
disabled: agentSaving,
|
|
10543
|
+
onClick: () => void handleCreateAssistantFromForm(),
|
|
10544
|
+
children: agentSaving ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
10545
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
10546
|
+
"Creating\u2026"
|
|
10547
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10548
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Bot, { className: "h-3.5 w-3.5" }),
|
|
10549
|
+
"Create assistant"
|
|
10550
|
+
] })
|
|
10551
|
+
}
|
|
10552
|
+
),
|
|
10553
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10554
|
+
Button,
|
|
10555
|
+
{
|
|
10556
|
+
type: "button",
|
|
10557
|
+
size: "sm",
|
|
10558
|
+
variant: "secondary",
|
|
10559
|
+
className: "gap-1",
|
|
10560
|
+
disabled: agentSaving || agentLoading,
|
|
10561
|
+
onClick: () => void handleRetryBootstrapAgent(),
|
|
10562
|
+
children: "Retry auto-setup"
|
|
10563
|
+
}
|
|
10564
|
+
)
|
|
10565
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10566
|
+
Button,
|
|
10567
|
+
{
|
|
10568
|
+
type: "button",
|
|
10569
|
+
size: "sm",
|
|
10570
|
+
className: "gap-1",
|
|
10571
|
+
disabled: agentSaving,
|
|
10572
|
+
onClick: () => void handleSaveAgent(),
|
|
10573
|
+
children: agentSaving ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
10574
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
10575
|
+
"Saving\u2026"
|
|
10576
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10577
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Save, { className: "h-3.5 w-3.5" }),
|
|
10578
|
+
"Save assistant"
|
|
10579
|
+
] })
|
|
10580
|
+
}
|
|
10581
|
+
)
|
|
10582
|
+
] }),
|
|
10583
|
+
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: [
|
|
10584
|
+
/* @__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: [
|
|
10585
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.FileUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
10586
|
+
"Knowledge for this agent"
|
|
10587
|
+
] }),
|
|
10588
|
+
/* @__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." }),
|
|
10589
|
+
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: [
|
|
10590
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "min-w-0 truncate", title: d.name, children: d.name }),
|
|
10591
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10592
|
+
Button,
|
|
10593
|
+
{
|
|
10594
|
+
type: "button",
|
|
10595
|
+
variant: "ghost",
|
|
10596
|
+
size: "sm",
|
|
10597
|
+
className: "h-7 shrink-0 text-xs text-red-600 hover:text-red-700 dark:text-red-400",
|
|
10598
|
+
onClick: () => void handleUnlinkKbDoc(d.id),
|
|
10599
|
+
children: "Remove"
|
|
10600
|
+
}
|
|
10601
|
+
)
|
|
10602
|
+
] }, d.id)) }),
|
|
10603
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "min-w-[180px] space-y-1", children: [
|
|
10604
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { className: "text-xs", children: "Upload file" }),
|
|
10605
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "relative", children: [
|
|
10606
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10607
|
+
Input,
|
|
10608
|
+
{
|
|
10609
|
+
type: "file",
|
|
10610
|
+
accept: ".txt,.md,.json,.pdf,text/plain,text/markdown,application/json,application/pdf",
|
|
10611
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink,
|
|
10612
|
+
className: "h-8 cursor-pointer text-xs disabled:opacity-60",
|
|
10613
|
+
onChange: onAttachedKbFileChange
|
|
10614
|
+
},
|
|
10615
|
+
attachedKbInputKey
|
|
10616
|
+
),
|
|
10617
|
+
uploadingAttachedKbFile ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
10618
|
+
"div",
|
|
10619
|
+
{
|
|
10620
|
+
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",
|
|
10621
|
+
"aria-live": "polite",
|
|
10622
|
+
children: [
|
|
10623
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-4 w-4 shrink-0 animate-spin" }),
|
|
10624
|
+
"Saving & linking\u2026"
|
|
10625
|
+
]
|
|
10626
|
+
}
|
|
10627
|
+
) : null
|
|
10628
|
+
] }),
|
|
10629
|
+
/* @__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)." })
|
|
10630
|
+
] }),
|
|
10631
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex flex-wrap items-end gap-2", children: [
|
|
10632
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "min-w-[200px] flex-1 space-y-1", children: [
|
|
10633
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { className: "text-xs", children: "Attach existing document" }),
|
|
10634
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Select, { value: attachExistingDocId, onValueChange: setAttachExistingDocId, children: [
|
|
10635
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SelectValue, { placeholder: "Choose a document" }) }),
|
|
10636
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(SelectContent, { children: [
|
|
10637
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SelectItem, { value: "__none__", children: "\u2014 Select \u2014" }),
|
|
10638
|
+
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))
|
|
10639
|
+
] })
|
|
10640
|
+
] })
|
|
10641
|
+
] }),
|
|
10642
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10643
|
+
Button,
|
|
10644
|
+
{
|
|
10645
|
+
type: "button",
|
|
10646
|
+
size: "sm",
|
|
10647
|
+
className: "h-8",
|
|
10648
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink || attachExistingDocId === "__none__",
|
|
10649
|
+
onClick: () => void handleAttachExistingToAttached(),
|
|
10650
|
+
children: uploadingAttachedKbLink ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
10651
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react32.Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
10652
|
+
"Linking\u2026"
|
|
10653
|
+
] }) : "Attach"
|
|
10654
|
+
}
|
|
10655
|
+
)
|
|
10656
|
+
] })
|
|
10657
|
+
] }) : null
|
|
10658
|
+
] }),
|
|
10032
10659
|
/* @__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: "
|
|
10660
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
|
|
10034
10661
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10035
10662
|
Input,
|
|
10036
10663
|
{
|
|
@@ -10200,8 +10827,14 @@ function PluginListItem({
|
|
|
10200
10827
|
}
|
|
10201
10828
|
function PluginsPage() {
|
|
10202
10829
|
const { pluginDescriptors = [] } = (0, import_react41.useContext)(AdminConfigContext);
|
|
10830
|
+
const searchParams = (0, import_navigation18.useSearchParams)();
|
|
10203
10831
|
const [selectedName, setSelectedName] = (0, import_react41.useState)(null);
|
|
10204
10832
|
const [enabledMap, setEnabledMap] = (0, import_react41.useState)({});
|
|
10833
|
+
(0, import_react41.useEffect)(() => {
|
|
10834
|
+
if (searchParams.get("plugin") !== "llm") return;
|
|
10835
|
+
const llmDesc = pluginDescriptors.find((p) => p.settingsGroup === "llm");
|
|
10836
|
+
if (llmDesc) setSelectedName(llmDesc.name);
|
|
10837
|
+
}, [searchParams, pluginDescriptors]);
|
|
10205
10838
|
(0, import_react41.useEffect)(() => {
|
|
10206
10839
|
pluginDescriptors.forEach((p) => {
|
|
10207
10840
|
if (!p.settingsGroup) return;
|
|
@@ -10264,7 +10897,7 @@ function PluginsPage() {
|
|
|
10264
10897
|
|
|
10265
10898
|
// src/admin/pages/BrandEditPage.tsx
|
|
10266
10899
|
var import_react42 = require("react");
|
|
10267
|
-
var
|
|
10900
|
+
var import_navigation19 = require("next/navigation");
|
|
10268
10901
|
var import_lucide_react33 = require("lucide-react");
|
|
10269
10902
|
|
|
10270
10903
|
// src/components/Admin/SeoSection.tsx
|
|
@@ -10359,7 +10992,7 @@ async function fetchSeo(seoId) {
|
|
|
10359
10992
|
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
10360
10993
|
var isCreate = (id) => id === "create";
|
|
10361
10994
|
function BrandEditPage({ brandId }) {
|
|
10362
|
-
const router = (0,
|
|
10995
|
+
const router = (0, import_navigation19.useRouter)();
|
|
10363
10996
|
const create = isCreate(brandId);
|
|
10364
10997
|
const [loading, setLoading] = (0, import_react42.useState)(!create);
|
|
10365
10998
|
const [saving, setSaving] = (0, import_react42.useState)(false);
|
|
@@ -10562,7 +11195,7 @@ function BrandEditPage({ brandId }) {
|
|
|
10562
11195
|
|
|
10563
11196
|
// src/admin/pages/ProductEditPage.tsx
|
|
10564
11197
|
var import_react44 = require("react");
|
|
10565
|
-
var
|
|
11198
|
+
var import_navigation20 = require("next/navigation");
|
|
10566
11199
|
var import_lucide_react34 = require("lucide-react");
|
|
10567
11200
|
|
|
10568
11201
|
// src/components/Admin/AttributeFacetNameInput.tsx
|
|
@@ -10741,7 +11374,7 @@ function pickOtherMetadata(m) {
|
|
|
10741
11374
|
return rest;
|
|
10742
11375
|
}
|
|
10743
11376
|
function ProductEditPage({ productId }) {
|
|
10744
|
-
const router = (0,
|
|
11377
|
+
const router = (0, import_navigation20.useRouter)();
|
|
10745
11378
|
const create = isCreate2(productId);
|
|
10746
11379
|
const [loading, setLoading] = (0, import_react44.useState)(!create);
|
|
10747
11380
|
const [saving, setSaving] = (0, import_react44.useState)(false);
|
|
@@ -11429,7 +12062,7 @@ function ProductEditPage({ productId }) {
|
|
|
11429
12062
|
|
|
11430
12063
|
// src/admin/pages/CollectionEditPage.tsx
|
|
11431
12064
|
var import_react45 = require("react");
|
|
11432
|
-
var
|
|
12065
|
+
var import_navigation21 = require("next/navigation");
|
|
11433
12066
|
var import_lucide_react35 = require("lucide-react");
|
|
11434
12067
|
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
11435
12068
|
var isCreate3 = (id) => id === "create";
|
|
@@ -11439,7 +12072,7 @@ var sectionCls2 = "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4
|
|
|
11439
12072
|
var labelCls2 = "block text-xs font-medium text-gray-600 mb-1";
|
|
11440
12073
|
var inputCls2 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
|
|
11441
12074
|
function CollectionEditPage({ collectionId }) {
|
|
11442
|
-
const router = (0,
|
|
12075
|
+
const router = (0, import_navigation21.useRouter)();
|
|
11443
12076
|
const create = isCreate3(collectionId);
|
|
11444
12077
|
const [loading, setLoading] = (0, import_react45.useState)(!create);
|
|
11445
12078
|
const [saving, setSaving] = (0, import_react45.useState)(false);
|
|
@@ -12384,13 +13017,16 @@ function BlogEditorWrapper({ blogId }) {
|
|
|
12384
13017
|
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(BlogEditor, { existingBlog: blog });
|
|
12385
13018
|
}
|
|
12386
13019
|
function AdminPageResolver({ slug }) {
|
|
12387
|
-
const router = (0,
|
|
13020
|
+
const router = (0, import_navigation22.useRouter)();
|
|
12388
13021
|
const { customCrudConfigs, storeEnabled } = (0, import_react48.useContext)(AdminConfigContext);
|
|
12389
13022
|
const key = slug?.[0] || "dashboard";
|
|
12390
13023
|
(0, import_react48.useEffect)(() => {
|
|
12391
13024
|
if (key === "layout-settings") {
|
|
12392
13025
|
router.replace("/admin/settings?tab=navbar");
|
|
12393
13026
|
}
|
|
13027
|
+
if (key === "llm_agents") {
|
|
13028
|
+
router.replace("/admin/plugins?plugin=llm");
|
|
13029
|
+
}
|
|
12394
13030
|
}, [key, router]);
|
|
12395
13031
|
if (key === "layout-settings") {
|
|
12396
13032
|
return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex justify-center py-8", children: [
|
|
@@ -12398,6 +13034,12 @@ function AdminPageResolver({ slug }) {
|
|
|
12398
13034
|
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "ml-2", children: "Redirecting..." })
|
|
12399
13035
|
] });
|
|
12400
13036
|
}
|
|
13037
|
+
if (key === "llm_agents") {
|
|
13038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex justify-center py-8", children: [
|
|
13039
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600" }),
|
|
13040
|
+
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "ml-2", children: "Opening Plugins\u2026" })
|
|
13041
|
+
] });
|
|
13042
|
+
}
|
|
12401
13043
|
const Page = PAGE_MAP[key];
|
|
12402
13044
|
if (Page) {
|
|
12403
13045
|
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Page, {});
|