@intranefr/superbackend 1.5.2 → 1.6.3
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/cookies.txt +6 -0
- package/cookies1.txt +6 -0
- package/cookies2.txt +6 -0
- package/cookies3.txt +6 -0
- package/cookies4.txt +5 -0
- package/cookies_old.txt +5 -0
- package/cookies_old_test.txt +6 -0
- package/cookies_super.txt +5 -0
- package/cookies_super_test.txt +6 -0
- package/cookies_test.txt +6 -0
- package/index.js +9 -0
- package/manage.js +745 -0
- package/package.json +6 -2
- package/plugins/core-waiting-list-migration/README.md +118 -0
- package/plugins/core-waiting-list-migration/index.js +438 -0
- package/plugins/global-settings-presets/index.js +20 -0
- package/plugins/hello-cli/index.js +17 -0
- package/plugins/ui-components-seeder/components/suiAlert.js +212 -0
- package/plugins/ui-components-seeder/components/suiToast.js +186 -0
- package/plugins/ui-components-seeder/index.js +31 -0
- package/public/js/admin-ui-components-preview.js +281 -0
- package/public/js/admin-ui-components.js +408 -0
- package/public/js/llm-provider-model-picker.js +193 -0
- package/public/test-iframe-fix.html +63 -0
- package/public/test-iframe.html +14 -0
- package/src/admin/endpointRegistry.js +68 -0
- package/src/controllers/admin.controller.js +36 -10
- package/src/controllers/adminAgents.controller.js +37 -0
- package/src/controllers/adminDataCleanup.controller.js +45 -0
- package/src/controllers/adminLlm.controller.js +19 -8
- package/src/controllers/adminLogin.controller.js +269 -0
- package/src/controllers/adminMarkdowns.controller.js +157 -0
- package/src/controllers/adminPlugins.controller.js +55 -0
- package/src/controllers/adminRegistry.controller.js +106 -0
- package/src/controllers/adminScripts.controller.js +138 -0
- package/src/controllers/adminStats.controller.js +4 -4
- package/src/controllers/adminTelegram.controller.js +72 -0
- package/src/controllers/markdowns.controller.js +42 -0
- package/src/controllers/registry.controller.js +32 -0
- package/src/controllers/waitingList.controller.js +52 -74
- package/src/helpers/mongooseHelper.js +6 -6
- package/src/helpers/scriptBase.js +2 -2
- package/src/middleware/auth.js +71 -1
- package/src/middleware/rbac.js +62 -0
- package/src/middleware.js +584 -176
- package/src/models/Agent.js +105 -0
- package/src/models/AgentMessage.js +82 -0
- package/src/models/GlobalSetting.js +11 -1
- package/src/models/Markdown.js +75 -0
- package/src/models/ScriptRun.js +8 -0
- package/src/models/TelegramBot.js +42 -0
- package/src/models/UiComponent.js +2 -0
- package/src/models/User.js +1 -1
- package/src/routes/admin.routes.js +3 -3
- package/src/routes/adminAgents.routes.js +13 -0
- package/src/routes/adminAssets.routes.js +11 -11
- package/src/routes/adminBlog.routes.js +2 -2
- package/src/routes/adminBlogAi.routes.js +2 -2
- package/src/routes/adminBlogAutomation.routes.js +2 -2
- package/src/routes/adminCache.routes.js +2 -2
- package/src/routes/adminConsoleManager.routes.js +2 -2
- package/src/routes/adminCrons.routes.js +2 -2
- package/src/routes/adminDataCleanup.routes.js +26 -0
- package/src/routes/adminDbBrowser.routes.js +2 -2
- package/src/routes/adminEjsVirtual.routes.js +2 -2
- package/src/routes/adminFeatureFlags.routes.js +6 -6
- package/src/routes/adminHeadless.routes.js +2 -2
- package/src/routes/adminHealthChecks.routes.js +2 -2
- package/src/routes/adminI18n.routes.js +2 -2
- package/src/routes/adminJsonConfigs.routes.js +8 -8
- package/src/routes/adminLlm.routes.js +8 -7
- package/src/routes/adminLogin.routes.js +23 -0
- package/src/routes/adminMarkdowns.routes.js +10 -0
- package/src/routes/adminMigration.routes.js +12 -12
- package/src/routes/adminPages.routes.js +2 -2
- package/src/routes/adminPlugins.routes.js +15 -0
- package/src/routes/adminProxy.routes.js +2 -2
- package/src/routes/adminRateLimits.routes.js +8 -8
- package/src/routes/adminRbac.routes.js +2 -2
- package/src/routes/adminRegistry.routes.js +24 -0
- package/src/routes/adminScripts.routes.js +6 -3
- package/src/routes/adminSeoConfig.routes.js +10 -10
- package/src/routes/adminTelegram.routes.js +14 -0
- package/src/routes/adminTerminals.routes.js +2 -2
- package/src/routes/adminUiComponents.routes.js +2 -2
- package/src/routes/adminUploadNamespaces.routes.js +7 -7
- package/src/routes/blogInternal.routes.js +2 -2
- package/src/routes/experiments.routes.js +2 -2
- package/src/routes/formsAdmin.routes.js +6 -6
- package/src/routes/globalSettings.routes.js +8 -8
- package/src/routes/internalExperiments.routes.js +2 -2
- package/src/routes/markdowns.routes.js +16 -0
- package/src/routes/notificationAdmin.routes.js +7 -7
- package/src/routes/orgAdmin.routes.js +16 -16
- package/src/routes/pages.routes.js +3 -3
- package/src/routes/registry.routes.js +11 -0
- package/src/routes/stripeAdmin.routes.js +12 -12
- package/src/routes/userAdmin.routes.js +7 -7
- package/src/routes/waitingListAdmin.routes.js +2 -2
- package/src/routes/workflows.routes.js +3 -3
- package/src/services/agent.service.js +546 -0
- package/src/services/agentHistory.service.js +345 -0
- package/src/services/agentTools.service.js +578 -0
- package/src/services/dataCleanup.service.js +286 -0
- package/src/services/jsonConfigs.service.js +284 -10
- package/src/services/llm.service.js +219 -6
- package/src/services/markdowns.service.js +522 -0
- package/src/services/plugins.service.js +348 -0
- package/src/services/registry.service.js +452 -0
- package/src/services/scriptsRunner.service.js +328 -37
- package/src/services/telegram.service.js +130 -0
- package/src/services/uiComponents.service.js +180 -0
- package/src/services/waitingListJson.service.js +401 -0
- package/src/utils/rbac/rightsRegistry.js +118 -0
- package/test-access.js +63 -0
- package/test-iframe-fix.html +63 -0
- package/test-iframe.html +14 -0
- package/views/admin-403.ejs +92 -0
- package/views/admin-agents.ejs +273 -0
- package/views/admin-coolify-deploy.ejs +8 -8
- package/views/admin-dashboard-home.ejs +52 -2
- package/views/admin-dashboard.ejs +179 -7
- package/views/admin-data-cleanup.ejs +357 -0
- package/views/admin-experiments.ejs +1 -1
- package/views/admin-login.ejs +286 -0
- package/views/admin-markdowns.ejs +905 -0
- package/views/admin-plugins-system.ejs +223 -0
- package/views/admin-scripts.ejs +221 -4
- package/views/admin-telegram.ejs +269 -0
- package/views/admin-ui-components.ejs +82 -402
- package/views/admin-users.ejs +207 -11
- package/views/partials/dashboard/nav-items.ejs +5 -0
- package/views/partials/llm-provider-model-picker.ejs +0 -161
- package/analysis-only.skill +0 -0
|
@@ -15,6 +15,22 @@ let cache = {
|
|
|
15
15
|
const CACHE_TTL = 60000;
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
const logger = {
|
|
19
|
+
log: (...args) => {
|
|
20
|
+
if (process.env.DEBUG_LLM === 'true' && process.env.NODE_ENV !== 'test') {
|
|
21
|
+
if (!process.env.TUI_MODE) console.log(...args);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
warn: (...args) => {
|
|
25
|
+
if (process.env.DEBUG_LLM === 'true' && process.env.NODE_ENV !== 'test') {
|
|
26
|
+
if (!process.env.TUI_MODE) console.warn(...args);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
error: (...args) => {
|
|
30
|
+
console.error(...args);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
18
34
|
function computeCompletionURL(baseUrl) {
|
|
19
35
|
const trimmed = baseUrl.replace(/\/$/, "");
|
|
20
36
|
|
|
@@ -294,6 +310,8 @@ async function call(promptKey, variables = {}, runtimeOptions = {}) {
|
|
|
294
310
|
"stop",
|
|
295
311
|
"n",
|
|
296
312
|
"stream",
|
|
313
|
+
"tools",
|
|
314
|
+
"tool_choice",
|
|
297
315
|
];
|
|
298
316
|
|
|
299
317
|
for (const key of allowedOptions) {
|
|
@@ -313,7 +331,7 @@ async function call(promptKey, variables = {}, runtimeOptions = {}) {
|
|
|
313
331
|
`-H "Content-Type: application/json"`,
|
|
314
332
|
...Object.entries(provider.extraHeaders || {}).map(([k, v]) => `-H "${k}: ${v}"`),
|
|
315
333
|
].join(' ');
|
|
316
|
-
|
|
334
|
+
logger.log(`[llm.service] curl equivalent:\n curl -X POST ${url} ${curlHeaders} -d '${JSON.stringify(body)}'\n`);
|
|
317
335
|
|
|
318
336
|
response = await axios.post(url, body, {
|
|
319
337
|
headers: {
|
|
@@ -394,6 +412,40 @@ async function call(promptKey, variables = {}, runtimeOptions = {}) {
|
|
|
394
412
|
};
|
|
395
413
|
}
|
|
396
414
|
|
|
415
|
+
let modelMetadataCache = {
|
|
416
|
+
data: {},
|
|
417
|
+
ts: 0
|
|
418
|
+
};
|
|
419
|
+
const MODEL_CACHE_TTL = 3600000;
|
|
420
|
+
|
|
421
|
+
async function getModelContextLength(modelId, providerKey) {
|
|
422
|
+
if (modelMetadataCache.ts && Date.now() - modelMetadataCache.ts < MODEL_CACHE_TTL) {
|
|
423
|
+
if (modelMetadataCache.data[modelId]) return modelMetadataCache.data[modelId];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (providerKey !== 'openrouter') return 200000;
|
|
427
|
+
|
|
428
|
+
try {
|
|
429
|
+
const { providers } = await loadConfig();
|
|
430
|
+
const provider = providers[providerKey];
|
|
431
|
+
if (!provider || !provider.apiKey) return 200000;
|
|
432
|
+
|
|
433
|
+
const res = await axios.get(`https://openrouter.ai/api/v1/models/${modelId}`, {
|
|
434
|
+
headers: { 'Authorization': `Bearer ${provider.apiKey}` }
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
const contextLength = res?.data?.data?.context_length || 200000;
|
|
438
|
+
|
|
439
|
+
modelMetadataCache.data[modelId] = contextLength;
|
|
440
|
+
modelMetadataCache.ts = Date.now();
|
|
441
|
+
|
|
442
|
+
return contextLength;
|
|
443
|
+
} catch (e) {
|
|
444
|
+
logger.warn(`[llm.service] Failed to fetch context length for ${modelId}:`, e.message);
|
|
445
|
+
return 200000;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
397
449
|
async function callAdhoc(
|
|
398
450
|
{
|
|
399
451
|
providerKey,
|
|
@@ -409,9 +461,9 @@ async function callAdhoc(
|
|
|
409
461
|
const key = String(providerKey || "").trim();
|
|
410
462
|
let provider = providers[key];
|
|
411
463
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
464
|
+
logger.log('[llm.service] callAdhoc providerKey:', key);
|
|
465
|
+
logger.log('[llm.service] callAdhoc available provider keys:', Object.keys(providers));
|
|
466
|
+
logger.log('[llm.service] callAdhoc found provider:', !!provider, provider ? { enabled: provider.enabled, hasApiKey: !!provider.apiKey } : null);
|
|
415
467
|
|
|
416
468
|
// Apply runtime overrides for provider if possible
|
|
417
469
|
if (runtimeOptions.apiKey || runtimeOptions.baseUrl) {
|
|
@@ -456,6 +508,8 @@ async function callAdhoc(
|
|
|
456
508
|
"stop",
|
|
457
509
|
"n",
|
|
458
510
|
"stream",
|
|
511
|
+
"tools",
|
|
512
|
+
"tool_choice",
|
|
459
513
|
];
|
|
460
514
|
|
|
461
515
|
for (const key of allowedOptions) {
|
|
@@ -467,6 +521,7 @@ async function callAdhoc(
|
|
|
467
521
|
let response;
|
|
468
522
|
let text = "";
|
|
469
523
|
let usage = null;
|
|
524
|
+
let toolCalls = null;
|
|
470
525
|
|
|
471
526
|
try {
|
|
472
527
|
// Debug: log curl equivalent
|
|
@@ -475,7 +530,7 @@ async function callAdhoc(
|
|
|
475
530
|
`-H "Content-Type: application/json"`,
|
|
476
531
|
...Object.entries(provider.extraHeaders || {}).map(([k, v]) => `-H "${k}: ${v}"`),
|
|
477
532
|
].join(' ');
|
|
478
|
-
|
|
533
|
+
logger.log(`[llm.service] adhoc curl equivalent:\n curl -X POST ${url} ${curlHeaders} -d '${JSON.stringify(body)}'\n`);
|
|
479
534
|
|
|
480
535
|
response = await axios.post(url, body, {
|
|
481
536
|
headers: {
|
|
@@ -495,6 +550,10 @@ async function callAdhoc(
|
|
|
495
550
|
choice && choice.message && typeof choice.message.content === "string"
|
|
496
551
|
? choice.message.content
|
|
497
552
|
: "";
|
|
553
|
+
|
|
554
|
+
toolCalls = choice && choice.message && Array.isArray(choice.message.tool_calls)
|
|
555
|
+
? choice.message.tool_calls
|
|
556
|
+
: null;
|
|
498
557
|
|
|
499
558
|
const rawUsage = data.usage || null;
|
|
500
559
|
const normalized = normalizeUsage(rawUsage);
|
|
@@ -550,6 +609,7 @@ async function callAdhoc(
|
|
|
550
609
|
|
|
551
610
|
return {
|
|
552
611
|
content: text,
|
|
612
|
+
toolCalls,
|
|
553
613
|
model: resolvedModel,
|
|
554
614
|
providerKey: provider.key,
|
|
555
615
|
usage,
|
|
@@ -634,7 +694,7 @@ async function stream(promptKey, variables = {}, runtimeOptions = {}, { onToken
|
|
|
634
694
|
`-H "Content-Type: application/json"`,
|
|
635
695
|
...Object.entries(provider.extraHeaders || {}).map(([k, v]) => `-H "${k}: ${v}"`),
|
|
636
696
|
].join(' ');
|
|
637
|
-
|
|
697
|
+
logger.log(`[llm.service] streaming curl equivalent:\n curl -X POST ${url} ${curlHeaders} -d '${JSON.stringify(body)}'\n`);
|
|
638
698
|
|
|
639
699
|
const response = await axios.post(url, body, {
|
|
640
700
|
headers: {
|
|
@@ -741,9 +801,162 @@ async function stream(promptKey, variables = {}, runtimeOptions = {}, { onToken
|
|
|
741
801
|
}
|
|
742
802
|
}
|
|
743
803
|
|
|
804
|
+
async function streamAdhoc(
|
|
805
|
+
{
|
|
806
|
+
providerKey,
|
|
807
|
+
model,
|
|
808
|
+
messages,
|
|
809
|
+
promptKeyForAudit,
|
|
810
|
+
},
|
|
811
|
+
runtimeOptions = {},
|
|
812
|
+
{ onToken, onReasoning } = {}
|
|
813
|
+
) {
|
|
814
|
+
const { providers: rawProviders } = await loadConfig();
|
|
815
|
+
const providers = normalizeProviderConfig(rawProviders);
|
|
816
|
+
|
|
817
|
+
const key = String(providerKey || "").trim();
|
|
818
|
+
let provider = providers[key];
|
|
819
|
+
|
|
820
|
+
if (runtimeOptions.apiKey || runtimeOptions.baseUrl) {
|
|
821
|
+
provider = {
|
|
822
|
+
...(provider || { key: key || 'custom', enabled: true, baseUrl: 'https://openrouter.ai/api/v1' }),
|
|
823
|
+
...(runtimeOptions.apiKey ? { apiKey: runtimeOptions.apiKey } : {}),
|
|
824
|
+
...(runtimeOptions.baseUrl ? { baseUrl: runtimeOptions.baseUrl } : {}),
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (!provider || provider.enabled === false || !provider.apiKey) {
|
|
829
|
+
throw new Error("Provider not found, disabled, or missing apiKey");
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
const resolvedModel = String(model || runtimeOptions.model || provider.defaultModel || "google/gemini-2.5-flash-lite").trim();
|
|
833
|
+
const inputMessages = Array.isArray(messages) ? messages : [];
|
|
834
|
+
if (!inputMessages.length) throw new Error("messages is required");
|
|
835
|
+
|
|
836
|
+
const url = computeCompletionURL(provider.baseUrl);
|
|
837
|
+
const body = {
|
|
838
|
+
model: resolvedModel,
|
|
839
|
+
messages: inputMessages,
|
|
840
|
+
stream: true
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
const allowedOptions = ["temperature", "top_p", "max_tokens", "presence_penalty", "frequency_penalty", "stop", "n", "tools", "tool_choice"];
|
|
844
|
+
for (const key of allowedOptions) {
|
|
845
|
+
if (runtimeOptions[key] !== undefined) body[key] = runtimeOptions[key];
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
let fullText = "";
|
|
849
|
+
let fullReasoning = "";
|
|
850
|
+
let lastUsage = null;
|
|
851
|
+
let toolCalls = [];
|
|
852
|
+
|
|
853
|
+
const curlHeaders = [
|
|
854
|
+
`-H "Authorization: Bearer ${provider.apiKey}"`,
|
|
855
|
+
`-H "Content-Type: application/json"`,
|
|
856
|
+
...Object.entries(provider.extraHeaders || {}).map(([k, v]) => `-H "${k}: ${v}"`),
|
|
857
|
+
].join(' ');
|
|
858
|
+
logger.log(`[llm.service] streamAdhoc curl equivalent:\n curl -X POST ${url} ${curlHeaders} -d '${JSON.stringify(body)}'\n`);
|
|
859
|
+
|
|
860
|
+
const response = await axios.post(url, body, {
|
|
861
|
+
headers: {
|
|
862
|
+
Authorization: `Bearer ${provider.apiKey}`,
|
|
863
|
+
"Content-Type": "application/json",
|
|
864
|
+
...provider.extraHeaders,
|
|
865
|
+
},
|
|
866
|
+
timeout: provider.timeoutMs,
|
|
867
|
+
responseType: "stream",
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
await new Promise((resolve, reject) => {
|
|
871
|
+
let buffer = "";
|
|
872
|
+
response.data.on("data", (chunk) => {
|
|
873
|
+
buffer += chunk.toString("utf8");
|
|
874
|
+
const lines = buffer.split(/\r?\n/);
|
|
875
|
+
buffer = lines.pop() || "";
|
|
876
|
+
|
|
877
|
+
for (const line of lines) {
|
|
878
|
+
const trimmed = line.trim();
|
|
879
|
+
if (!trimmed || !trimmed.startsWith("data:")) continue;
|
|
880
|
+
const payload = trimmed.slice(5).trim();
|
|
881
|
+
if (payload === "[DONE]") continue;
|
|
882
|
+
|
|
883
|
+
try {
|
|
884
|
+
const parsed = JSON.parse(payload);
|
|
885
|
+
if (parsed.usage) lastUsage = parsed.usage;
|
|
886
|
+
|
|
887
|
+
const choice = parsed.choices?.[0];
|
|
888
|
+
if (!choice) {
|
|
889
|
+
const topReasoning = parsed.reasoning_content || parsed.reasoning || parsed.thinking;
|
|
890
|
+
if (topReasoning) {
|
|
891
|
+
fullReasoning += topReasoning;
|
|
892
|
+
if (onReasoning) onReasoning(topReasoning);
|
|
893
|
+
}
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
const delta = choice.delta || {};
|
|
898
|
+
|
|
899
|
+
if (delta.content) {
|
|
900
|
+
fullText += delta.content;
|
|
901
|
+
if (onToken) onToken(delta.content);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
const reasoning = delta.reasoning_content || delta.reasoning || delta.thinking || choice.reasoning_content || choice.reasoning;
|
|
905
|
+
if (reasoning) {
|
|
906
|
+
fullReasoning += reasoning;
|
|
907
|
+
if (onReasoning) onReasoning(reasoning);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
if (delta.tool_calls) {
|
|
911
|
+
for (const tc of delta.tool_calls) {
|
|
912
|
+
if (tc.index === undefined) tc.index = 0;
|
|
913
|
+
if (!toolCalls[tc.index]) {
|
|
914
|
+
toolCalls[tc.index] = {
|
|
915
|
+
id: tc.id,
|
|
916
|
+
type: 'function',
|
|
917
|
+
function: { name: '', arguments: '' }
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
if (tc.id) toolCalls[tc.index].id = tc.id;
|
|
921
|
+
if (tc.function?.name) toolCalls[tc.index].function.name += tc.function.name;
|
|
922
|
+
if (tc.function?.arguments) toolCalls[tc.index].function.arguments += tc.function.arguments;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
} catch (e) {}
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
response.data.on("end", () => resolve());
|
|
930
|
+
response.data.on("error", (err) => reject(err));
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
const finalUsage = normalizeUsage(lastUsage);
|
|
934
|
+
|
|
935
|
+
await logAuditEntry({
|
|
936
|
+
promptKey: String(promptKeyForAudit || "adhoc_stream"),
|
|
937
|
+
providerKey: provider.key,
|
|
938
|
+
model: resolvedModel,
|
|
939
|
+
variables: {},
|
|
940
|
+
requestOptions: runtimeOptions,
|
|
941
|
+
outcome: "success",
|
|
942
|
+
usage: finalUsage,
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
return {
|
|
946
|
+
content: fullText,
|
|
947
|
+
reasoning: fullReasoning,
|
|
948
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : null,
|
|
949
|
+
model: resolvedModel,
|
|
950
|
+
providerKey: provider.key,
|
|
951
|
+
usage: finalUsage
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
|
|
744
955
|
module.exports = {
|
|
745
956
|
call,
|
|
746
957
|
testPrompt,
|
|
747
958
|
callAdhoc,
|
|
959
|
+
streamAdhoc,
|
|
748
960
|
stream,
|
|
961
|
+
getModelContextLength
|
|
749
962
|
};
|