@exulu/backend 1.13.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -2
- package/dist/index.cjs +291 -263
- package/dist/index.d.cts +27 -15
- package/dist/index.d.ts +27 -15
- package/dist/index.js +282 -254
- package/package.json +3 -3
- package/types/enums/field-types.ts +1 -1
- package/types/enums/statistics.ts +10 -10
- package/types/models/agent.ts +0 -1
package/dist/index.cjs
CHANGED
|
@@ -121,15 +121,15 @@ var import_ai = require("ai");
|
|
|
121
121
|
|
|
122
122
|
// types/enums/statistics.ts
|
|
123
123
|
var STATISTICS_TYPE_ENUM = {
|
|
124
|
-
CONTEXT_RETRIEVE: "
|
|
125
|
-
SOURCE_UPDATE: "
|
|
126
|
-
EMBEDDER_UPSERT: "
|
|
127
|
-
EMBEDDER_GENERATE: "
|
|
128
|
-
EMBEDDER_DELETE: "
|
|
129
|
-
WORKFLOW_RUN: "
|
|
130
|
-
CONTEXT_UPSERT: "
|
|
131
|
-
TOOL_CALL: "
|
|
132
|
-
AGENT_RUN: "
|
|
124
|
+
CONTEXT_RETRIEVE: "CONTEXT_RETRIEVE",
|
|
125
|
+
SOURCE_UPDATE: "SOURCE_UPDATE",
|
|
126
|
+
EMBEDDER_UPSERT: "EMBEDDER_UPSERT",
|
|
127
|
+
EMBEDDER_GENERATE: "EMBEDDER_GENERATE",
|
|
128
|
+
EMBEDDER_DELETE: "EMBEDDER_DELETE",
|
|
129
|
+
WORKFLOW_RUN: "WORKFLOW_RUN",
|
|
130
|
+
CONTEXT_UPSERT: "CONTEXT_UPSERT",
|
|
131
|
+
TOOL_CALL: "TOOL_CALL",
|
|
132
|
+
AGENT_RUN: "AGENT_RUN"
|
|
133
133
|
};
|
|
134
134
|
|
|
135
135
|
// types/enums/eval-types.ts
|
|
@@ -304,7 +304,7 @@ var bullmqDecorator = async ({
|
|
|
304
304
|
|
|
305
305
|
// src/registry/utils/map-types.ts
|
|
306
306
|
var mapType = (t, type, name, defaultValue, unique) => {
|
|
307
|
-
if (type === "text") {
|
|
307
|
+
if (type === "text" || type === "enum") {
|
|
308
308
|
t.text(name);
|
|
309
309
|
if (unique) t.unique(name);
|
|
310
310
|
if (defaultValue) t.defaultTo(defaultValue);
|
|
@@ -445,6 +445,7 @@ var ExuluEvalUtils = {
|
|
|
445
445
|
|
|
446
446
|
// src/registry/classes.ts
|
|
447
447
|
var import_crypto_js = __toESM(require("crypto-js"), 1);
|
|
448
|
+
var import_express = require("express");
|
|
448
449
|
function sanitizeToolName(name) {
|
|
449
450
|
if (typeof name !== "string") return "";
|
|
450
451
|
let sanitized = name.replace(/[^a-zA-Z0-9_-]+/g, "_");
|
|
@@ -463,7 +464,7 @@ var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
|
463
464
|
console.log("[EXULU] Sanitized tools", sanitizedTools);
|
|
464
465
|
const askForConfirmation = {
|
|
465
466
|
description: "Ask the user for confirmation.",
|
|
466
|
-
|
|
467
|
+
inputSchema: import_zod2.z.object({
|
|
467
468
|
message: import_zod2.z.string().describe("The message to ask for confirmation.")
|
|
468
469
|
})
|
|
469
470
|
};
|
|
@@ -574,10 +575,12 @@ var ExuluAgent = class {
|
|
|
574
575
|
this.model = this.config?.model;
|
|
575
576
|
}
|
|
576
577
|
get providerName() {
|
|
577
|
-
|
|
578
|
+
const model = this.config?.model?.create({ apiKey: "" });
|
|
579
|
+
return typeof model === "string" ? model : model?.provider || "";
|
|
578
580
|
}
|
|
579
581
|
get modelName() {
|
|
580
|
-
|
|
582
|
+
const model = this.config?.model?.create({ apiKey: "" });
|
|
583
|
+
return typeof model === "string" ? model : model?.modelId || "";
|
|
581
584
|
}
|
|
582
585
|
// Exports the agent as a tool that can be used by another agent
|
|
583
586
|
// todo test this
|
|
@@ -603,28 +606,44 @@ var ExuluAgent = class {
|
|
|
603
606
|
}
|
|
604
607
|
});
|
|
605
608
|
};
|
|
606
|
-
generateSync = async ({
|
|
609
|
+
generateSync = async ({ prompt, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
607
610
|
if (!this.model) {
|
|
608
611
|
throw new Error("Model is required for streaming.");
|
|
609
612
|
}
|
|
610
613
|
if (!this.config) {
|
|
611
614
|
throw new Error("Config is required for generating.");
|
|
612
615
|
}
|
|
613
|
-
if (prompt &&
|
|
614
|
-
throw new Error("
|
|
616
|
+
if (prompt && message) {
|
|
617
|
+
throw new Error("Message and prompt cannot be provided at the same time.");
|
|
615
618
|
}
|
|
616
619
|
const model = this.model.create({
|
|
617
620
|
apiKey: providerApiKey
|
|
618
621
|
});
|
|
622
|
+
let messages = [];
|
|
623
|
+
if (message && session && user) {
|
|
624
|
+
const previousMessages = await getAgentMessages({
|
|
625
|
+
session,
|
|
626
|
+
user,
|
|
627
|
+
limit: 50,
|
|
628
|
+
page: 1
|
|
629
|
+
});
|
|
630
|
+
const previousMessagesContent = previousMessages.map((message2) => JSON.parse(message2.content));
|
|
631
|
+
messages = await (0, import_ai.validateUIMessages)({
|
|
632
|
+
// append the new message to the previous messages:
|
|
633
|
+
messages: [...previousMessagesContent, message]
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
console.log("[EXULU] Model provider key", providerApiKey);
|
|
637
|
+
console.log("[EXULU] Tool configs", toolConfigs);
|
|
619
638
|
const { text } = await (0, import_ai.generateText)({
|
|
620
639
|
model,
|
|
621
640
|
// Should be a LanguageModelV1
|
|
622
641
|
system: "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.",
|
|
623
|
-
messages,
|
|
642
|
+
messages: messages ? (0, import_ai.convertToModelMessages)(messages) : void 0,
|
|
624
643
|
prompt,
|
|
625
644
|
maxRetries: 2,
|
|
626
645
|
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
627
|
-
|
|
646
|
+
stopWhen: [(0, import_ai.stepCountIs)(5)]
|
|
628
647
|
});
|
|
629
648
|
if (statistics) {
|
|
630
649
|
await updateStatistic({
|
|
@@ -637,36 +656,61 @@ var ExuluAgent = class {
|
|
|
637
656
|
}
|
|
638
657
|
return text;
|
|
639
658
|
};
|
|
640
|
-
generateStream = ({
|
|
659
|
+
generateStream = async ({ express: express3, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
641
660
|
if (!this.model) {
|
|
642
661
|
throw new Error("Model is required for streaming.");
|
|
643
662
|
}
|
|
644
663
|
if (!this.config) {
|
|
645
664
|
throw new Error("Config is required for generating.");
|
|
646
665
|
}
|
|
647
|
-
if (
|
|
648
|
-
throw new Error("
|
|
666
|
+
if (!message) {
|
|
667
|
+
throw new Error("Message is required for streaming.");
|
|
649
668
|
}
|
|
650
669
|
const model = this.model.create({
|
|
651
670
|
apiKey: providerApiKey
|
|
652
671
|
});
|
|
672
|
+
let messages = [];
|
|
673
|
+
const previousMessages = await getAgentMessages({
|
|
674
|
+
session,
|
|
675
|
+
user,
|
|
676
|
+
limit: 50,
|
|
677
|
+
page: 1
|
|
678
|
+
});
|
|
679
|
+
const previousMessagesContent = previousMessages.map((message2) => JSON.parse(message2.content));
|
|
680
|
+
messages = await (0, import_ai.validateUIMessages)({
|
|
681
|
+
// append the new message to the previous messages:
|
|
682
|
+
messages: [...previousMessagesContent, message]
|
|
683
|
+
});
|
|
653
684
|
console.log("[EXULU] Model provider key", providerApiKey);
|
|
654
685
|
console.log("[EXULU] Tool configs", toolConfigs);
|
|
655
|
-
|
|
686
|
+
const result = (0, import_ai.streamText)({
|
|
656
687
|
model,
|
|
657
688
|
// Should be a LanguageModelV1
|
|
658
|
-
messages,
|
|
659
|
-
prompt,
|
|
689
|
+
messages: messages ? (0, import_ai.convertToModelMessages)(messages) : void 0,
|
|
660
690
|
system: "You are a helpful assistant. When you use a tool to answer a question do not explicitly comment on the result of the tool call unless the user has explicitly you to do something with the result.",
|
|
661
691
|
maxRetries: 2,
|
|
662
692
|
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
663
|
-
maxSteps: 5,
|
|
664
693
|
onError: (error) => console.error("[EXULU] chat stream error.", error),
|
|
665
|
-
|
|
694
|
+
stopWhen: [(0, import_ai.stepCountIs)(5)]
|
|
695
|
+
});
|
|
696
|
+
result.consumeStream();
|
|
697
|
+
result.pipeUIMessageStreamToResponse(express3.res, {
|
|
698
|
+
originalMessages: messages,
|
|
699
|
+
sendReasoning: true,
|
|
700
|
+
generateMessageId: (0, import_ai.createIdGenerator)({
|
|
701
|
+
prefix: "msg_",
|
|
702
|
+
size: 16
|
|
703
|
+
}),
|
|
704
|
+
onFinish: async ({ messages: messages2 }) => {
|
|
666
705
|
console.info(
|
|
667
706
|
"[EXULU] chat stream finished.",
|
|
668
|
-
|
|
707
|
+
messages2
|
|
669
708
|
);
|
|
709
|
+
await saveChat({
|
|
710
|
+
session,
|
|
711
|
+
user,
|
|
712
|
+
messages: messages2
|
|
713
|
+
});
|
|
670
714
|
if (statistics) {
|
|
671
715
|
await updateStatistic({
|
|
672
716
|
name: "count",
|
|
@@ -678,8 +722,26 @@ var ExuluAgent = class {
|
|
|
678
722
|
}
|
|
679
723
|
}
|
|
680
724
|
});
|
|
725
|
+
return;
|
|
681
726
|
};
|
|
682
727
|
};
|
|
728
|
+
var getAgentMessages = async ({ session, user, limit, page }) => {
|
|
729
|
+
const { db: db3 } = await postgresClient();
|
|
730
|
+
const messages = await db3.from("agent_messages").where({ session, user }).limit(limit).offset(page * limit);
|
|
731
|
+
return messages;
|
|
732
|
+
};
|
|
733
|
+
var saveChat = async ({ session, user, messages }) => {
|
|
734
|
+
const { db: db3 } = await postgresClient();
|
|
735
|
+
const promises2 = messages.map((message) => {
|
|
736
|
+
return db3.from("agent_messages").insert({
|
|
737
|
+
session,
|
|
738
|
+
user,
|
|
739
|
+
content: JSON.stringify(message),
|
|
740
|
+
title: message.role === "user" ? "User" : "Assistant"
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
await Promise.all(promises2);
|
|
744
|
+
};
|
|
683
745
|
var ExuluEmbedder = class {
|
|
684
746
|
id;
|
|
685
747
|
name;
|
|
@@ -930,7 +992,7 @@ var ExuluTool = class {
|
|
|
930
992
|
this.type = type;
|
|
931
993
|
this.tool = (0, import_ai.tool)({
|
|
932
994
|
description,
|
|
933
|
-
|
|
995
|
+
inputSchema: inputSchema || import_zod2.z.object({}),
|
|
934
996
|
execute: execute2
|
|
935
997
|
});
|
|
936
998
|
}
|
|
@@ -1419,22 +1481,27 @@ var ExuluSource = class {
|
|
|
1419
1481
|
var updateStatistic = async (statistic) => {
|
|
1420
1482
|
const currentDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1421
1483
|
const { db: db3 } = await postgresClient();
|
|
1422
|
-
const existing = await db3.from("
|
|
1484
|
+
const existing = await db3.from("tracking").where({
|
|
1485
|
+
...statistic.user ? { user: statistic.user } : {},
|
|
1486
|
+
...statistic.role ? { role: statistic.role } : {},
|
|
1423
1487
|
name: statistic.name,
|
|
1424
1488
|
label: statistic.label,
|
|
1425
1489
|
type: statistic.type,
|
|
1426
1490
|
createdAt: currentDate
|
|
1427
1491
|
}).first();
|
|
1492
|
+
console.log("!!! existing !!!", existing);
|
|
1428
1493
|
if (!existing) {
|
|
1429
|
-
await db3.from("
|
|
1494
|
+
await db3.from("tracking").insert({
|
|
1430
1495
|
name: statistic.name,
|
|
1431
1496
|
label: statistic.label,
|
|
1432
1497
|
type: statistic.type,
|
|
1433
1498
|
total: statistic.count ?? 1,
|
|
1434
|
-
createdAt: currentDate
|
|
1499
|
+
createdAt: currentDate,
|
|
1500
|
+
...statistic.user ? { user: statistic.user } : {},
|
|
1501
|
+
...statistic.role ? { role: statistic.role } : {}
|
|
1435
1502
|
});
|
|
1436
1503
|
} else {
|
|
1437
|
-
await db3.from("
|
|
1504
|
+
await db3.from("tracking").update({
|
|
1438
1505
|
total: db3.raw("total + ?", [statistic.count ?? 1])
|
|
1439
1506
|
}).where({
|
|
1440
1507
|
name: statistic.name,
|
|
@@ -1446,10 +1513,10 @@ var updateStatistic = async (statistic) => {
|
|
|
1446
1513
|
};
|
|
1447
1514
|
|
|
1448
1515
|
// src/registry/index.ts
|
|
1449
|
-
var
|
|
1516
|
+
var import_express7 = require("express");
|
|
1450
1517
|
|
|
1451
1518
|
// src/registry/routes.ts
|
|
1452
|
-
var
|
|
1519
|
+
var import_express3 = require("express");
|
|
1453
1520
|
|
|
1454
1521
|
// src/registry/rate-limiter.ts
|
|
1455
1522
|
var rateLimiter = async (key, windowSeconds, limit, points) => {
|
|
@@ -1773,25 +1840,25 @@ var requestValidators = {
|
|
|
1773
1840
|
message: "Missing body."
|
|
1774
1841
|
};
|
|
1775
1842
|
}
|
|
1776
|
-
if (!req.
|
|
1843
|
+
if (!req.headers["user"]) {
|
|
1777
1844
|
return {
|
|
1778
1845
|
error: true,
|
|
1779
1846
|
code: 400,
|
|
1780
|
-
message:
|
|
1847
|
+
message: 'Missing "user" property in headers.'
|
|
1781
1848
|
};
|
|
1782
1849
|
}
|
|
1783
|
-
if (!req.
|
|
1850
|
+
if (!req.headers["session"]) {
|
|
1784
1851
|
return {
|
|
1785
1852
|
error: true,
|
|
1786
1853
|
code: 400,
|
|
1787
|
-
message:
|
|
1854
|
+
message: 'Missing "session" property in headers.'
|
|
1788
1855
|
};
|
|
1789
1856
|
}
|
|
1790
|
-
if (!req.body.
|
|
1857
|
+
if (!req.body.message) {
|
|
1791
1858
|
return {
|
|
1792
1859
|
error: true,
|
|
1793
1860
|
code: 400,
|
|
1794
|
-
message: 'Missing "
|
|
1861
|
+
message: 'Missing "message" property in body.'
|
|
1795
1862
|
};
|
|
1796
1863
|
}
|
|
1797
1864
|
return {
|
|
@@ -1840,7 +1907,7 @@ var VectorMethodEnum = {
|
|
|
1840
1907
|
};
|
|
1841
1908
|
|
|
1842
1909
|
// src/registry/routes.ts
|
|
1843
|
-
var
|
|
1910
|
+
var import_express4 = __toESM(require("express"), 1);
|
|
1844
1911
|
var import_server3 = require("@apollo/server");
|
|
1845
1912
|
var Papa = __toESM(require("papaparse"), 1);
|
|
1846
1913
|
var import_cors = __toESM(require("cors"), 1);
|
|
@@ -1895,6 +1962,9 @@ var map = (field) => {
|
|
|
1895
1962
|
case "code":
|
|
1896
1963
|
type = "String";
|
|
1897
1964
|
break;
|
|
1965
|
+
case "enum":
|
|
1966
|
+
type = field.enumValues ? `${field.name}Enum` : "String";
|
|
1967
|
+
break;
|
|
1898
1968
|
case "number":
|
|
1899
1969
|
type = "Float";
|
|
1900
1970
|
break;
|
|
@@ -1913,6 +1983,16 @@ var map = (field) => {
|
|
|
1913
1983
|
return type;
|
|
1914
1984
|
};
|
|
1915
1985
|
function createTypeDefs(table) {
|
|
1986
|
+
const enumDefs = table.fields.filter((field) => field.type === "enum" && field.enumValues).map((field) => {
|
|
1987
|
+
const enumValues = field.enumValues.map((value) => {
|
|
1988
|
+
const sanitized = String(value).replace(/[^a-zA-Z0-9_]/g, "_").replace(/^[0-9]/, "_$&").toUpperCase();
|
|
1989
|
+
return ` ${sanitized}`;
|
|
1990
|
+
}).join("\n");
|
|
1991
|
+
return `
|
|
1992
|
+
enum ${field.name}Enum {
|
|
1993
|
+
${enumValues}
|
|
1994
|
+
}`;
|
|
1995
|
+
}).join("\n");
|
|
1916
1996
|
const fields = table.fields.map((field) => {
|
|
1917
1997
|
let type;
|
|
1918
1998
|
type = map(field);
|
|
@@ -1924,8 +2004,6 @@ function createTypeDefs(table) {
|
|
|
1924
2004
|
type ${table.name.singular} {
|
|
1925
2005
|
${fields.join("\n")}
|
|
1926
2006
|
${table.fields.find((field) => field.name === "id") ? "" : "id: ID!"}
|
|
1927
|
-
createdAt: Date!
|
|
1928
|
-
updatedAt: Date!
|
|
1929
2007
|
${rbacField}
|
|
1930
2008
|
}
|
|
1931
2009
|
`;
|
|
@@ -1936,39 +2014,62 @@ ${table.fields.map((f) => ` ${f.name}: ${map(f)}`).join("\n")}
|
|
|
1936
2014
|
${rbacInputField}
|
|
1937
2015
|
}
|
|
1938
2016
|
`;
|
|
1939
|
-
return typeDef + inputDef;
|
|
2017
|
+
return enumDefs + typeDef + inputDef;
|
|
1940
2018
|
}
|
|
1941
2019
|
function createFilterTypeDefs(table) {
|
|
1942
2020
|
const fieldFilters = table.fields.map((field) => {
|
|
1943
2021
|
let type;
|
|
1944
|
-
type
|
|
2022
|
+
if (field.type === "enum" && field.enumValues) {
|
|
2023
|
+
type = `${field.name}Enum`;
|
|
2024
|
+
} else {
|
|
2025
|
+
type = map(field);
|
|
2026
|
+
}
|
|
1945
2027
|
return `
|
|
1946
2028
|
${field.name}: FilterOperator${type}`;
|
|
1947
2029
|
});
|
|
1948
2030
|
const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
|
|
2031
|
+
const enumFilterOperators = table.fields.filter((field) => field.type === "enum" && field.enumValues).map((field) => {
|
|
2032
|
+
const enumTypeName = `${field.name}Enum`;
|
|
2033
|
+
return `
|
|
2034
|
+
input FilterOperator${enumTypeName} {
|
|
2035
|
+
eq: ${enumTypeName}
|
|
2036
|
+
ne: ${enumTypeName}
|
|
2037
|
+
in: [${enumTypeName}]
|
|
2038
|
+
and: [FilterOperator${enumTypeName}]
|
|
2039
|
+
or: [FilterOperator${enumTypeName}]
|
|
2040
|
+
}`;
|
|
2041
|
+
}).join("\n");
|
|
1949
2042
|
const operatorTypes = `
|
|
1950
2043
|
input FilterOperatorString {
|
|
1951
2044
|
eq: String
|
|
1952
2045
|
ne: String
|
|
1953
2046
|
in: [String]
|
|
1954
2047
|
contains: String
|
|
2048
|
+
and: [FilterOperatorString]
|
|
2049
|
+
or: [FilterOperatorString]
|
|
1955
2050
|
}
|
|
1956
2051
|
|
|
1957
2052
|
input FilterOperatorDate {
|
|
1958
2053
|
lte: Date
|
|
1959
2054
|
gte: Date
|
|
2055
|
+
and: [FilterOperatorDate]
|
|
2056
|
+
or: [FilterOperatorDate]
|
|
1960
2057
|
}
|
|
1961
2058
|
|
|
1962
2059
|
input FilterOperatorFloat {
|
|
1963
2060
|
eq: Float
|
|
1964
2061
|
ne: Float
|
|
1965
2062
|
in: [Float]
|
|
2063
|
+
and: [FilterOperatorFloat]
|
|
2064
|
+
or: [FilterOperatorFloat]
|
|
1966
2065
|
}
|
|
1967
2066
|
|
|
1968
2067
|
input FilterOperatorBoolean {
|
|
1969
2068
|
eq: Boolean
|
|
1970
2069
|
ne: Boolean
|
|
1971
2070
|
in: [Boolean]
|
|
2071
|
+
and: [FilterOperatorBoolean]
|
|
2072
|
+
or: [FilterOperatorBoolean]
|
|
1972
2073
|
}
|
|
1973
2074
|
|
|
1974
2075
|
input FilterOperatorJSON {
|
|
@@ -1987,6 +2088,8 @@ enum SortDirection {
|
|
|
1987
2088
|
DESC
|
|
1988
2089
|
}
|
|
1989
2090
|
|
|
2091
|
+
${enumFilterOperators}
|
|
2092
|
+
|
|
1990
2093
|
input Filter${tableNameSingularUpperCaseFirst} {
|
|
1991
2094
|
${fieldFilters.join("\n")}
|
|
1992
2095
|
}`;
|
|
@@ -2058,6 +2161,17 @@ function createMutations(table) {
|
|
|
2058
2161
|
const validateWriteAccess = async (id, context) => {
|
|
2059
2162
|
try {
|
|
2060
2163
|
const { db: db3, req, user } = context;
|
|
2164
|
+
if (user.super_admin === true) {
|
|
2165
|
+
return true;
|
|
2166
|
+
}
|
|
2167
|
+
if (!user.role || !(table.name.plural === "agents" && user.role.agents === "write") && !(table.name.plural === "workflow_templates" && user.role.workflows === "write") && !(table.name.plural === "variables" && user.role.variables === "write") && !(table.name.plural === "users" && user.role.users === "write")) {
|
|
2168
|
+
console.error("Access control error: no role found for current user or no access to entity type.");
|
|
2169
|
+
throw new Error("Access control error: no role found for current user or no access to entity type.");
|
|
2170
|
+
}
|
|
2171
|
+
const hasRBAC = table.RBAC === true;
|
|
2172
|
+
if (!hasRBAC) {
|
|
2173
|
+
return true;
|
|
2174
|
+
}
|
|
2061
2175
|
const record = await db3.from(tableNamePlural).select(["rights_mode", "created_by"]).where({ id }).first();
|
|
2062
2176
|
if (!record) {
|
|
2063
2177
|
throw new Error("Record not found");
|
|
@@ -2067,17 +2181,6 @@ function createMutations(table) {
|
|
|
2067
2181
|
throw new Error("You are not authorized to edit this record");
|
|
2068
2182
|
}
|
|
2069
2183
|
}
|
|
2070
|
-
const hasRBAC = table.RBAC === true;
|
|
2071
|
-
if (!hasRBAC) {
|
|
2072
|
-
return true;
|
|
2073
|
-
}
|
|
2074
|
-
if (user.super_admin === true) {
|
|
2075
|
-
return true;
|
|
2076
|
-
}
|
|
2077
|
-
if (!user.role || !(table.name.plural === "agents" && user.role.agents === "write") && !(table.name.plural === "workflow_templates" && user.role.workflows === "write") && !(table.name.plural === "variables" && user.role.variables === "write") && !(table.name.plural === "users" && user.role.users === "write")) {
|
|
2078
|
-
console.error("Access control error: no role found for current user or no access to entity type.");
|
|
2079
|
-
throw new Error("Access control error: no role found for current user or no access to entity type.");
|
|
2080
|
-
}
|
|
2081
2184
|
if (record.rights_mode === "public") {
|
|
2082
2185
|
return true;
|
|
2083
2186
|
}
|
|
@@ -2258,15 +2361,15 @@ function createMutations(table) {
|
|
|
2258
2361
|
var applyAccessControl = (table, user, query) => {
|
|
2259
2362
|
console.log("table", table);
|
|
2260
2363
|
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2261
|
-
|
|
2262
|
-
|
|
2364
|
+
if (!user.super_admin && table.name.plural === "jobs") {
|
|
2365
|
+
query = query.where("created_by", user.id);
|
|
2263
2366
|
return query;
|
|
2264
2367
|
}
|
|
2265
|
-
|
|
2368
|
+
const hasRBAC = table.RBAC === true;
|
|
2369
|
+
if (!hasRBAC) {
|
|
2266
2370
|
return query;
|
|
2267
2371
|
}
|
|
2268
|
-
if (table.name.plural
|
|
2269
|
-
query = query.where("created_by", user.id);
|
|
2372
|
+
if (table.name.plural !== "agent_sessions" && user.super_admin === true) {
|
|
2270
2373
|
return query;
|
|
2271
2374
|
}
|
|
2272
2375
|
if (!user.role || !(table.name.plural === "agents" && (user.role.agents === "read" || user.role.agents === "write")) && !(table.name.plural === "workflow_templates" && (user.role.workflows === "read" || user.role.workflows === "write")) && !(table.name.plural === "variables" && (user.role.variables === "read" || user.role.variables === "write")) && !(table.name.plural === "users" && (user.role.users === "read" || user.role.users === "write"))) {
|
|
@@ -2297,6 +2400,27 @@ var applyAccessControl = (table, user, query) => {
|
|
|
2297
2400
|
}
|
|
2298
2401
|
return query;
|
|
2299
2402
|
};
|
|
2403
|
+
var converOperatorToQuery = (query, fieldName, operators) => {
|
|
2404
|
+
if (operators.eq !== void 0) {
|
|
2405
|
+
query = query.where(fieldName, operators.eq);
|
|
2406
|
+
}
|
|
2407
|
+
if (operators.ne !== void 0) {
|
|
2408
|
+
query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
|
|
2409
|
+
}
|
|
2410
|
+
if (operators.in !== void 0) {
|
|
2411
|
+
query = query.whereIn(fieldName, operators.in);
|
|
2412
|
+
}
|
|
2413
|
+
if (operators.contains !== void 0) {
|
|
2414
|
+
query = query.where(fieldName, "like", `%${operators.contains}%`);
|
|
2415
|
+
}
|
|
2416
|
+
if (operators.lte !== void 0) {
|
|
2417
|
+
query = query.where(fieldName, "<=", operators.lte);
|
|
2418
|
+
}
|
|
2419
|
+
if (operators.gte !== void 0) {
|
|
2420
|
+
query = query.where(fieldName, ">=", operators.gte);
|
|
2421
|
+
}
|
|
2422
|
+
return query;
|
|
2423
|
+
};
|
|
2300
2424
|
function createQueries(table) {
|
|
2301
2425
|
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2302
2426
|
const tableNameSingular = table.name.singular.toLowerCase();
|
|
@@ -2304,18 +2428,19 @@ function createQueries(table) {
|
|
|
2304
2428
|
filters.forEach((filter) => {
|
|
2305
2429
|
Object.entries(filter).forEach(([fieldName, operators]) => {
|
|
2306
2430
|
if (operators) {
|
|
2307
|
-
if (operators.
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
}
|
|
2313
|
-
if (operators.in !== void 0) {
|
|
2314
|
-
query = query.whereIn(fieldName, operators.in);
|
|
2431
|
+
if (operators.and !== void 0) {
|
|
2432
|
+
console.log("operators.and", operators.and);
|
|
2433
|
+
operators.and.forEach((operator) => {
|
|
2434
|
+
query = converOperatorToQuery(query, fieldName, operator);
|
|
2435
|
+
});
|
|
2315
2436
|
}
|
|
2316
|
-
if (operators.
|
|
2317
|
-
|
|
2437
|
+
if (operators.or !== void 0) {
|
|
2438
|
+
operators.or.forEach((operator) => {
|
|
2439
|
+
query = converOperatorToQuery(query, fieldName, operator);
|
|
2440
|
+
});
|
|
2318
2441
|
}
|
|
2442
|
+
query = converOperatorToQuery(query, fieldName, operators);
|
|
2443
|
+
console.log("query", query);
|
|
2319
2444
|
}
|
|
2320
2445
|
});
|
|
2321
2446
|
});
|
|
@@ -2388,57 +2513,36 @@ function createQueries(table) {
|
|
|
2388
2513
|
query = applyFilters(query, filters);
|
|
2389
2514
|
query = applyAccessControl(table, context.user, query);
|
|
2390
2515
|
if (groupBy) {
|
|
2391
|
-
|
|
2516
|
+
query = query.select(groupBy).groupBy(groupBy);
|
|
2517
|
+
if (tableNamePlural === "tracking") {
|
|
2518
|
+
query = query.sum("total as count");
|
|
2519
|
+
} else {
|
|
2520
|
+
query = query.count("* as count");
|
|
2521
|
+
}
|
|
2522
|
+
const results = await query;
|
|
2523
|
+
console.log("!!! results !!!", results);
|
|
2392
2524
|
return results.map((r) => ({
|
|
2393
2525
|
group: r[groupBy],
|
|
2394
|
-
count: Number(r.count)
|
|
2526
|
+
count: r.count ? Number(r.count) : 0
|
|
2395
2527
|
}));
|
|
2396
2528
|
} else {
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
count
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
query = query.where("user", user);
|
|
2412
|
-
}
|
|
2413
|
-
if (agent) {
|
|
2414
|
-
query = query.where("agent", agent);
|
|
2415
|
-
}
|
|
2416
|
-
if (from) {
|
|
2417
|
-
query = query.where("createdAt", ">=", from);
|
|
2418
|
-
}
|
|
2419
|
-
if (to) {
|
|
2420
|
-
query = query.where("createdAt", "<=", to);
|
|
2529
|
+
if (tableNamePlural === "tracking") {
|
|
2530
|
+
query = query.sum("total as count");
|
|
2531
|
+
const [{ count }] = await query.sum("total as count");
|
|
2532
|
+
console.log("!!! count !!!", count);
|
|
2533
|
+
return [{
|
|
2534
|
+
group: "total",
|
|
2535
|
+
count: count ? Number(count) : 0
|
|
2536
|
+
}];
|
|
2537
|
+
} else {
|
|
2538
|
+
const [{ count }] = await query.count("* as count");
|
|
2539
|
+
return [{
|
|
2540
|
+
group: "total",
|
|
2541
|
+
count: count ? Number(count) : 0
|
|
2542
|
+
}];
|
|
2421
2543
|
}
|
|
2422
|
-
query = applyAccessControl(table, context.user, query);
|
|
2423
|
-
const runningQuery = query.clone().whereIn("status", ["active", "waiting", "delayed", "paused"]);
|
|
2424
|
-
const [{ runningCount }] = await runningQuery.count("* as runningCount");
|
|
2425
|
-
const erroredQuery = query.clone().whereIn("status", ["failed", "stuck"]);
|
|
2426
|
-
const [{ erroredCount }] = await erroredQuery.count("* as erroredCount");
|
|
2427
|
-
const completedQuery = query.clone().where("status", "completed");
|
|
2428
|
-
const [{ completedCount }] = await completedQuery.count("* as completedCount");
|
|
2429
|
-
const failedQuery = query.clone().where("status", "failed");
|
|
2430
|
-
const [{ failedCount }] = await failedQuery.count("* as failedCount");
|
|
2431
|
-
const durationQuery = query.clone().where("status", "completed").whereNotNull("duration").select(db3.raw('AVG("duration") as averageDuration'));
|
|
2432
|
-
const [{ averageDuration }] = await durationQuery;
|
|
2433
|
-
return {
|
|
2434
|
-
runningCount: Number(runningCount),
|
|
2435
|
-
erroredCount: Number(erroredCount),
|
|
2436
|
-
completedCount: Number(completedCount),
|
|
2437
|
-
failedCount: Number(failedCount),
|
|
2438
|
-
averageDuration: averageDuration ? Number(averageDuration) : 0
|
|
2439
|
-
};
|
|
2440
2544
|
}
|
|
2441
|
-
}
|
|
2545
|
+
}
|
|
2442
2546
|
};
|
|
2443
2547
|
}
|
|
2444
2548
|
var RBACResolver = async (db3, table, entityName, resourceId, rights_mode) => {
|
|
@@ -2458,6 +2562,16 @@ var RBACResolver = async (db3, table, entityName, resourceId, rights_mode) => {
|
|
|
2458
2562
|
};
|
|
2459
2563
|
};
|
|
2460
2564
|
function createSDL(tables) {
|
|
2565
|
+
tables.forEach((table) => {
|
|
2566
|
+
table.fields.push({
|
|
2567
|
+
name: "createdAt",
|
|
2568
|
+
type: "date"
|
|
2569
|
+
});
|
|
2570
|
+
table.fields.push({
|
|
2571
|
+
name: "updatedAt",
|
|
2572
|
+
type: "date"
|
|
2573
|
+
});
|
|
2574
|
+
});
|
|
2461
2575
|
console.log("[EXULU] Creating SDL");
|
|
2462
2576
|
let typeDefs = `
|
|
2463
2577
|
scalar JSON
|
|
@@ -2514,7 +2628,6 @@ function createSDL(tables) {
|
|
|
2514
2628
|
${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
|
|
2515
2629
|
${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
|
|
2516
2630
|
${tableNamePlural}Statistics(filters: [Filter${tableNameSingularUpperCaseFirst}], groupBy: String): [StatisticsResult]!
|
|
2517
|
-
${tableNamePlural === "jobs" ? `jobStatistics(user: ID, agent: String, from: String, to: String): JobStatistics` : ""}
|
|
2518
2631
|
`;
|
|
2519
2632
|
mutationDefs += `
|
|
2520
2633
|
${tableNamePlural}CreateOne(input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
@@ -2539,17 +2652,6 @@ type PageInfo {
|
|
|
2539
2652
|
hasNextPage: Boolean!
|
|
2540
2653
|
}
|
|
2541
2654
|
`;
|
|
2542
|
-
if (tableNamePlural === "jobs") {
|
|
2543
|
-
modelDefs += `
|
|
2544
|
-
type JobStatistics {
|
|
2545
|
-
runningCount: Int!
|
|
2546
|
-
erroredCount: Int!
|
|
2547
|
-
completedCount: Int!
|
|
2548
|
-
failedCount: Int!
|
|
2549
|
-
averageDuration: Float!
|
|
2550
|
-
}
|
|
2551
|
-
`;
|
|
2552
|
-
}
|
|
2553
2655
|
Object.assign(resolvers.Query, createQueries(table));
|
|
2554
2656
|
Object.assign(resolvers.Mutation, createMutations(table));
|
|
2555
2657
|
if (table.RBAC) {
|
|
@@ -2641,6 +2743,10 @@ var agentMessagesSchema = {
|
|
|
2641
2743
|
name: "title",
|
|
2642
2744
|
type: "text"
|
|
2643
2745
|
},
|
|
2746
|
+
{
|
|
2747
|
+
name: "user",
|
|
2748
|
+
type: "number"
|
|
2749
|
+
},
|
|
2644
2750
|
{
|
|
2645
2751
|
name: "session",
|
|
2646
2752
|
type: "text"
|
|
@@ -2877,6 +2983,10 @@ var rolesSchema = {
|
|
|
2877
2983
|
type: "text"
|
|
2878
2984
|
// write | read access to agents
|
|
2879
2985
|
},
|
|
2986
|
+
{
|
|
2987
|
+
name: "api",
|
|
2988
|
+
type: "text"
|
|
2989
|
+
},
|
|
2880
2990
|
{
|
|
2881
2991
|
name: "workflows",
|
|
2882
2992
|
type: "text"
|
|
@@ -2896,8 +3006,8 @@ var rolesSchema = {
|
|
|
2896
3006
|
};
|
|
2897
3007
|
var statisticsSchema = {
|
|
2898
3008
|
name: {
|
|
2899
|
-
plural: "
|
|
2900
|
-
singular: "
|
|
3009
|
+
plural: "tracking",
|
|
3010
|
+
singular: "tracking"
|
|
2901
3011
|
},
|
|
2902
3012
|
fields: [
|
|
2903
3013
|
{
|
|
@@ -2910,11 +3020,20 @@ var statisticsSchema = {
|
|
|
2910
3020
|
},
|
|
2911
3021
|
{
|
|
2912
3022
|
name: "type",
|
|
2913
|
-
type: "
|
|
3023
|
+
type: "enum",
|
|
3024
|
+
enumValues: Object.values(STATISTICS_TYPE_ENUM)
|
|
2914
3025
|
},
|
|
2915
3026
|
{
|
|
2916
3027
|
name: "total",
|
|
2917
3028
|
type: "number"
|
|
3029
|
+
},
|
|
3030
|
+
{
|
|
3031
|
+
name: "user",
|
|
3032
|
+
type: "number"
|
|
3033
|
+
},
|
|
3034
|
+
{
|
|
3035
|
+
name: "role",
|
|
3036
|
+
type: "uuid"
|
|
2918
3037
|
}
|
|
2919
3038
|
]
|
|
2920
3039
|
};
|
|
@@ -2975,6 +3094,7 @@ var jobsSchema = {
|
|
|
2975
3094
|
plural: "jobs",
|
|
2976
3095
|
singular: "job"
|
|
2977
3096
|
},
|
|
3097
|
+
RBAC: true,
|
|
2978
3098
|
fields: [
|
|
2979
3099
|
{
|
|
2980
3100
|
name: "redis",
|
|
@@ -2984,10 +3104,6 @@ var jobsSchema = {
|
|
|
2984
3104
|
name: "session",
|
|
2985
3105
|
type: "text"
|
|
2986
3106
|
},
|
|
2987
|
-
{
|
|
2988
|
-
name: "created_by",
|
|
2989
|
-
type: "number"
|
|
2990
|
-
},
|
|
2991
3107
|
{
|
|
2992
3108
|
name: "status",
|
|
2993
3109
|
type: "text"
|
|
@@ -3113,7 +3229,7 @@ var coreSchemas = {
|
|
|
3113
3229
|
};
|
|
3114
3230
|
|
|
3115
3231
|
// src/registry/uppy.ts
|
|
3116
|
-
var
|
|
3232
|
+
var import_express2 = require("express");
|
|
3117
3233
|
var createUppyRoutes = async (app) => {
|
|
3118
3234
|
const {
|
|
3119
3235
|
S3Client,
|
|
@@ -3587,7 +3703,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3587
3703
|
optionsSuccessStatus: 200
|
|
3588
3704
|
// some legacy browsers (IE11, various SmartTVs) choke on 204
|
|
3589
3705
|
};
|
|
3590
|
-
app.use(
|
|
3706
|
+
app.use(import_express4.default.json({ limit: REQUEST_SIZE_LIMIT }));
|
|
3591
3707
|
app.use((0, import_cors.default)(corsOptions));
|
|
3592
3708
|
app.use(import_body_parser.default.urlencoded({ extended: true, limit: REQUEST_SIZE_LIMIT }));
|
|
3593
3709
|
app.use(import_body_parser.default.json({ limit: REQUEST_SIZE_LIMIT }));
|
|
@@ -3630,11 +3746,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3630
3746
|
{ route: "/agents/:id", method: "GET", note: "Get specific agent" },
|
|
3631
3747
|
{ route: "/contexts", method: "GET", note: "List all contexts" },
|
|
3632
3748
|
{ route: "/contexts/:id", method: "GET", note: "Get specific context" },
|
|
3633
|
-
{ route: "/contexts/statistics", method: "GET", note: "Get context statistics" },
|
|
3634
3749
|
{ route: "/tools", method: "GET", note: "List all tools" },
|
|
3635
3750
|
{ route: "/tools/:id", method: "GET", note: "Get specific tool" },
|
|
3636
|
-
{ route: "/statistics/timeseries", method: "POST", note: "Get time series statistics" },
|
|
3637
|
-
{ route: "/statistics/totals", method: "POST", note: "Get totals statistics" },
|
|
3638
3751
|
{ route: "/items/:context", method: "POST", note: "Create new item in context" },
|
|
3639
3752
|
{ route: "/items/:context", method: "GET", note: "Get items from context" },
|
|
3640
3753
|
{ route: "/items/export/:context", method: "GET", note: "Export items from context" },
|
|
@@ -3672,7 +3785,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3672
3785
|
app.use(
|
|
3673
3786
|
"/graphql",
|
|
3674
3787
|
(0, import_cors.default)(corsOptions),
|
|
3675
|
-
|
|
3788
|
+
import_express4.default.json({ limit: REQUEST_SIZE_LIMIT }),
|
|
3676
3789
|
(0, import_express5.expressMiddleware)(server, {
|
|
3677
3790
|
context: async ({ req }) => {
|
|
3678
3791
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
@@ -4167,115 +4280,6 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4167
4280
|
authenticated: true
|
|
4168
4281
|
});
|
|
4169
4282
|
});
|
|
4170
|
-
console.log("[EXULU] statistics timeseries");
|
|
4171
|
-
app.post("/statistics/timeseries", async (req, res) => {
|
|
4172
|
-
const authenticationResult = await requestValidators.authenticate(req);
|
|
4173
|
-
if (!authenticationResult.user?.id) {
|
|
4174
|
-
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4175
|
-
return;
|
|
4176
|
-
}
|
|
4177
|
-
const { db: db3 } = await postgresClient();
|
|
4178
|
-
const type = req.body.type;
|
|
4179
|
-
if (!Object.values(STATISTICS_TYPE_ENUM).includes(type)) {
|
|
4180
|
-
res.status(400).json({
|
|
4181
|
-
message: "Invalid type, must be one of: " + Object.values(STATISTICS_TYPE_ENUM).join(", ")
|
|
4182
|
-
});
|
|
4183
|
-
return;
|
|
4184
|
-
}
|
|
4185
|
-
let from = new Date(req.body.from);
|
|
4186
|
-
let to = new Date(req.body.to);
|
|
4187
|
-
if (!from || !to) {
|
|
4188
|
-
from = new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3);
|
|
4189
|
-
to = /* @__PURE__ */ new Date();
|
|
4190
|
-
}
|
|
4191
|
-
const query = db3.from("statistics").select("*");
|
|
4192
|
-
query.where("name", "count");
|
|
4193
|
-
query.andWhere("type", type);
|
|
4194
|
-
query.andWhere("createdAt", ">=", from);
|
|
4195
|
-
query.andWhere("createdAt", "<=", to);
|
|
4196
|
-
const results = await query;
|
|
4197
|
-
const dates = [];
|
|
4198
|
-
for (let i = 0; i < (to.getTime() - from.getTime()) / (1e3 * 60 * 60 * 24); i++) {
|
|
4199
|
-
dates.push(new Date(from.getTime() + i * (1e3 * 60 * 60 * 24)));
|
|
4200
|
-
}
|
|
4201
|
-
const data = dates.map((date) => {
|
|
4202
|
-
const result = results.find((result2) => result2.date === date);
|
|
4203
|
-
if (result) {
|
|
4204
|
-
return result;
|
|
4205
|
-
}
|
|
4206
|
-
return {
|
|
4207
|
-
date,
|
|
4208
|
-
count: 0
|
|
4209
|
-
};
|
|
4210
|
-
});
|
|
4211
|
-
res.status(200).json({
|
|
4212
|
-
data,
|
|
4213
|
-
filter: {
|
|
4214
|
-
from,
|
|
4215
|
-
to
|
|
4216
|
-
}
|
|
4217
|
-
});
|
|
4218
|
-
});
|
|
4219
|
-
console.log("[EXULU] statistics totals");
|
|
4220
|
-
app.post("/statistics/totals", async (req, res) => {
|
|
4221
|
-
const authenticationResult = await requestValidators.authenticate(req);
|
|
4222
|
-
if (!authenticationResult.user?.id) {
|
|
4223
|
-
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4224
|
-
return;
|
|
4225
|
-
}
|
|
4226
|
-
const { db: db3 } = await postgresClient();
|
|
4227
|
-
let from = new Date(req.body.from);
|
|
4228
|
-
let to = new Date(req.body.to);
|
|
4229
|
-
if (!from || !to) {
|
|
4230
|
-
from = new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3);
|
|
4231
|
-
to = /* @__PURE__ */ new Date();
|
|
4232
|
-
}
|
|
4233
|
-
let promises2 = Object.values(STATISTICS_TYPE_ENUM).map(async (type) => {
|
|
4234
|
-
const result = await db3.from("statistics").where("name", "count").andWhere("type", type).andWhere("createdAt", ">=", from).andWhere("createdAt", "<=", to).sum("total as total");
|
|
4235
|
-
return {
|
|
4236
|
-
[type]: result[0]?.total || 0
|
|
4237
|
-
};
|
|
4238
|
-
});
|
|
4239
|
-
const results = await Promise.all(promises2);
|
|
4240
|
-
res.status(200).json({
|
|
4241
|
-
data: { ...Object.assign({}, ...results) },
|
|
4242
|
-
filter: {
|
|
4243
|
-
from,
|
|
4244
|
-
to
|
|
4245
|
-
}
|
|
4246
|
-
});
|
|
4247
|
-
});
|
|
4248
|
-
console.log("[EXULU] contexts statistics");
|
|
4249
|
-
app.get("/contexts/statistics", async (req, res) => {
|
|
4250
|
-
const authenticationResult = await requestValidators.authenticate(req);
|
|
4251
|
-
if (!authenticationResult.user?.id) {
|
|
4252
|
-
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4253
|
-
return;
|
|
4254
|
-
}
|
|
4255
|
-
const { db: db3 } = await postgresClient();
|
|
4256
|
-
const statistics = await db3("statistics").where("name", "count").andWhere("type", "context.retrieve").sum("total as total").first();
|
|
4257
|
-
const response = await db3("jobs").select(db3.raw(`to_char("createdAt", 'YYYY-MM-DD') as date`)).count("* as count").where("type", "embedder").groupByRaw(`to_char("createdAt", 'YYYY-MM-DD')`).then((rows) => ({
|
|
4258
|
-
jobs: rows
|
|
4259
|
-
}));
|
|
4260
|
-
let jobs = [];
|
|
4261
|
-
if (response[0]) {
|
|
4262
|
-
jobs = response[0].jobs.map((job) => ({
|
|
4263
|
-
date: job.id,
|
|
4264
|
-
count: job.count
|
|
4265
|
-
}));
|
|
4266
|
-
}
|
|
4267
|
-
const embeddingsCountResult = await db3("jobs").where("type", "embedder").count("* as count").first();
|
|
4268
|
-
res.status(200).json({
|
|
4269
|
-
active: contexts.filter((context) => context.active).length,
|
|
4270
|
-
inactive: contexts.filter((context) => !context.active).length,
|
|
4271
|
-
sources: contexts.reduce((acc, context) => acc + context.sources.get().length, 0),
|
|
4272
|
-
queries: statistics?.total || 0,
|
|
4273
|
-
jobs,
|
|
4274
|
-
totals: {
|
|
4275
|
-
embeddings: embeddingsCountResult?.count || 0
|
|
4276
|
-
}
|
|
4277
|
-
});
|
|
4278
|
-
});
|
|
4279
4283
|
console.log("[EXULU] context by id");
|
|
4280
4284
|
app.get(`/contexts/:id`, async (req, res) => {
|
|
4281
4285
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
@@ -4446,7 +4450,11 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4446
4450
|
return;
|
|
4447
4451
|
}
|
|
4448
4452
|
}
|
|
4449
|
-
const
|
|
4453
|
+
const headers = {
|
|
4454
|
+
stream: req.headers["stream"] === "true" || false,
|
|
4455
|
+
user: req.headers["user"] || null,
|
|
4456
|
+
session: req.headers["session"] || null
|
|
4457
|
+
};
|
|
4450
4458
|
const requestValidationResult = requestValidators.agents(req);
|
|
4451
4459
|
if (requestValidationResult.error) {
|
|
4452
4460
|
res.status(requestValidationResult.code || 500).json({ detail: `${requestValidationResult.message}` });
|
|
@@ -4457,6 +4465,13 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4457
4465
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4458
4466
|
return;
|
|
4459
4467
|
}
|
|
4468
|
+
const user = authenticationResult.user;
|
|
4469
|
+
if (user.type !== "api" && !user.super_admin && req.body.resourceId !== user.id) {
|
|
4470
|
+
res.status(400).json({
|
|
4471
|
+
message: "The provided user id in the resourceId field is not the same as the authenticated user. Only super admins and API users can impersonate other users."
|
|
4472
|
+
});
|
|
4473
|
+
return;
|
|
4474
|
+
}
|
|
4460
4475
|
console.log("[EXULU] agent tools", agentInstance.tools);
|
|
4461
4476
|
const enabledTools = agentInstance.tools.map(({ config, toolId }) => tools.find(({ id }) => id === toolId)).filter(Boolean);
|
|
4462
4477
|
console.log("[EXULU] enabled tools", enabledTools);
|
|
@@ -4479,9 +4494,15 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4479
4494
|
const bytes = import_crypto_js3.default.AES.decrypt(variable.value, process.env.NEXTAUTH_SECRET);
|
|
4480
4495
|
providerApiKey = bytes.toString(import_crypto_js3.default.enc.Utf8);
|
|
4481
4496
|
}
|
|
4482
|
-
if (!!stream) {
|
|
4483
|
-
|
|
4484
|
-
|
|
4497
|
+
if (!!headers.stream) {
|
|
4498
|
+
await agent.generateStream({
|
|
4499
|
+
express: {
|
|
4500
|
+
res,
|
|
4501
|
+
req
|
|
4502
|
+
},
|
|
4503
|
+
user: headers.user,
|
|
4504
|
+
session: headers.session,
|
|
4505
|
+
message: req.body.message,
|
|
4485
4506
|
tools: enabledTools,
|
|
4486
4507
|
providerApiKey,
|
|
4487
4508
|
toolConfigs: agentInstance.tools,
|
|
@@ -4490,11 +4511,12 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4490
4511
|
trigger: "agent"
|
|
4491
4512
|
}
|
|
4492
4513
|
});
|
|
4493
|
-
result.pipeDataStreamToResponse(res);
|
|
4494
4514
|
return;
|
|
4495
4515
|
} else {
|
|
4496
4516
|
const response = await agent.generateSync({
|
|
4497
|
-
|
|
4517
|
+
user: headers.user,
|
|
4518
|
+
session: headers.session,
|
|
4519
|
+
message: req.body.message,
|
|
4498
4520
|
tools: enabledTools.map((tool2) => tool2.tool),
|
|
4499
4521
|
providerApiKey,
|
|
4500
4522
|
toolConfigs: agentInstance.tools,
|
|
@@ -4516,7 +4538,7 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4516
4538
|
console.log("Routes:");
|
|
4517
4539
|
console.table(routeLogs);
|
|
4518
4540
|
const TARGET_API = "https://api.anthropic.com";
|
|
4519
|
-
app.use("/gateway/anthropic/:id",
|
|
4541
|
+
app.use("/gateway/anthropic/:id", import_express4.default.raw({ type: "*/*", limit: REQUEST_SIZE_LIMIT }), async (req, res) => {
|
|
4520
4542
|
const path3 = req.url;
|
|
4521
4543
|
const url = `${TARGET_API}${path3}`;
|
|
4522
4544
|
try {
|
|
@@ -4861,7 +4883,7 @@ var import_node_crypto = require("crypto");
|
|
|
4861
4883
|
var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
4862
4884
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
4863
4885
|
var import_zod3 = require("zod");
|
|
4864
|
-
var
|
|
4886
|
+
var import_express6 = require("express");
|
|
4865
4887
|
var SESSION_ID_HEADER = "mcp-session-id";
|
|
4866
4888
|
var ExuluMCP = class {
|
|
4867
4889
|
server;
|
|
@@ -4999,7 +5021,7 @@ ${code}`
|
|
|
4999
5021
|
};
|
|
5000
5022
|
|
|
5001
5023
|
// src/registry/index.ts
|
|
5002
|
-
var
|
|
5024
|
+
var import_express8 = __toESM(require("express"), 1);
|
|
5003
5025
|
|
|
5004
5026
|
// src/templates/agents/claude-code.ts
|
|
5005
5027
|
var agentId = "0832-5178-1145-2194";
|
|
@@ -5019,7 +5041,6 @@ var defaultAgent = new ExuluAgent({
|
|
|
5019
5041
|
description: `Basic agent without any defined tools, that can support MCP's.`,
|
|
5020
5042
|
type: "agent",
|
|
5021
5043
|
capabilities: {
|
|
5022
|
-
tools: false,
|
|
5023
5044
|
images: [],
|
|
5024
5045
|
files: [],
|
|
5025
5046
|
audio: [],
|
|
@@ -5031,10 +5052,10 @@ var defaultAgent = new ExuluAgent({
|
|
|
5031
5052
|
instructions: "You are a helpful assistant.",
|
|
5032
5053
|
model: {
|
|
5033
5054
|
create: ({ apiKey }) => {
|
|
5034
|
-
const
|
|
5055
|
+
const anthropic = (0, import_anthropic.createAnthropic)({
|
|
5035
5056
|
apiKey
|
|
5036
5057
|
});
|
|
5037
|
-
return
|
|
5058
|
+
return anthropic.languageModel("claude-4-opus-20250514");
|
|
5038
5059
|
}
|
|
5039
5060
|
// todo add a field of type string that adds a dropdown list from which the user can select the model
|
|
5040
5061
|
// todo for each model, check which provider is used, and require the admin to add one or multiple
|
|
@@ -5080,7 +5101,7 @@ var ExuluApp = class {
|
|
|
5080
5101
|
];
|
|
5081
5102
|
this._queues = [...new Set(queues2.filter((o) => !!o))];
|
|
5082
5103
|
if (!this._expressApp) {
|
|
5083
|
-
this._expressApp = (0,
|
|
5104
|
+
this._expressApp = (0, import_express8.default)();
|
|
5084
5105
|
await this.server.express.init();
|
|
5085
5106
|
console.log("[EXULU] Express app initialized.");
|
|
5086
5107
|
}
|
|
@@ -6575,6 +6596,13 @@ var ExuluJobs = {
|
|
|
6575
6596
|
var db2 = {
|
|
6576
6597
|
init: async () => {
|
|
6577
6598
|
await execute();
|
|
6599
|
+
},
|
|
6600
|
+
api: {
|
|
6601
|
+
key: {
|
|
6602
|
+
generate: async (name, email) => {
|
|
6603
|
+
return await generateApiKey(name, email);
|
|
6604
|
+
}
|
|
6605
|
+
}
|
|
6578
6606
|
}
|
|
6579
6607
|
};
|
|
6580
6608
|
var ExuluChunkers = {
|