@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.js
CHANGED
|
@@ -75,19 +75,19 @@ import "bullmq";
|
|
|
75
75
|
import { z } from "zod";
|
|
76
76
|
import * as fs from "fs";
|
|
77
77
|
import * as path from "path";
|
|
78
|
-
import { generateObject, generateText, streamText, tool } from "ai";
|
|
78
|
+
import { convertToModelMessages, createIdGenerator, generateObject, generateText, streamText, tool, validateUIMessages, stepCountIs } from "ai";
|
|
79
79
|
|
|
80
80
|
// types/enums/statistics.ts
|
|
81
81
|
var STATISTICS_TYPE_ENUM = {
|
|
82
|
-
CONTEXT_RETRIEVE: "
|
|
83
|
-
SOURCE_UPDATE: "
|
|
84
|
-
EMBEDDER_UPSERT: "
|
|
85
|
-
EMBEDDER_GENERATE: "
|
|
86
|
-
EMBEDDER_DELETE: "
|
|
87
|
-
WORKFLOW_RUN: "
|
|
88
|
-
CONTEXT_UPSERT: "
|
|
89
|
-
TOOL_CALL: "
|
|
90
|
-
AGENT_RUN: "
|
|
82
|
+
CONTEXT_RETRIEVE: "CONTEXT_RETRIEVE",
|
|
83
|
+
SOURCE_UPDATE: "SOURCE_UPDATE",
|
|
84
|
+
EMBEDDER_UPSERT: "EMBEDDER_UPSERT",
|
|
85
|
+
EMBEDDER_GENERATE: "EMBEDDER_GENERATE",
|
|
86
|
+
EMBEDDER_DELETE: "EMBEDDER_DELETE",
|
|
87
|
+
WORKFLOW_RUN: "WORKFLOW_RUN",
|
|
88
|
+
CONTEXT_UPSERT: "CONTEXT_UPSERT",
|
|
89
|
+
TOOL_CALL: "TOOL_CALL",
|
|
90
|
+
AGENT_RUN: "AGENT_RUN"
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
// types/enums/eval-types.ts
|
|
@@ -262,7 +262,7 @@ var bullmqDecorator = async ({
|
|
|
262
262
|
|
|
263
263
|
// src/registry/utils/map-types.ts
|
|
264
264
|
var mapType = (t, type, name, defaultValue, unique) => {
|
|
265
|
-
if (type === "text") {
|
|
265
|
+
if (type === "text" || type === "enum") {
|
|
266
266
|
t.text(name);
|
|
267
267
|
if (unique) t.unique(name);
|
|
268
268
|
if (defaultValue) t.defaultTo(defaultValue);
|
|
@@ -403,6 +403,7 @@ var ExuluEvalUtils = {
|
|
|
403
403
|
|
|
404
404
|
// src/registry/classes.ts
|
|
405
405
|
import CryptoJS from "crypto-js";
|
|
406
|
+
import "express";
|
|
406
407
|
function sanitizeToolName(name) {
|
|
407
408
|
if (typeof name !== "string") return "";
|
|
408
409
|
let sanitized = name.replace(/[^a-zA-Z0-9_-]+/g, "_");
|
|
@@ -421,7 +422,7 @@ var convertToolsArrayToObject = (tools, configs, providerApiKey) => {
|
|
|
421
422
|
console.log("[EXULU] Sanitized tools", sanitizedTools);
|
|
422
423
|
const askForConfirmation = {
|
|
423
424
|
description: "Ask the user for confirmation.",
|
|
424
|
-
|
|
425
|
+
inputSchema: z.object({
|
|
425
426
|
message: z.string().describe("The message to ask for confirmation.")
|
|
426
427
|
})
|
|
427
428
|
};
|
|
@@ -532,10 +533,12 @@ var ExuluAgent = class {
|
|
|
532
533
|
this.model = this.config?.model;
|
|
533
534
|
}
|
|
534
535
|
get providerName() {
|
|
535
|
-
|
|
536
|
+
const model = this.config?.model?.create({ apiKey: "" });
|
|
537
|
+
return typeof model === "string" ? model : model?.provider || "";
|
|
536
538
|
}
|
|
537
539
|
get modelName() {
|
|
538
|
-
|
|
540
|
+
const model = this.config?.model?.create({ apiKey: "" });
|
|
541
|
+
return typeof model === "string" ? model : model?.modelId || "";
|
|
539
542
|
}
|
|
540
543
|
// Exports the agent as a tool that can be used by another agent
|
|
541
544
|
// todo test this
|
|
@@ -561,28 +564,44 @@ var ExuluAgent = class {
|
|
|
561
564
|
}
|
|
562
565
|
});
|
|
563
566
|
};
|
|
564
|
-
generateSync = async ({
|
|
567
|
+
generateSync = async ({ prompt, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
565
568
|
if (!this.model) {
|
|
566
569
|
throw new Error("Model is required for streaming.");
|
|
567
570
|
}
|
|
568
571
|
if (!this.config) {
|
|
569
572
|
throw new Error("Config is required for generating.");
|
|
570
573
|
}
|
|
571
|
-
if (prompt &&
|
|
572
|
-
throw new Error("
|
|
574
|
+
if (prompt && message) {
|
|
575
|
+
throw new Error("Message and prompt cannot be provided at the same time.");
|
|
573
576
|
}
|
|
574
577
|
const model = this.model.create({
|
|
575
578
|
apiKey: providerApiKey
|
|
576
579
|
});
|
|
580
|
+
let messages = [];
|
|
581
|
+
if (message && session && user) {
|
|
582
|
+
const previousMessages = await getAgentMessages({
|
|
583
|
+
session,
|
|
584
|
+
user,
|
|
585
|
+
limit: 50,
|
|
586
|
+
page: 1
|
|
587
|
+
});
|
|
588
|
+
const previousMessagesContent = previousMessages.map((message2) => JSON.parse(message2.content));
|
|
589
|
+
messages = await validateUIMessages({
|
|
590
|
+
// append the new message to the previous messages:
|
|
591
|
+
messages: [...previousMessagesContent, message]
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
console.log("[EXULU] Model provider key", providerApiKey);
|
|
595
|
+
console.log("[EXULU] Tool configs", toolConfigs);
|
|
577
596
|
const { text } = await generateText({
|
|
578
597
|
model,
|
|
579
598
|
// Should be a LanguageModelV1
|
|
580
599
|
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.",
|
|
581
|
-
messages,
|
|
600
|
+
messages: messages ? convertToModelMessages(messages) : void 0,
|
|
582
601
|
prompt,
|
|
583
602
|
maxRetries: 2,
|
|
584
603
|
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
585
|
-
|
|
604
|
+
stopWhen: [stepCountIs(5)]
|
|
586
605
|
});
|
|
587
606
|
if (statistics) {
|
|
588
607
|
await updateStatistic({
|
|
@@ -595,36 +614,61 @@ var ExuluAgent = class {
|
|
|
595
614
|
}
|
|
596
615
|
return text;
|
|
597
616
|
};
|
|
598
|
-
generateStream = ({
|
|
617
|
+
generateStream = async ({ express: express3, user, session, message, tools, statistics, toolConfigs, providerApiKey }) => {
|
|
599
618
|
if (!this.model) {
|
|
600
619
|
throw new Error("Model is required for streaming.");
|
|
601
620
|
}
|
|
602
621
|
if (!this.config) {
|
|
603
622
|
throw new Error("Config is required for generating.");
|
|
604
623
|
}
|
|
605
|
-
if (
|
|
606
|
-
throw new Error("
|
|
624
|
+
if (!message) {
|
|
625
|
+
throw new Error("Message is required for streaming.");
|
|
607
626
|
}
|
|
608
627
|
const model = this.model.create({
|
|
609
628
|
apiKey: providerApiKey
|
|
610
629
|
});
|
|
630
|
+
let messages = [];
|
|
631
|
+
const previousMessages = await getAgentMessages({
|
|
632
|
+
session,
|
|
633
|
+
user,
|
|
634
|
+
limit: 50,
|
|
635
|
+
page: 1
|
|
636
|
+
});
|
|
637
|
+
const previousMessagesContent = previousMessages.map((message2) => JSON.parse(message2.content));
|
|
638
|
+
messages = await validateUIMessages({
|
|
639
|
+
// append the new message to the previous messages:
|
|
640
|
+
messages: [...previousMessagesContent, message]
|
|
641
|
+
});
|
|
611
642
|
console.log("[EXULU] Model provider key", providerApiKey);
|
|
612
643
|
console.log("[EXULU] Tool configs", toolConfigs);
|
|
613
|
-
|
|
644
|
+
const result = streamText({
|
|
614
645
|
model,
|
|
615
646
|
// Should be a LanguageModelV1
|
|
616
|
-
messages,
|
|
617
|
-
prompt,
|
|
647
|
+
messages: messages ? convertToModelMessages(messages) : void 0,
|
|
618
648
|
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.",
|
|
619
649
|
maxRetries: 2,
|
|
620
650
|
tools: convertToolsArrayToObject(tools, toolConfigs, providerApiKey),
|
|
621
|
-
maxSteps: 5,
|
|
622
651
|
onError: (error) => console.error("[EXULU] chat stream error.", error),
|
|
623
|
-
|
|
652
|
+
stopWhen: [stepCountIs(5)]
|
|
653
|
+
});
|
|
654
|
+
result.consumeStream();
|
|
655
|
+
result.pipeUIMessageStreamToResponse(express3.res, {
|
|
656
|
+
originalMessages: messages,
|
|
657
|
+
sendReasoning: true,
|
|
658
|
+
generateMessageId: createIdGenerator({
|
|
659
|
+
prefix: "msg_",
|
|
660
|
+
size: 16
|
|
661
|
+
}),
|
|
662
|
+
onFinish: async ({ messages: messages2 }) => {
|
|
624
663
|
console.info(
|
|
625
664
|
"[EXULU] chat stream finished.",
|
|
626
|
-
|
|
665
|
+
messages2
|
|
627
666
|
);
|
|
667
|
+
await saveChat({
|
|
668
|
+
session,
|
|
669
|
+
user,
|
|
670
|
+
messages: messages2
|
|
671
|
+
});
|
|
628
672
|
if (statistics) {
|
|
629
673
|
await updateStatistic({
|
|
630
674
|
name: "count",
|
|
@@ -636,8 +680,26 @@ var ExuluAgent = class {
|
|
|
636
680
|
}
|
|
637
681
|
}
|
|
638
682
|
});
|
|
683
|
+
return;
|
|
639
684
|
};
|
|
640
685
|
};
|
|
686
|
+
var getAgentMessages = async ({ session, user, limit, page }) => {
|
|
687
|
+
const { db: db3 } = await postgresClient();
|
|
688
|
+
const messages = await db3.from("agent_messages").where({ session, user }).limit(limit).offset(page * limit);
|
|
689
|
+
return messages;
|
|
690
|
+
};
|
|
691
|
+
var saveChat = async ({ session, user, messages }) => {
|
|
692
|
+
const { db: db3 } = await postgresClient();
|
|
693
|
+
const promises2 = messages.map((message) => {
|
|
694
|
+
return db3.from("agent_messages").insert({
|
|
695
|
+
session,
|
|
696
|
+
user,
|
|
697
|
+
content: JSON.stringify(message),
|
|
698
|
+
title: message.role === "user" ? "User" : "Assistant"
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
await Promise.all(promises2);
|
|
702
|
+
};
|
|
641
703
|
var ExuluEmbedder = class {
|
|
642
704
|
id;
|
|
643
705
|
name;
|
|
@@ -888,7 +950,7 @@ var ExuluTool = class {
|
|
|
888
950
|
this.type = type;
|
|
889
951
|
this.tool = tool({
|
|
890
952
|
description,
|
|
891
|
-
|
|
953
|
+
inputSchema: inputSchema || z.object({}),
|
|
892
954
|
execute: execute2
|
|
893
955
|
});
|
|
894
956
|
}
|
|
@@ -1377,22 +1439,27 @@ var ExuluSource = class {
|
|
|
1377
1439
|
var updateStatistic = async (statistic) => {
|
|
1378
1440
|
const currentDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1379
1441
|
const { db: db3 } = await postgresClient();
|
|
1380
|
-
const existing = await db3.from("
|
|
1442
|
+
const existing = await db3.from("tracking").where({
|
|
1443
|
+
...statistic.user ? { user: statistic.user } : {},
|
|
1444
|
+
...statistic.role ? { role: statistic.role } : {},
|
|
1381
1445
|
name: statistic.name,
|
|
1382
1446
|
label: statistic.label,
|
|
1383
1447
|
type: statistic.type,
|
|
1384
1448
|
createdAt: currentDate
|
|
1385
1449
|
}).first();
|
|
1450
|
+
console.log("!!! existing !!!", existing);
|
|
1386
1451
|
if (!existing) {
|
|
1387
|
-
await db3.from("
|
|
1452
|
+
await db3.from("tracking").insert({
|
|
1388
1453
|
name: statistic.name,
|
|
1389
1454
|
label: statistic.label,
|
|
1390
1455
|
type: statistic.type,
|
|
1391
1456
|
total: statistic.count ?? 1,
|
|
1392
|
-
createdAt: currentDate
|
|
1457
|
+
createdAt: currentDate,
|
|
1458
|
+
...statistic.user ? { user: statistic.user } : {},
|
|
1459
|
+
...statistic.role ? { role: statistic.role } : {}
|
|
1393
1460
|
});
|
|
1394
1461
|
} else {
|
|
1395
|
-
await db3.from("
|
|
1462
|
+
await db3.from("tracking").update({
|
|
1396
1463
|
total: db3.raw("total + ?", [statistic.count ?? 1])
|
|
1397
1464
|
}).where({
|
|
1398
1465
|
name: statistic.name,
|
|
@@ -1731,25 +1798,25 @@ var requestValidators = {
|
|
|
1731
1798
|
message: "Missing body."
|
|
1732
1799
|
};
|
|
1733
1800
|
}
|
|
1734
|
-
if (!req.
|
|
1801
|
+
if (!req.headers["user"]) {
|
|
1735
1802
|
return {
|
|
1736
1803
|
error: true,
|
|
1737
1804
|
code: 400,
|
|
1738
|
-
message:
|
|
1805
|
+
message: 'Missing "user" property in headers.'
|
|
1739
1806
|
};
|
|
1740
1807
|
}
|
|
1741
|
-
if (!req.
|
|
1808
|
+
if (!req.headers["session"]) {
|
|
1742
1809
|
return {
|
|
1743
1810
|
error: true,
|
|
1744
1811
|
code: 400,
|
|
1745
|
-
message:
|
|
1812
|
+
message: 'Missing "session" property in headers.'
|
|
1746
1813
|
};
|
|
1747
1814
|
}
|
|
1748
|
-
if (!req.body.
|
|
1815
|
+
if (!req.body.message) {
|
|
1749
1816
|
return {
|
|
1750
1817
|
error: true,
|
|
1751
1818
|
code: 400,
|
|
1752
|
-
message: 'Missing "
|
|
1819
|
+
message: 'Missing "message" property in body.'
|
|
1753
1820
|
};
|
|
1754
1821
|
}
|
|
1755
1822
|
return {
|
|
@@ -1853,6 +1920,9 @@ var map = (field) => {
|
|
|
1853
1920
|
case "code":
|
|
1854
1921
|
type = "String";
|
|
1855
1922
|
break;
|
|
1923
|
+
case "enum":
|
|
1924
|
+
type = field.enumValues ? `${field.name}Enum` : "String";
|
|
1925
|
+
break;
|
|
1856
1926
|
case "number":
|
|
1857
1927
|
type = "Float";
|
|
1858
1928
|
break;
|
|
@@ -1871,6 +1941,16 @@ var map = (field) => {
|
|
|
1871
1941
|
return type;
|
|
1872
1942
|
};
|
|
1873
1943
|
function createTypeDefs(table) {
|
|
1944
|
+
const enumDefs = table.fields.filter((field) => field.type === "enum" && field.enumValues).map((field) => {
|
|
1945
|
+
const enumValues = field.enumValues.map((value) => {
|
|
1946
|
+
const sanitized = String(value).replace(/[^a-zA-Z0-9_]/g, "_").replace(/^[0-9]/, "_$&").toUpperCase();
|
|
1947
|
+
return ` ${sanitized}`;
|
|
1948
|
+
}).join("\n");
|
|
1949
|
+
return `
|
|
1950
|
+
enum ${field.name}Enum {
|
|
1951
|
+
${enumValues}
|
|
1952
|
+
}`;
|
|
1953
|
+
}).join("\n");
|
|
1874
1954
|
const fields = table.fields.map((field) => {
|
|
1875
1955
|
let type;
|
|
1876
1956
|
type = map(field);
|
|
@@ -1882,8 +1962,6 @@ function createTypeDefs(table) {
|
|
|
1882
1962
|
type ${table.name.singular} {
|
|
1883
1963
|
${fields.join("\n")}
|
|
1884
1964
|
${table.fields.find((field) => field.name === "id") ? "" : "id: ID!"}
|
|
1885
|
-
createdAt: Date!
|
|
1886
|
-
updatedAt: Date!
|
|
1887
1965
|
${rbacField}
|
|
1888
1966
|
}
|
|
1889
1967
|
`;
|
|
@@ -1894,39 +1972,62 @@ ${table.fields.map((f) => ` ${f.name}: ${map(f)}`).join("\n")}
|
|
|
1894
1972
|
${rbacInputField}
|
|
1895
1973
|
}
|
|
1896
1974
|
`;
|
|
1897
|
-
return typeDef + inputDef;
|
|
1975
|
+
return enumDefs + typeDef + inputDef;
|
|
1898
1976
|
}
|
|
1899
1977
|
function createFilterTypeDefs(table) {
|
|
1900
1978
|
const fieldFilters = table.fields.map((field) => {
|
|
1901
1979
|
let type;
|
|
1902
|
-
type
|
|
1980
|
+
if (field.type === "enum" && field.enumValues) {
|
|
1981
|
+
type = `${field.name}Enum`;
|
|
1982
|
+
} else {
|
|
1983
|
+
type = map(field);
|
|
1984
|
+
}
|
|
1903
1985
|
return `
|
|
1904
1986
|
${field.name}: FilterOperator${type}`;
|
|
1905
1987
|
});
|
|
1906
1988
|
const tableNameSingularUpperCaseFirst = table.name.singular.charAt(0).toUpperCase() + table.name.singular.slice(1);
|
|
1989
|
+
const enumFilterOperators = table.fields.filter((field) => field.type === "enum" && field.enumValues).map((field) => {
|
|
1990
|
+
const enumTypeName = `${field.name}Enum`;
|
|
1991
|
+
return `
|
|
1992
|
+
input FilterOperator${enumTypeName} {
|
|
1993
|
+
eq: ${enumTypeName}
|
|
1994
|
+
ne: ${enumTypeName}
|
|
1995
|
+
in: [${enumTypeName}]
|
|
1996
|
+
and: [FilterOperator${enumTypeName}]
|
|
1997
|
+
or: [FilterOperator${enumTypeName}]
|
|
1998
|
+
}`;
|
|
1999
|
+
}).join("\n");
|
|
1907
2000
|
const operatorTypes = `
|
|
1908
2001
|
input FilterOperatorString {
|
|
1909
2002
|
eq: String
|
|
1910
2003
|
ne: String
|
|
1911
2004
|
in: [String]
|
|
1912
2005
|
contains: String
|
|
2006
|
+
and: [FilterOperatorString]
|
|
2007
|
+
or: [FilterOperatorString]
|
|
1913
2008
|
}
|
|
1914
2009
|
|
|
1915
2010
|
input FilterOperatorDate {
|
|
1916
2011
|
lte: Date
|
|
1917
2012
|
gte: Date
|
|
2013
|
+
and: [FilterOperatorDate]
|
|
2014
|
+
or: [FilterOperatorDate]
|
|
1918
2015
|
}
|
|
1919
2016
|
|
|
1920
2017
|
input FilterOperatorFloat {
|
|
1921
2018
|
eq: Float
|
|
1922
2019
|
ne: Float
|
|
1923
2020
|
in: [Float]
|
|
2021
|
+
and: [FilterOperatorFloat]
|
|
2022
|
+
or: [FilterOperatorFloat]
|
|
1924
2023
|
}
|
|
1925
2024
|
|
|
1926
2025
|
input FilterOperatorBoolean {
|
|
1927
2026
|
eq: Boolean
|
|
1928
2027
|
ne: Boolean
|
|
1929
2028
|
in: [Boolean]
|
|
2029
|
+
and: [FilterOperatorBoolean]
|
|
2030
|
+
or: [FilterOperatorBoolean]
|
|
1930
2031
|
}
|
|
1931
2032
|
|
|
1932
2033
|
input FilterOperatorJSON {
|
|
@@ -1945,6 +2046,8 @@ enum SortDirection {
|
|
|
1945
2046
|
DESC
|
|
1946
2047
|
}
|
|
1947
2048
|
|
|
2049
|
+
${enumFilterOperators}
|
|
2050
|
+
|
|
1948
2051
|
input Filter${tableNameSingularUpperCaseFirst} {
|
|
1949
2052
|
${fieldFilters.join("\n")}
|
|
1950
2053
|
}`;
|
|
@@ -2016,6 +2119,17 @@ function createMutations(table) {
|
|
|
2016
2119
|
const validateWriteAccess = async (id, context) => {
|
|
2017
2120
|
try {
|
|
2018
2121
|
const { db: db3, req, user } = context;
|
|
2122
|
+
if (user.super_admin === true) {
|
|
2123
|
+
return true;
|
|
2124
|
+
}
|
|
2125
|
+
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")) {
|
|
2126
|
+
console.error("Access control error: no role found for current user or no access to entity type.");
|
|
2127
|
+
throw new Error("Access control error: no role found for current user or no access to entity type.");
|
|
2128
|
+
}
|
|
2129
|
+
const hasRBAC = table.RBAC === true;
|
|
2130
|
+
if (!hasRBAC) {
|
|
2131
|
+
return true;
|
|
2132
|
+
}
|
|
2019
2133
|
const record = await db3.from(tableNamePlural).select(["rights_mode", "created_by"]).where({ id }).first();
|
|
2020
2134
|
if (!record) {
|
|
2021
2135
|
throw new Error("Record not found");
|
|
@@ -2025,17 +2139,6 @@ function createMutations(table) {
|
|
|
2025
2139
|
throw new Error("You are not authorized to edit this record");
|
|
2026
2140
|
}
|
|
2027
2141
|
}
|
|
2028
|
-
const hasRBAC = table.RBAC === true;
|
|
2029
|
-
if (!hasRBAC) {
|
|
2030
|
-
return true;
|
|
2031
|
-
}
|
|
2032
|
-
if (user.super_admin === true) {
|
|
2033
|
-
return true;
|
|
2034
|
-
}
|
|
2035
|
-
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")) {
|
|
2036
|
-
console.error("Access control error: no role found for current user or no access to entity type.");
|
|
2037
|
-
throw new Error("Access control error: no role found for current user or no access to entity type.");
|
|
2038
|
-
}
|
|
2039
2142
|
if (record.rights_mode === "public") {
|
|
2040
2143
|
return true;
|
|
2041
2144
|
}
|
|
@@ -2216,15 +2319,15 @@ function createMutations(table) {
|
|
|
2216
2319
|
var applyAccessControl = (table, user, query) => {
|
|
2217
2320
|
console.log("table", table);
|
|
2218
2321
|
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2219
|
-
|
|
2220
|
-
|
|
2322
|
+
if (!user.super_admin && table.name.plural === "jobs") {
|
|
2323
|
+
query = query.where("created_by", user.id);
|
|
2221
2324
|
return query;
|
|
2222
2325
|
}
|
|
2223
|
-
|
|
2326
|
+
const hasRBAC = table.RBAC === true;
|
|
2327
|
+
if (!hasRBAC) {
|
|
2224
2328
|
return query;
|
|
2225
2329
|
}
|
|
2226
|
-
if (table.name.plural
|
|
2227
|
-
query = query.where("created_by", user.id);
|
|
2330
|
+
if (table.name.plural !== "agent_sessions" && user.super_admin === true) {
|
|
2228
2331
|
return query;
|
|
2229
2332
|
}
|
|
2230
2333
|
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"))) {
|
|
@@ -2255,6 +2358,27 @@ var applyAccessControl = (table, user, query) => {
|
|
|
2255
2358
|
}
|
|
2256
2359
|
return query;
|
|
2257
2360
|
};
|
|
2361
|
+
var converOperatorToQuery = (query, fieldName, operators) => {
|
|
2362
|
+
if (operators.eq !== void 0) {
|
|
2363
|
+
query = query.where(fieldName, operators.eq);
|
|
2364
|
+
}
|
|
2365
|
+
if (operators.ne !== void 0) {
|
|
2366
|
+
query = query.whereRaw(`?? IS DISTINCT FROM ?`, [fieldName, operators.ne]);
|
|
2367
|
+
}
|
|
2368
|
+
if (operators.in !== void 0) {
|
|
2369
|
+
query = query.whereIn(fieldName, operators.in);
|
|
2370
|
+
}
|
|
2371
|
+
if (operators.contains !== void 0) {
|
|
2372
|
+
query = query.where(fieldName, "like", `%${operators.contains}%`);
|
|
2373
|
+
}
|
|
2374
|
+
if (operators.lte !== void 0) {
|
|
2375
|
+
query = query.where(fieldName, "<=", operators.lte);
|
|
2376
|
+
}
|
|
2377
|
+
if (operators.gte !== void 0) {
|
|
2378
|
+
query = query.where(fieldName, ">=", operators.gte);
|
|
2379
|
+
}
|
|
2380
|
+
return query;
|
|
2381
|
+
};
|
|
2258
2382
|
function createQueries(table) {
|
|
2259
2383
|
const tableNamePlural = table.name.plural.toLowerCase();
|
|
2260
2384
|
const tableNameSingular = table.name.singular.toLowerCase();
|
|
@@ -2262,18 +2386,19 @@ function createQueries(table) {
|
|
|
2262
2386
|
filters.forEach((filter) => {
|
|
2263
2387
|
Object.entries(filter).forEach(([fieldName, operators]) => {
|
|
2264
2388
|
if (operators) {
|
|
2265
|
-
if (operators.
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
}
|
|
2271
|
-
if (operators.in !== void 0) {
|
|
2272
|
-
query = query.whereIn(fieldName, operators.in);
|
|
2389
|
+
if (operators.and !== void 0) {
|
|
2390
|
+
console.log("operators.and", operators.and);
|
|
2391
|
+
operators.and.forEach((operator) => {
|
|
2392
|
+
query = converOperatorToQuery(query, fieldName, operator);
|
|
2393
|
+
});
|
|
2273
2394
|
}
|
|
2274
|
-
if (operators.
|
|
2275
|
-
|
|
2395
|
+
if (operators.or !== void 0) {
|
|
2396
|
+
operators.or.forEach((operator) => {
|
|
2397
|
+
query = converOperatorToQuery(query, fieldName, operator);
|
|
2398
|
+
});
|
|
2276
2399
|
}
|
|
2400
|
+
query = converOperatorToQuery(query, fieldName, operators);
|
|
2401
|
+
console.log("query", query);
|
|
2277
2402
|
}
|
|
2278
2403
|
});
|
|
2279
2404
|
});
|
|
@@ -2346,57 +2471,36 @@ function createQueries(table) {
|
|
|
2346
2471
|
query = applyFilters(query, filters);
|
|
2347
2472
|
query = applyAccessControl(table, context.user, query);
|
|
2348
2473
|
if (groupBy) {
|
|
2349
|
-
|
|
2474
|
+
query = query.select(groupBy).groupBy(groupBy);
|
|
2475
|
+
if (tableNamePlural === "tracking") {
|
|
2476
|
+
query = query.sum("total as count");
|
|
2477
|
+
} else {
|
|
2478
|
+
query = query.count("* as count");
|
|
2479
|
+
}
|
|
2480
|
+
const results = await query;
|
|
2481
|
+
console.log("!!! results !!!", results);
|
|
2350
2482
|
return results.map((r) => ({
|
|
2351
2483
|
group: r[groupBy],
|
|
2352
|
-
count: Number(r.count)
|
|
2484
|
+
count: r.count ? Number(r.count) : 0
|
|
2353
2485
|
}));
|
|
2354
2486
|
} else {
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
count
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
query = query.where("user", user);
|
|
2370
|
-
}
|
|
2371
|
-
if (agent) {
|
|
2372
|
-
query = query.where("agent", agent);
|
|
2373
|
-
}
|
|
2374
|
-
if (from) {
|
|
2375
|
-
query = query.where("createdAt", ">=", from);
|
|
2376
|
-
}
|
|
2377
|
-
if (to) {
|
|
2378
|
-
query = query.where("createdAt", "<=", to);
|
|
2487
|
+
if (tableNamePlural === "tracking") {
|
|
2488
|
+
query = query.sum("total as count");
|
|
2489
|
+
const [{ count }] = await query.sum("total as count");
|
|
2490
|
+
console.log("!!! count !!!", count);
|
|
2491
|
+
return [{
|
|
2492
|
+
group: "total",
|
|
2493
|
+
count: count ? Number(count) : 0
|
|
2494
|
+
}];
|
|
2495
|
+
} else {
|
|
2496
|
+
const [{ count }] = await query.count("* as count");
|
|
2497
|
+
return [{
|
|
2498
|
+
group: "total",
|
|
2499
|
+
count: count ? Number(count) : 0
|
|
2500
|
+
}];
|
|
2379
2501
|
}
|
|
2380
|
-
query = applyAccessControl(table, context.user, query);
|
|
2381
|
-
const runningQuery = query.clone().whereIn("status", ["active", "waiting", "delayed", "paused"]);
|
|
2382
|
-
const [{ runningCount }] = await runningQuery.count("* as runningCount");
|
|
2383
|
-
const erroredQuery = query.clone().whereIn("status", ["failed", "stuck"]);
|
|
2384
|
-
const [{ erroredCount }] = await erroredQuery.count("* as erroredCount");
|
|
2385
|
-
const completedQuery = query.clone().where("status", "completed");
|
|
2386
|
-
const [{ completedCount }] = await completedQuery.count("* as completedCount");
|
|
2387
|
-
const failedQuery = query.clone().where("status", "failed");
|
|
2388
|
-
const [{ failedCount }] = await failedQuery.count("* as failedCount");
|
|
2389
|
-
const durationQuery = query.clone().where("status", "completed").whereNotNull("duration").select(db3.raw('AVG("duration") as averageDuration'));
|
|
2390
|
-
const [{ averageDuration }] = await durationQuery;
|
|
2391
|
-
return {
|
|
2392
|
-
runningCount: Number(runningCount),
|
|
2393
|
-
erroredCount: Number(erroredCount),
|
|
2394
|
-
completedCount: Number(completedCount),
|
|
2395
|
-
failedCount: Number(failedCount),
|
|
2396
|
-
averageDuration: averageDuration ? Number(averageDuration) : 0
|
|
2397
|
-
};
|
|
2398
2502
|
}
|
|
2399
|
-
}
|
|
2503
|
+
}
|
|
2400
2504
|
};
|
|
2401
2505
|
}
|
|
2402
2506
|
var RBACResolver = async (db3, table, entityName, resourceId, rights_mode) => {
|
|
@@ -2416,6 +2520,16 @@ var RBACResolver = async (db3, table, entityName, resourceId, rights_mode) => {
|
|
|
2416
2520
|
};
|
|
2417
2521
|
};
|
|
2418
2522
|
function createSDL(tables) {
|
|
2523
|
+
tables.forEach((table) => {
|
|
2524
|
+
table.fields.push({
|
|
2525
|
+
name: "createdAt",
|
|
2526
|
+
type: "date"
|
|
2527
|
+
});
|
|
2528
|
+
table.fields.push({
|
|
2529
|
+
name: "updatedAt",
|
|
2530
|
+
type: "date"
|
|
2531
|
+
});
|
|
2532
|
+
});
|
|
2419
2533
|
console.log("[EXULU] Creating SDL");
|
|
2420
2534
|
let typeDefs = `
|
|
2421
2535
|
scalar JSON
|
|
@@ -2472,7 +2586,6 @@ function createSDL(tables) {
|
|
|
2472
2586
|
${tableNamePlural}Pagination(limit: Int, page: Int, filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingularUpperCaseFirst}PaginationResult
|
|
2473
2587
|
${tableNameSingular}One(filters: [Filter${tableNameSingularUpperCaseFirst}], sort: SortBy): ${tableNameSingular}
|
|
2474
2588
|
${tableNamePlural}Statistics(filters: [Filter${tableNameSingularUpperCaseFirst}], groupBy: String): [StatisticsResult]!
|
|
2475
|
-
${tableNamePlural === "jobs" ? `jobStatistics(user: ID, agent: String, from: String, to: String): JobStatistics` : ""}
|
|
2476
2589
|
`;
|
|
2477
2590
|
mutationDefs += `
|
|
2478
2591
|
${tableNamePlural}CreateOne(input: ${tableNameSingular}Input!): ${tableNameSingular}
|
|
@@ -2497,17 +2610,6 @@ type PageInfo {
|
|
|
2497
2610
|
hasNextPage: Boolean!
|
|
2498
2611
|
}
|
|
2499
2612
|
`;
|
|
2500
|
-
if (tableNamePlural === "jobs") {
|
|
2501
|
-
modelDefs += `
|
|
2502
|
-
type JobStatistics {
|
|
2503
|
-
runningCount: Int!
|
|
2504
|
-
erroredCount: Int!
|
|
2505
|
-
completedCount: Int!
|
|
2506
|
-
failedCount: Int!
|
|
2507
|
-
averageDuration: Float!
|
|
2508
|
-
}
|
|
2509
|
-
`;
|
|
2510
|
-
}
|
|
2511
2613
|
Object.assign(resolvers.Query, createQueries(table));
|
|
2512
2614
|
Object.assign(resolvers.Mutation, createMutations(table));
|
|
2513
2615
|
if (table.RBAC) {
|
|
@@ -2599,6 +2701,10 @@ var agentMessagesSchema = {
|
|
|
2599
2701
|
name: "title",
|
|
2600
2702
|
type: "text"
|
|
2601
2703
|
},
|
|
2704
|
+
{
|
|
2705
|
+
name: "user",
|
|
2706
|
+
type: "number"
|
|
2707
|
+
},
|
|
2602
2708
|
{
|
|
2603
2709
|
name: "session",
|
|
2604
2710
|
type: "text"
|
|
@@ -2835,6 +2941,10 @@ var rolesSchema = {
|
|
|
2835
2941
|
type: "text"
|
|
2836
2942
|
// write | read access to agents
|
|
2837
2943
|
},
|
|
2944
|
+
{
|
|
2945
|
+
name: "api",
|
|
2946
|
+
type: "text"
|
|
2947
|
+
},
|
|
2838
2948
|
{
|
|
2839
2949
|
name: "workflows",
|
|
2840
2950
|
type: "text"
|
|
@@ -2854,8 +2964,8 @@ var rolesSchema = {
|
|
|
2854
2964
|
};
|
|
2855
2965
|
var statisticsSchema = {
|
|
2856
2966
|
name: {
|
|
2857
|
-
plural: "
|
|
2858
|
-
singular: "
|
|
2967
|
+
plural: "tracking",
|
|
2968
|
+
singular: "tracking"
|
|
2859
2969
|
},
|
|
2860
2970
|
fields: [
|
|
2861
2971
|
{
|
|
@@ -2868,11 +2978,20 @@ var statisticsSchema = {
|
|
|
2868
2978
|
},
|
|
2869
2979
|
{
|
|
2870
2980
|
name: "type",
|
|
2871
|
-
type: "
|
|
2981
|
+
type: "enum",
|
|
2982
|
+
enumValues: Object.values(STATISTICS_TYPE_ENUM)
|
|
2872
2983
|
},
|
|
2873
2984
|
{
|
|
2874
2985
|
name: "total",
|
|
2875
2986
|
type: "number"
|
|
2987
|
+
},
|
|
2988
|
+
{
|
|
2989
|
+
name: "user",
|
|
2990
|
+
type: "number"
|
|
2991
|
+
},
|
|
2992
|
+
{
|
|
2993
|
+
name: "role",
|
|
2994
|
+
type: "uuid"
|
|
2876
2995
|
}
|
|
2877
2996
|
]
|
|
2878
2997
|
};
|
|
@@ -2933,6 +3052,7 @@ var jobsSchema = {
|
|
|
2933
3052
|
plural: "jobs",
|
|
2934
3053
|
singular: "job"
|
|
2935
3054
|
},
|
|
3055
|
+
RBAC: true,
|
|
2936
3056
|
fields: [
|
|
2937
3057
|
{
|
|
2938
3058
|
name: "redis",
|
|
@@ -2942,10 +3062,6 @@ var jobsSchema = {
|
|
|
2942
3062
|
name: "session",
|
|
2943
3063
|
type: "text"
|
|
2944
3064
|
},
|
|
2945
|
-
{
|
|
2946
|
-
name: "created_by",
|
|
2947
|
-
type: "number"
|
|
2948
|
-
},
|
|
2949
3065
|
{
|
|
2950
3066
|
name: "status",
|
|
2951
3067
|
type: "text"
|
|
@@ -3588,11 +3704,8 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
3588
3704
|
{ route: "/agents/:id", method: "GET", note: "Get specific agent" },
|
|
3589
3705
|
{ route: "/contexts", method: "GET", note: "List all contexts" },
|
|
3590
3706
|
{ route: "/contexts/:id", method: "GET", note: "Get specific context" },
|
|
3591
|
-
{ route: "/contexts/statistics", method: "GET", note: "Get context statistics" },
|
|
3592
3707
|
{ route: "/tools", method: "GET", note: "List all tools" },
|
|
3593
3708
|
{ route: "/tools/:id", method: "GET", note: "Get specific tool" },
|
|
3594
|
-
{ route: "/statistics/timeseries", method: "POST", note: "Get time series statistics" },
|
|
3595
|
-
{ route: "/statistics/totals", method: "POST", note: "Get totals statistics" },
|
|
3596
3709
|
{ route: "/items/:context", method: "POST", note: "Create new item in context" },
|
|
3597
3710
|
{ route: "/items/:context", method: "GET", note: "Get items from context" },
|
|
3598
3711
|
{ route: "/items/export/:context", method: "GET", note: "Export items from context" },
|
|
@@ -4125,115 +4238,6 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4125
4238
|
authenticated: true
|
|
4126
4239
|
});
|
|
4127
4240
|
});
|
|
4128
|
-
console.log("[EXULU] statistics timeseries");
|
|
4129
|
-
app.post("/statistics/timeseries", async (req, res) => {
|
|
4130
|
-
const authenticationResult = await requestValidators.authenticate(req);
|
|
4131
|
-
if (!authenticationResult.user?.id) {
|
|
4132
|
-
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4133
|
-
return;
|
|
4134
|
-
}
|
|
4135
|
-
const { db: db3 } = await postgresClient();
|
|
4136
|
-
const type = req.body.type;
|
|
4137
|
-
if (!Object.values(STATISTICS_TYPE_ENUM).includes(type)) {
|
|
4138
|
-
res.status(400).json({
|
|
4139
|
-
message: "Invalid type, must be one of: " + Object.values(STATISTICS_TYPE_ENUM).join(", ")
|
|
4140
|
-
});
|
|
4141
|
-
return;
|
|
4142
|
-
}
|
|
4143
|
-
let from = new Date(req.body.from);
|
|
4144
|
-
let to = new Date(req.body.to);
|
|
4145
|
-
if (!from || !to) {
|
|
4146
|
-
from = new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3);
|
|
4147
|
-
to = /* @__PURE__ */ new Date();
|
|
4148
|
-
}
|
|
4149
|
-
const query = db3.from("statistics").select("*");
|
|
4150
|
-
query.where("name", "count");
|
|
4151
|
-
query.andWhere("type", type);
|
|
4152
|
-
query.andWhere("createdAt", ">=", from);
|
|
4153
|
-
query.andWhere("createdAt", "<=", to);
|
|
4154
|
-
const results = await query;
|
|
4155
|
-
const dates = [];
|
|
4156
|
-
for (let i = 0; i < (to.getTime() - from.getTime()) / (1e3 * 60 * 60 * 24); i++) {
|
|
4157
|
-
dates.push(new Date(from.getTime() + i * (1e3 * 60 * 60 * 24)));
|
|
4158
|
-
}
|
|
4159
|
-
const data = dates.map((date) => {
|
|
4160
|
-
const result = results.find((result2) => result2.date === date);
|
|
4161
|
-
if (result) {
|
|
4162
|
-
return result;
|
|
4163
|
-
}
|
|
4164
|
-
return {
|
|
4165
|
-
date,
|
|
4166
|
-
count: 0
|
|
4167
|
-
};
|
|
4168
|
-
});
|
|
4169
|
-
res.status(200).json({
|
|
4170
|
-
data,
|
|
4171
|
-
filter: {
|
|
4172
|
-
from,
|
|
4173
|
-
to
|
|
4174
|
-
}
|
|
4175
|
-
});
|
|
4176
|
-
});
|
|
4177
|
-
console.log("[EXULU] statistics totals");
|
|
4178
|
-
app.post("/statistics/totals", async (req, res) => {
|
|
4179
|
-
const authenticationResult = await requestValidators.authenticate(req);
|
|
4180
|
-
if (!authenticationResult.user?.id) {
|
|
4181
|
-
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4182
|
-
return;
|
|
4183
|
-
}
|
|
4184
|
-
const { db: db3 } = await postgresClient();
|
|
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
|
-
let promises2 = Object.values(STATISTICS_TYPE_ENUM).map(async (type) => {
|
|
4192
|
-
const result = await db3.from("statistics").where("name", "count").andWhere("type", type).andWhere("createdAt", ">=", from).andWhere("createdAt", "<=", to).sum("total as total");
|
|
4193
|
-
return {
|
|
4194
|
-
[type]: result[0]?.total || 0
|
|
4195
|
-
};
|
|
4196
|
-
});
|
|
4197
|
-
const results = await Promise.all(promises2);
|
|
4198
|
-
res.status(200).json({
|
|
4199
|
-
data: { ...Object.assign({}, ...results) },
|
|
4200
|
-
filter: {
|
|
4201
|
-
from,
|
|
4202
|
-
to
|
|
4203
|
-
}
|
|
4204
|
-
});
|
|
4205
|
-
});
|
|
4206
|
-
console.log("[EXULU] contexts statistics");
|
|
4207
|
-
app.get("/contexts/statistics", async (req, res) => {
|
|
4208
|
-
const authenticationResult = await requestValidators.authenticate(req);
|
|
4209
|
-
if (!authenticationResult.user?.id) {
|
|
4210
|
-
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4211
|
-
return;
|
|
4212
|
-
}
|
|
4213
|
-
const { db: db3 } = await postgresClient();
|
|
4214
|
-
const statistics = await db3("statistics").where("name", "count").andWhere("type", "context.retrieve").sum("total as total").first();
|
|
4215
|
-
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) => ({
|
|
4216
|
-
jobs: rows
|
|
4217
|
-
}));
|
|
4218
|
-
let jobs = [];
|
|
4219
|
-
if (response[0]) {
|
|
4220
|
-
jobs = response[0].jobs.map((job) => ({
|
|
4221
|
-
date: job.id,
|
|
4222
|
-
count: job.count
|
|
4223
|
-
}));
|
|
4224
|
-
}
|
|
4225
|
-
const embeddingsCountResult = await db3("jobs").where("type", "embedder").count("* as count").first();
|
|
4226
|
-
res.status(200).json({
|
|
4227
|
-
active: contexts.filter((context) => context.active).length,
|
|
4228
|
-
inactive: contexts.filter((context) => !context.active).length,
|
|
4229
|
-
sources: contexts.reduce((acc, context) => acc + context.sources.get().length, 0),
|
|
4230
|
-
queries: statistics?.total || 0,
|
|
4231
|
-
jobs,
|
|
4232
|
-
totals: {
|
|
4233
|
-
embeddings: embeddingsCountResult?.count || 0
|
|
4234
|
-
}
|
|
4235
|
-
});
|
|
4236
|
-
});
|
|
4237
4241
|
console.log("[EXULU] context by id");
|
|
4238
4242
|
app.get(`/contexts/:id`, async (req, res) => {
|
|
4239
4243
|
const authenticationResult = await requestValidators.authenticate(req);
|
|
@@ -4404,7 +4408,11 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4404
4408
|
return;
|
|
4405
4409
|
}
|
|
4406
4410
|
}
|
|
4407
|
-
const
|
|
4411
|
+
const headers = {
|
|
4412
|
+
stream: req.headers["stream"] === "true" || false,
|
|
4413
|
+
user: req.headers["user"] || null,
|
|
4414
|
+
session: req.headers["session"] || null
|
|
4415
|
+
};
|
|
4408
4416
|
const requestValidationResult = requestValidators.agents(req);
|
|
4409
4417
|
if (requestValidationResult.error) {
|
|
4410
4418
|
res.status(requestValidationResult.code || 500).json({ detail: `${requestValidationResult.message}` });
|
|
@@ -4415,6 +4423,13 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4415
4423
|
res.status(authenticationResult.code || 500).json({ detail: `${authenticationResult.message}` });
|
|
4416
4424
|
return;
|
|
4417
4425
|
}
|
|
4426
|
+
const user = authenticationResult.user;
|
|
4427
|
+
if (user.type !== "api" && !user.super_admin && req.body.resourceId !== user.id) {
|
|
4428
|
+
res.status(400).json({
|
|
4429
|
+
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."
|
|
4430
|
+
});
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4418
4433
|
console.log("[EXULU] agent tools", agentInstance.tools);
|
|
4419
4434
|
const enabledTools = agentInstance.tools.map(({ config, toolId }) => tools.find(({ id }) => id === toolId)).filter(Boolean);
|
|
4420
4435
|
console.log("[EXULU] enabled tools", enabledTools);
|
|
@@ -4437,9 +4452,15 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4437
4452
|
const bytes = CryptoJS3.AES.decrypt(variable.value, process.env.NEXTAUTH_SECRET);
|
|
4438
4453
|
providerApiKey = bytes.toString(CryptoJS3.enc.Utf8);
|
|
4439
4454
|
}
|
|
4440
|
-
if (!!stream) {
|
|
4441
|
-
|
|
4442
|
-
|
|
4455
|
+
if (!!headers.stream) {
|
|
4456
|
+
await agent.generateStream({
|
|
4457
|
+
express: {
|
|
4458
|
+
res,
|
|
4459
|
+
req
|
|
4460
|
+
},
|
|
4461
|
+
user: headers.user,
|
|
4462
|
+
session: headers.session,
|
|
4463
|
+
message: req.body.message,
|
|
4443
4464
|
tools: enabledTools,
|
|
4444
4465
|
providerApiKey,
|
|
4445
4466
|
toolConfigs: agentInstance.tools,
|
|
@@ -4448,11 +4469,12 @@ var createExpressRoutes = async (app, agents, tools, contexts) => {
|
|
|
4448
4469
|
trigger: "agent"
|
|
4449
4470
|
}
|
|
4450
4471
|
});
|
|
4451
|
-
result.pipeDataStreamToResponse(res);
|
|
4452
4472
|
return;
|
|
4453
4473
|
} else {
|
|
4454
4474
|
const response = await agent.generateSync({
|
|
4455
|
-
|
|
4475
|
+
user: headers.user,
|
|
4476
|
+
session: headers.session,
|
|
4477
|
+
message: req.body.message,
|
|
4456
4478
|
tools: enabledTools.map((tool2) => tool2.tool),
|
|
4457
4479
|
providerApiKey,
|
|
4458
4480
|
toolConfigs: agentInstance.tools,
|
|
@@ -4977,7 +4999,6 @@ var defaultAgent = new ExuluAgent({
|
|
|
4977
4999
|
description: `Basic agent without any defined tools, that can support MCP's.`,
|
|
4978
5000
|
type: "agent",
|
|
4979
5001
|
capabilities: {
|
|
4980
|
-
tools: false,
|
|
4981
5002
|
images: [],
|
|
4982
5003
|
files: [],
|
|
4983
5004
|
audio: [],
|
|
@@ -4989,10 +5010,10 @@ var defaultAgent = new ExuluAgent({
|
|
|
4989
5010
|
instructions: "You are a helpful assistant.",
|
|
4990
5011
|
model: {
|
|
4991
5012
|
create: ({ apiKey }) => {
|
|
4992
|
-
const
|
|
5013
|
+
const anthropic = createAnthropic({
|
|
4993
5014
|
apiKey
|
|
4994
5015
|
});
|
|
4995
|
-
return
|
|
5016
|
+
return anthropic.languageModel("claude-4-opus-20250514");
|
|
4996
5017
|
}
|
|
4997
5018
|
// todo add a field of type string that adds a dropdown list from which the user can select the model
|
|
4998
5019
|
// todo for each model, check which provider is used, and require the admin to add one or multiple
|
|
@@ -6533,6 +6554,13 @@ var ExuluJobs = {
|
|
|
6533
6554
|
var db2 = {
|
|
6534
6555
|
init: async () => {
|
|
6535
6556
|
await execute();
|
|
6557
|
+
},
|
|
6558
|
+
api: {
|
|
6559
|
+
key: {
|
|
6560
|
+
generate: async (name, email) => {
|
|
6561
|
+
return await generateApiKey(name, email);
|
|
6562
|
+
}
|
|
6563
|
+
}
|
|
6536
6564
|
}
|
|
6537
6565
|
};
|
|
6538
6566
|
var ExuluChunkers = {
|