@exulu/backend 1.57.0 → 1.59.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/dist/catalog-EOKGOHTY.js +10 -0
- package/dist/chunk-U36VJDZ7.js +7210 -0
- package/dist/chunk-YS27XOXI.js +62 -0
- package/dist/convert-exulu-tools-to-ai-sdk-tools-ZEECMX43.js +6 -0
- package/dist/index.cjs +10841 -7188
- package/dist/index.d.cts +64 -18
- package/dist/index.d.ts +64 -18
- package/dist/index.js +3740 -7898
- package/ee/agentic-retrieval/v3/index.ts +1 -1
- package/ee/agentic-retrieval/v4/index.ts +1 -1
- package/ee/entitlements.ts +6 -3
- package/ee/invoke-skills/create-sandbox.ts +783 -32
- package/ee/python/.litellm/config.yaml.example +64 -0
- package/ee/python/documents/processing/doc_processor.ts +4 -5
- package/ee/python/requirements.txt +16 -0
- package/ee/python/setup.sh +13 -0
- package/ee/workers.ts +18 -29
- package/package.json +5 -3
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# LiteLLM Proxy configuration for Exulu.
|
|
2
|
+
#
|
|
3
|
+
# This file is read by the LiteLLM process Exulu spawns when EXULU_USE_LITELLM=true.
|
|
4
|
+
# Documentation: https://docs.litellm.ai/docs/proxy/configs
|
|
5
|
+
#
|
|
6
|
+
# To use:
|
|
7
|
+
# 1. Copy this file to config.yaml in the same directory.
|
|
8
|
+
# 2. Edit model_list to add the providers you want to expose.
|
|
9
|
+
# 3. Set the referenced env vars (LITELLM_MASTER_KEY, GOOGLE_VERTEX_PROJECT, etc.).
|
|
10
|
+
# 4. Set EXULU_USE_LITELLM=true and (re)start Exulu.
|
|
11
|
+
|
|
12
|
+
general_settings:
|
|
13
|
+
master_key: os.environ/LITELLM_MASTER_KEY
|
|
14
|
+
|
|
15
|
+
# Database mode (optional). Set `database_url` only if you want LiteLLM's
|
|
16
|
+
# user/key/budget/spend tracking tables. When set, LiteLLM creates ~60
|
|
17
|
+
# tables in the target database (all prefixed `LiteLLM_`).
|
|
18
|
+
#
|
|
19
|
+
# ⚠ ALWAYS use a DEDICATED Postgres database for LiteLLM — never share it
|
|
20
|
+
# with Exulu's main database. LiteLLM's schema sync drops any tables in
|
|
21
|
+
# the public schema that aren't part of its schema; sharing a database
|
|
22
|
+
# with Exulu has destroyed application data in the past.
|
|
23
|
+
#
|
|
24
|
+
# Exulu's ExuluDatabase.init runs `prisma db push` against this URL
|
|
25
|
+
# automatically at boot, but only after verifying:
|
|
26
|
+
# 1. database_url is NOT the same as Exulu's own Postgres (warns + skips)
|
|
27
|
+
# 2. the target database contains no non-LiteLLM_* tables (warns + skips)
|
|
28
|
+
# 3. the push itself runs without --accept-data-loss (Prisma refuses any
|
|
29
|
+
# schema change that would drop data)
|
|
30
|
+
# Re-running on an already-set-up database is a no-op.
|
|
31
|
+
#
|
|
32
|
+
# database_url: "postgresql://user:pass@host:5432/litellm_dedicated"
|
|
33
|
+
|
|
34
|
+
model_list:
|
|
35
|
+
# Each entry's `model_name` is what Exulu agents will reference in their
|
|
36
|
+
# `model` field after toggling LiteLLM on. Pick stable, human-friendly names.
|
|
37
|
+
|
|
38
|
+
- model_name: vertex-flash
|
|
39
|
+
litellm_params:
|
|
40
|
+
model: vertex_ai/gemini-2.5-flash
|
|
41
|
+
vertex_project: os.environ/GOOGLE_VERTEX_PROJECT
|
|
42
|
+
vertex_location: europe-west1
|
|
43
|
+
vertex_credentials: os.environ/GOOGLE_VERTEX_CREDENTIALS_JSON
|
|
44
|
+
|
|
45
|
+
- model_name: vertex-pro
|
|
46
|
+
litellm_params:
|
|
47
|
+
model: vertex_ai/gemini-2.5-pro
|
|
48
|
+
vertex_project: os.environ/GOOGLE_VERTEX_PROJECT
|
|
49
|
+
vertex_location: europe-west1
|
|
50
|
+
vertex_credentials: os.environ/GOOGLE_VERTEX_CREDENTIALS_JSON
|
|
51
|
+
|
|
52
|
+
- model_name: claude-haiku
|
|
53
|
+
litellm_params:
|
|
54
|
+
model: anthropic/claude-haiku-4-5
|
|
55
|
+
api_key: os.environ/ANTHROPIC_API_KEY
|
|
56
|
+
|
|
57
|
+
- model_name: gpt-5
|
|
58
|
+
litellm_params:
|
|
59
|
+
model: openai/gpt-5
|
|
60
|
+
api_key: os.environ/OPENAI_API_KEY
|
|
61
|
+
|
|
62
|
+
# Per-model rate limits and budgets are configured here in LiteLLM-native form.
|
|
63
|
+
# See https://docs.litellm.ai/docs/proxy/users for budget configuration and
|
|
64
|
+
# https://docs.litellm.ai/docs/proxy/rate_limit_tiers for rate limiting.
|
|
@@ -630,7 +630,7 @@ async function processDocument(
|
|
|
630
630
|
source: filePath,
|
|
631
631
|
}
|
|
632
632
|
|
|
633
|
-
const stripped = filePath.split('.').pop()?.trim();
|
|
633
|
+
const stripped = filePath.split('.').pop()?.trim().toLowerCase();
|
|
634
634
|
let result: ProcessorOutput;
|
|
635
635
|
switch (stripped) {
|
|
636
636
|
case 'txt':
|
|
@@ -1017,7 +1017,7 @@ export async function documentProcessor({
|
|
|
1017
1017
|
supportedTypes = ['pdf', 'docx', 'doc', 'txt', 'md', 'jpg', 'jpeg', 'png', 'gif', 'webp'];
|
|
1018
1018
|
break;
|
|
1019
1019
|
case "officeparser":
|
|
1020
|
-
supportedTypes = [];
|
|
1020
|
+
supportedTypes = ['docx', 'pptx', 'xlsx', 'odt', 'odp', 'ods', 'pdf', 'rtf', 'csv', 'md', 'html'];
|
|
1021
1021
|
break;
|
|
1022
1022
|
case "liteparse":
|
|
1023
1023
|
supportedTypes = ['pdf', 'doc', 'docx', 'docm', 'odt', 'rtf', 'ppt', 'pptx', 'pptm', 'odp', 'xls', 'xlsx', 'xlsm', 'ods', 'csv', 'tsv'];
|
|
@@ -1027,8 +1027,8 @@ export async function documentProcessor({
|
|
|
1027
1027
|
break;
|
|
1028
1028
|
}
|
|
1029
1029
|
|
|
1030
|
-
if (!supportedTypes.includes(fileType)) {
|
|
1031
|
-
throw new Error(`[EXULU] Unsupported file type: ${fileType} for Exulu document processor, the ${config?.processor.name} processor only supports the following file types: ${supportedTypes.join(', ')}.`);
|
|
1030
|
+
if (!supportedTypes.includes(fileType.toLowerCase())) {
|
|
1031
|
+
throw new Error(`[EXULU] Unsupported file type: ${fileType.toLowerCase()} for Exulu document processor, the ${config?.processor.name} processor only supports the following file types: ${supportedTypes.join(', ')}.`);
|
|
1032
1032
|
}
|
|
1033
1033
|
|
|
1034
1034
|
// Process document with VLM validation enabled
|
|
@@ -1043,7 +1043,6 @@ export async function documentProcessor({
|
|
|
1043
1043
|
|
|
1044
1044
|
return content.json;
|
|
1045
1045
|
|
|
1046
|
-
|
|
1047
1046
|
} catch (error) {
|
|
1048
1047
|
console.error('Error during chunking:', error);
|
|
1049
1048
|
throw error;
|
|
@@ -2,3 +2,19 @@ docling
|
|
|
2
2
|
transformers
|
|
3
3
|
pyinstaller
|
|
4
4
|
docling-hierarchical-pdf
|
|
5
|
+
defusedxml
|
|
6
|
+
# LiteLLM proxy — only used when EXULU_USE_LITELLM=true. Always installed so
|
|
7
|
+
# the dep is ready when the env var is flipped. Pinned to a tested version;
|
|
8
|
+
# upgrade deliberately.
|
|
9
|
+
litellm[proxy]==1.85.1
|
|
10
|
+
# Prisma Python client — required by LiteLLM proxy whenever a `database_url`
|
|
11
|
+
# is set in config.litellm.yaml (used for user/budget tracking, key
|
|
12
|
+
# management, etc.). NOT included in litellm[proxy] in 1.85.1, hence the
|
|
13
|
+
# separate pin. setup.sh runs `prisma generate` against LiteLLM's bundled
|
|
14
|
+
# schema after pip install so the Python client module is materialized.
|
|
15
|
+
prisma==0.15.0
|
|
16
|
+
# Vertex AI SDK — required by LiteLLM when routing to `vertex_ai/*` models
|
|
17
|
+
# (the `vertexai` Python module lives inside google-cloud-aiplatform).
|
|
18
|
+
# NOT included in litellm[proxy]; without it, requests to Vertex models
|
|
19
|
+
# fail with "No module named 'vertexai'".
|
|
20
|
+
google-cloud-aiplatform>=1.38
|
package/ee/python/setup.sh
CHANGED
|
@@ -203,6 +203,19 @@ pip install -r "$REQUIREMENTS_FILE"
|
|
|
203
203
|
|
|
204
204
|
print_success "All dependencies installed successfully"
|
|
205
205
|
|
|
206
|
+
# Step 6.5: Generate Prisma client for LiteLLM database mode.
|
|
207
|
+
# LiteLLM's PrismaClient does `from prisma import Prisma`, which only works
|
|
208
|
+
# after `prisma generate` has materialized the Python client against
|
|
209
|
+
# LiteLLM's bundled schema. Skip silently if LiteLLM isn't installed or its
|
|
210
|
+
# schema isn't where we expect — database mode is opt-in via config.litellm.yaml.
|
|
211
|
+
LITELLM_PROXY_DIR=$(find "$VENV_DIR/lib" -path "*/litellm/proxy" -type d 2>/dev/null | head -1)
|
|
212
|
+
if [ -n "$LITELLM_PROXY_DIR" ] && [ -f "$LITELLM_PROXY_DIR/schema.prisma" ]; then
|
|
213
|
+
print_info "Generating Prisma client for LiteLLM..."
|
|
214
|
+
(cd "$LITELLM_PROXY_DIR" && PATH="$VENV_DIR/bin:$PATH" "$VENV_DIR/bin/prisma" generate > /dev/null 2>&1) \
|
|
215
|
+
&& print_success "Prisma client generated for LiteLLM" \
|
|
216
|
+
|| print_warning "Prisma generate failed; LiteLLM database mode (database_url in config.litellm.yaml) may not work until you run 'cd $LITELLM_PROXY_DIR && PATH=$VENV_DIR/bin:\$PATH $VENV_DIR/bin/prisma generate'"
|
|
217
|
+
fi
|
|
218
|
+
|
|
206
219
|
# Step 7: Validate installation
|
|
207
220
|
echo ""
|
|
208
221
|
echo "Step 7: Validating installation..."
|
package/ee/workers.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { getTableName, type ExuluContext } from "@SRC/exulu/context.ts";
|
|
|
10
10
|
import type { ExuluReranker } from "@SRC/exulu/reranker.ts";
|
|
11
11
|
import type { ExuluEval } from "@SRC/exulu/evals.ts";
|
|
12
12
|
import type { ExuluTool } from "@SRC/exulu/tool.ts";
|
|
13
|
+
import { resolveModel } from "@SRC/exulu/resolve-model.ts";
|
|
13
14
|
import { postgresClient } from "@SRC/postgres/client";
|
|
14
15
|
import type { BullMqJobData } from "@EE/queues/decorator.ts";
|
|
15
16
|
import { type Tracer } from "@opentelemetry/api";
|
|
@@ -405,6 +406,9 @@ export const createWorkers = async (
|
|
|
405
406
|
// not part of the database, so remove it here before
|
|
406
407
|
// we upadte the item in the db.
|
|
407
408
|
delete processorResult.field;
|
|
409
|
+
// fts is a generated column (tsvector GENERATED ALWAYS AS ... STORED)
|
|
410
|
+
// and Postgres rejects any explicit update to it.
|
|
411
|
+
delete processorResult.fts;
|
|
408
412
|
|
|
409
413
|
// Memory optimization: For large processor results (e.g., documents),
|
|
410
414
|
// extract only the fields we need for the database update to avoid
|
|
@@ -1376,37 +1380,21 @@ export const processUiMessagesFlow = async ({
|
|
|
1376
1380
|
enabledTools?.map((x) => x.name + " (" + x.id + ")"),
|
|
1377
1381
|
);
|
|
1378
1382
|
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
const { db } = await postgresClient();
|
|
1384
|
-
|
|
1385
|
-
let providerapikey: string | undefined;
|
|
1386
|
-
|
|
1387
|
-
if (variableName) {
|
|
1388
|
-
const variable = await db.from("variables").where({ name: variableName }).first();
|
|
1389
|
-
if (!variable) {
|
|
1390
|
-
throw new Error(
|
|
1391
|
-
`Provider API key variable not found for agent ${agent.name} (${agent.id}).`,
|
|
1392
|
-
);
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
// Get the API key from the variable (decrypt if encrypted)
|
|
1396
|
-
providerapikey = variable.value;
|
|
1397
|
-
|
|
1398
|
-
if (!variable.encrypted) {
|
|
1399
|
-
throw new Error(
|
|
1400
|
-
`Provider API key variable not encrypted for agent ${agent.name} (${agent.id}), for security reasons you are only allowed to use encrypted variables for provider API keys.`,
|
|
1401
|
-
);
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
if (variable.encrypted) {
|
|
1405
|
-
const bytes = CryptoJS.AES.decrypt(variable.value, process.env.NEXTAUTH_SECRET);
|
|
1406
|
-
providerapikey = bytes.toString(CryptoJS.enc.Utf8);
|
|
1407
|
-
}
|
|
1383
|
+
if (!agent.model) {
|
|
1384
|
+
throw new Error(
|
|
1385
|
+
`Agent ${agent.name} (${agent.id}) has no model configured.`,
|
|
1386
|
+
);
|
|
1408
1387
|
}
|
|
1409
1388
|
|
|
1389
|
+
const resolved = await resolveModel({
|
|
1390
|
+
modelId: agent.model,
|
|
1391
|
+
user,
|
|
1392
|
+
providers,
|
|
1393
|
+
agent: { id: agent.id },
|
|
1394
|
+
});
|
|
1395
|
+
const providerapikey = resolved.apiKey;
|
|
1396
|
+
const resolvedLanguageModel = resolved.languageModel;
|
|
1397
|
+
|
|
1410
1398
|
// Remove placeholder agent response before sending
|
|
1411
1399
|
const messagesWithoutPlaceholder = inputMessages.filter(
|
|
1412
1400
|
(message) => (message.metadata as any)?.type !== "placeholder",
|
|
@@ -1509,6 +1497,7 @@ export const processUiMessagesFlow = async ({
|
|
|
1509
1497
|
message: currentMessage,
|
|
1510
1498
|
currentTools: enabledTools,
|
|
1511
1499
|
allExuluTools: tools,
|
|
1500
|
+
languageModel: resolvedLanguageModel,
|
|
1512
1501
|
providerapikey,
|
|
1513
1502
|
toolConfigs: agent.tools,
|
|
1514
1503
|
exuluConfig: config,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exulu/backend",
|
|
3
3
|
"author": "Qventu Bv.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.59.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"private": false,
|
|
7
7
|
"publishConfig": {
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"@types/express": "^5.0.1",
|
|
64
64
|
"@types/graphql-type-json": "^0.3.5",
|
|
65
65
|
"@types/jest": "^29.5.14",
|
|
66
|
+
"@types/multer": "^2.1.0",
|
|
66
67
|
"@types/node": "^22.14.0",
|
|
67
68
|
"@types/pg": "^8.15.1",
|
|
68
69
|
"@types/supertest": "^6.0.2",
|
|
@@ -88,8 +89,8 @@
|
|
|
88
89
|
"dependencies": {
|
|
89
90
|
"@ai-sdk/anthropic": "^3.0.23",
|
|
90
91
|
"@ai-sdk/azure": "^3.0.53",
|
|
91
|
-
"@ai-sdk/cerebras": "^2.0.
|
|
92
|
-
"@ai-sdk/google-vertex": "^4.0.
|
|
92
|
+
"@ai-sdk/cerebras": "^2.0.51",
|
|
93
|
+
"@ai-sdk/google-vertex": "^4.0.136",
|
|
93
94
|
"@ai-sdk/openai": "^3.0.18",
|
|
94
95
|
"@ai-sdk/openai-compatible": "^2.0.37",
|
|
95
96
|
"@anthropic-ai/sandbox-runtime": "^0.0.49",
|
|
@@ -139,6 +140,7 @@
|
|
|
139
140
|
"knex": "^3.1.0",
|
|
140
141
|
"link": "^2.1.1",
|
|
141
142
|
"mammoth": "^1.11.0",
|
|
143
|
+
"multer": "^2.1.1",
|
|
142
144
|
"natural": "^8.1.0",
|
|
143
145
|
"nodemailer": "^8.0.7",
|
|
144
146
|
"officeparser": "^5.2.2",
|