@exulu/backend 1.61.3 → 1.62.1

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.
@@ -220,7 +220,8 @@ import { resolve } from "path";
220
220
  var MAX_CRASHES = 5;
221
221
  var INITIAL_BACKOFF_MS = 1e3;
222
222
  var MAX_BACKOFF_MS = 3e4;
223
- var READY_TIMEOUT_MS = 3e4;
223
+ var READY_TIMEOUT_MS = 9e4;
224
+ var WAIT_TIMEOUT_MS = 6e4;
224
225
  var READY_POLL_INTERVAL_MS = 200;
225
226
  var SHUTDOWN_GRACE_MS = 5e3;
226
227
  var internal = {
@@ -236,7 +237,7 @@ var resolveConfig = (packageRoot) => {
236
237
  const host = process.env.LITELLM_HOST ?? "127.0.0.1";
237
238
  const port = process.env.LITELLM_PORT ?? "4000";
238
239
  const masterKey = process.env.LITELLM_MASTER_KEY;
239
- const configPath = process.env.LITELLM_CONFIG_PATH ?? resolve(packageRoot, "./config.litellm.yaml");
240
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? resolve(process.cwd(), "./config.litellm.yaml");
240
241
  const venvBin = resolve(packageRoot, "ee/python/.venv/bin");
241
242
  const venvPython = resolve(venvBin, "python");
242
243
  const litellmBin = resolve(venvBin, "litellm");
@@ -263,7 +264,13 @@ var spawnLiteLLM = (cfg) => {
263
264
  `Spawning LiteLLM: ${cfg.litellmBin} --config ${cfg.configPath} --port ${cfg.port} --host ${cfg.host}`
264
265
  );
265
266
  const { DEBUG: _debug, ...rest } = process.env;
266
- const childEnv = { ...rest, DEBUG: "false" };
267
+ const childEnv = {
268
+ ...rest,
269
+ DEBUG: "false"
270
+ };
271
+ if (process.env.EXULU_LITELLM_UI_PATH && !process.env.SERVER_ROOT_PATH) {
272
+ childEnv.SERVER_ROOT_PATH = process.env.EXULU_LITELLM_UI_PATH;
273
+ }
267
274
  const child = spawn(
268
275
  cfg.litellmBin,
269
276
  [
@@ -388,10 +395,18 @@ var startLiteLLMSupervisor = async (options = {}) => {
388
395
  var waitForLiteLLMReady = async () => {
389
396
  if (!isLiteLLMEnabled()) return;
390
397
  if (!internal.readyPromise) {
391
- await startLiteLLMSupervisor();
392
- return;
398
+ return startLiteLLMSupervisor();
393
399
  }
394
- return internal.readyPromise;
400
+ const deadline = Date.now() + WAIT_TIMEOUT_MS;
401
+ while (Date.now() < deadline) {
402
+ const s = getSupervisorState();
403
+ if (s === "ready") return;
404
+ if (s === "given_up") {
405
+ throw new Error("LiteLLM supervisor has given up.");
406
+ }
407
+ await new Promise((r) => setTimeout(r, READY_POLL_INTERVAL_MS));
408
+ }
409
+ throw new Error("Timed out waiting for LiteLLM to become ready.");
395
410
  };
396
411
  var stopLiteLLM = (signal = "SIGTERM") => {
397
412
  internal.shutdownRequested = true;
@@ -418,6 +433,7 @@ var registerShutdownHandlers = () => {
418
433
  process.on("SIGTERM", () => stopLiteLLM("SIGTERM"));
419
434
  process.on("exit", () => stopLiteLLM("SIGTERM"));
420
435
  };
436
+ var getSupervisorState = () => internal.state;
421
437
 
422
438
  // src/exulu/tags.ts
423
439
  var MAX_LEN = 63;
@@ -577,7 +593,17 @@ var getLiteLLMProvider = ({
577
593
  name: "litellm",
578
594
  baseURL: `http://${host}:${port}/v1`,
579
595
  apiKey: masterKey,
580
- fetch: createTaggedFetch(tags)
596
+ fetch: createTaggedFetch(tags),
597
+ // Without this flag the openai-compatible provider strips any
598
+ // responseFormat.schema before sending and warns
599
+ // "JSON response format schema is only supported with structuredOutputs".
600
+ // Models then return free-form JSON that fails Zod parsing in callers
601
+ // using `Output.object({ schema })`. LiteLLM forwards
602
+ // `response_format: { type: "json_schema", ... }` to every upstream it
603
+ // supports — including Vertex Gemini, which translates it into
604
+ // responseSchema/responseMimeType — so enabling this matches the actual
605
+ // proxy contract.
606
+ supportsStructuredOutputs: true
581
607
  });
582
608
  return _litellmProvider;
583
609
  };
@@ -744,7 +770,7 @@ var ExuluTool = class {
744
770
  });
745
771
  providerapikey = resolved.apiKey;
746
772
  }
747
- const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-VRZ45OGI.js");
773
+ const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-FZ4ZCVBZ.js");
748
774
  const tools = await convertExuluToolsToAiSdkTools2(
749
775
  [this],
750
776
  [],
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  convertExuluToolsToAiSdkTools
3
- } from "./chunk-PFKAWGB6.js";
3
+ } from "./chunk-4TCN467I.js";
4
4
  export {
5
5
  convertExuluToolsToAiSdkTools
6
6
  };
package/dist/index.cjs CHANGED
@@ -376,7 +376,7 @@ var init_statistics = __esm({
376
376
  });
377
377
 
378
378
  // src/exulu/litellm/supervisor.ts
379
- var import_node_child_process, import_node_fs, import_node_path, MAX_CRASHES, INITIAL_BACKOFF_MS, MAX_BACKOFF_MS, READY_TIMEOUT_MS, READY_POLL_INTERVAL_MS, SHUTDOWN_GRACE_MS, internal, isLiteLLMEnabled, resolveConfig, log, pollHealth, spawnLiteLLM, supervise, _packageRoot, setLiteLLMPackageRoot, startLiteLLMSupervisor, waitForLiteLLMReady, stopLiteLLM, shutdownHandlersRegistered, registerShutdownHandlers;
379
+ var import_node_child_process, import_node_fs, import_node_path, MAX_CRASHES, INITIAL_BACKOFF_MS, MAX_BACKOFF_MS, READY_TIMEOUT_MS, WAIT_TIMEOUT_MS, READY_POLL_INTERVAL_MS, SHUTDOWN_GRACE_MS, internal, isLiteLLMEnabled, resolveConfig, log, pollHealth, spawnLiteLLM, supervise, _packageRoot, setLiteLLMPackageRoot, startLiteLLMSupervisor, waitForLiteLLMReady, stopLiteLLM, shutdownHandlersRegistered, registerShutdownHandlers, getSupervisorState;
380
380
  var init_supervisor = __esm({
381
381
  "src/exulu/litellm/supervisor.ts"() {
382
382
  "use strict";
@@ -387,7 +387,8 @@ var init_supervisor = __esm({
387
387
  MAX_CRASHES = 5;
388
388
  INITIAL_BACKOFF_MS = 1e3;
389
389
  MAX_BACKOFF_MS = 3e4;
390
- READY_TIMEOUT_MS = 3e4;
390
+ READY_TIMEOUT_MS = 9e4;
391
+ WAIT_TIMEOUT_MS = 6e4;
391
392
  READY_POLL_INTERVAL_MS = 200;
392
393
  SHUTDOWN_GRACE_MS = 5e3;
393
394
  internal = {
@@ -403,7 +404,7 @@ var init_supervisor = __esm({
403
404
  const host = process.env.LITELLM_HOST ?? "127.0.0.1";
404
405
  const port = process.env.LITELLM_PORT ?? "4000";
405
406
  const masterKey = process.env.LITELLM_MASTER_KEY;
406
- const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path.resolve)(packageRoot, "./config.litellm.yaml");
407
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path.resolve)(process.cwd(), "./config.litellm.yaml");
407
408
  const venvBin = (0, import_node_path.resolve)(packageRoot, "ee/python/.venv/bin");
408
409
  const venvPython = (0, import_node_path.resolve)(venvBin, "python");
409
410
  const litellmBin = (0, import_node_path.resolve)(venvBin, "litellm");
@@ -430,7 +431,13 @@ var init_supervisor = __esm({
430
431
  `Spawning LiteLLM: ${cfg.litellmBin} --config ${cfg.configPath} --port ${cfg.port} --host ${cfg.host}`
431
432
  );
432
433
  const { DEBUG: _debug, ...rest } = process.env;
433
- const childEnv = { ...rest, DEBUG: "false" };
434
+ const childEnv = {
435
+ ...rest,
436
+ DEBUG: "false"
437
+ };
438
+ if (process.env.EXULU_LITELLM_UI_PATH && !process.env.SERVER_ROOT_PATH) {
439
+ childEnv.SERVER_ROOT_PATH = process.env.EXULU_LITELLM_UI_PATH;
440
+ }
434
441
  const child = (0, import_node_child_process.spawn)(
435
442
  cfg.litellmBin,
436
443
  [
@@ -554,10 +561,18 @@ var init_supervisor = __esm({
554
561
  waitForLiteLLMReady = async () => {
555
562
  if (!isLiteLLMEnabled()) return;
556
563
  if (!internal.readyPromise) {
557
- await startLiteLLMSupervisor();
558
- return;
564
+ return startLiteLLMSupervisor();
559
565
  }
560
- return internal.readyPromise;
566
+ const deadline = Date.now() + WAIT_TIMEOUT_MS;
567
+ while (Date.now() < deadline) {
568
+ const s = getSupervisorState();
569
+ if (s === "ready") return;
570
+ if (s === "given_up") {
571
+ throw new Error("LiteLLM supervisor has given up.");
572
+ }
573
+ await new Promise((r) => setTimeout(r, READY_POLL_INTERVAL_MS));
574
+ }
575
+ throw new Error("Timed out waiting for LiteLLM to become ready.");
561
576
  };
562
577
  stopLiteLLM = (signal = "SIGTERM") => {
563
578
  internal.shutdownRequested = true;
@@ -584,6 +599,7 @@ var init_supervisor = __esm({
584
599
  process.on("SIGTERM", () => stopLiteLLM("SIGTERM"));
585
600
  process.on("exit", () => stopLiteLLM("SIGTERM"));
586
601
  };
602
+ getSupervisorState = () => internal.state;
587
603
  }
588
604
  });
589
605
 
@@ -1002,7 +1018,17 @@ var init_resolve_model = __esm({
1002
1018
  name: "litellm",
1003
1019
  baseURL: `http://${host}:${port}/v1`,
1004
1020
  apiKey: masterKey,
1005
- fetch: createTaggedFetch(tags)
1021
+ fetch: createTaggedFetch(tags),
1022
+ // Without this flag the openai-compatible provider strips any
1023
+ // responseFormat.schema before sending and warns
1024
+ // "JSON response format schema is only supported with structuredOutputs".
1025
+ // Models then return free-form JSON that fails Zod parsing in callers
1026
+ // using `Output.object({ schema })`. LiteLLM forwards
1027
+ // `response_format: { type: "json_schema", ... }` to every upstream it
1028
+ // supports — including Vertex Gemini, which translates it into
1029
+ // responseSchema/responseMimeType — so enabling this matches the actual
1030
+ // proxy contract.
1031
+ supportsStructuredOutputs: true
1006
1032
  });
1007
1033
  return _litellmProvider;
1008
1034
  };
@@ -13034,30 +13060,6 @@ type LiteLLMModel {
13034
13060
  pageInfo: PageInfo!
13035
13061
  }
13036
13062
  `;
13037
- typeDefs += `
13038
- agentWorldAgents: [AgentWorldAgent!]!
13039
- `;
13040
- resolvers.Query["agentWorldAgents"] = async (_, _args, context) => {
13041
- const { db: db2 } = context;
13042
- const sessions = await db2("agent_sessions as s").select([
13043
- "s.id as sessionId",
13044
- "s.agent as agentId",
13045
- "s.currenttask as currentTask",
13046
- "s.createdAt as lastActivityAt",
13047
- "s.created_by as userId"
13048
- ]).whereNotNull("s.currenttask").limit(20).orderBy("s.createdAt", "desc");
13049
- return sessions.map((row) => {
13050
- const agent = providers.find((p) => p.id === row.agentId);
13051
- return {
13052
- sessionId: row.sessionId,
13053
- agentId: row.agentId ?? "",
13054
- agentName: agent?.name ?? row.agentId ?? "Agent",
13055
- agentImage: agent?.image ?? null,
13056
- currentTask: row.currentTask,
13057
- lastActivityAt: row.lastActivityAt
13058
- };
13059
- });
13060
- };
13061
13063
  typeDefs += "}\n";
13062
13064
  mutationDefs += "}\n";
13063
13065
  const genericTypes = `
@@ -13272,15 +13274,6 @@ type StatisticsResult {
13272
13274
  group: String!
13273
13275
  count: Int!
13274
13276
  }
13275
-
13276
- type AgentWorldAgent {
13277
- sessionId: ID!
13278
- agentId: ID!
13279
- agentName: String!
13280
- agentImage: String
13281
- currentTask: String
13282
- lastActivityAt: String
13283
- }
13284
13277
  `;
13285
13278
  const fullSDL = typeDefs + mutationDefs + modelDefs + genericTypes;
13286
13279
  const schema = (0, import_schema.makeExecutableSchema)({
@@ -13491,7 +13484,7 @@ var import_utils5 = require("@apollo/utils.keyvaluecache");
13491
13484
  var import_body_parser = __toESM(require("body-parser"), 1);
13492
13485
  var import_crypto_js8 = __toESM(require("crypto-js"), 1);
13493
13486
  var import_openai = __toESM(require("openai"), 1);
13494
- var import_fs4 = __toESM(require("fs"), 1);
13487
+ var import_fs3 = __toESM(require("fs"), 1);
13495
13488
  var import_node_crypto5 = require("crypto");
13496
13489
  var import_api2 = require("@opentelemetry/api");
13497
13490
  init_check_record_access();
@@ -13574,7 +13567,7 @@ async function clearSessionCurrentTask(session) {
13574
13567
  }
13575
13568
 
13576
13569
  // src/exulu/provider.ts
13577
- var import_fs2 = __toESM(require("fs"), 1);
13570
+ var import_fs2 = require("fs");
13578
13571
  var ExuluProvider = class {
13579
13572
  // Must begin with a letter (a-z) or underscore (_). Subsequent characters in a name can be letters, digits (0-9), or
13580
13573
  // underscores and be a max length of 80 characters and at least 5 characters long.
@@ -14237,7 +14230,6 @@ ${extractedText}
14237
14230
  // todo make this configurable?
14238
14231
  page: 1
14239
14232
  });
14240
- import_fs2.default.writeFileSync("pre-fetched-relevant-information.json", JSON.stringify(result2, null, 2));
14241
14233
  if (result2?.chunks?.length) {
14242
14234
  memoryItems = result2.chunks;
14243
14235
  memoryContext = `
@@ -14888,212 +14880,6 @@ See docs/superpowers/specs/2026-05-31-in-chat-image-generation-design.md for the
14888
14880
 
14889
14881
  // src/exulu/routes.ts
14890
14882
  var import_node_path5 = require("path");
14891
-
14892
- // src/utils/python-setup.ts
14893
- init_cjs_shims();
14894
- var import_child_process = require("child_process");
14895
- var import_util = require("util");
14896
- var import_path = require("path");
14897
- var import_fs3 = require("fs");
14898
- var import_url = require("url");
14899
- var execAsync4 = (0, import_util.promisify)(import_child_process.exec);
14900
- function getPackageRoot() {
14901
- const currentFile = (0, import_url.fileURLToPath)(importMetaUrl);
14902
- let currentDir = (0, import_path.dirname)(currentFile);
14903
- let attempts = 0;
14904
- const maxAttempts = 10;
14905
- while (attempts < maxAttempts) {
14906
- const packageJsonPath = (0, import_path.join)(currentDir, "package.json");
14907
- if ((0, import_fs3.existsSync)(packageJsonPath)) {
14908
- try {
14909
- const packageJson = JSON.parse((0, import_fs3.readFileSync)(packageJsonPath, "utf-8"));
14910
- if (packageJson.name === "@exulu/backend") {
14911
- return currentDir;
14912
- }
14913
- } catch {
14914
- }
14915
- }
14916
- const parentDir = (0, import_path.resolve)(currentDir, "..");
14917
- if (parentDir === currentDir) {
14918
- break;
14919
- }
14920
- currentDir = parentDir;
14921
- attempts++;
14922
- }
14923
- const fallback = (0, import_path.resolve)((0, import_path.dirname)((0, import_url.fileURLToPath)(importMetaUrl)), "../..");
14924
- return fallback;
14925
- }
14926
- function getSetupScriptPath(packageRoot) {
14927
- return (0, import_path.resolve)(packageRoot, "ee/python/setup.sh");
14928
- }
14929
- function getVenvPath(packageRoot) {
14930
- return (0, import_path.resolve)(packageRoot, "ee/python/.venv");
14931
- }
14932
- function isPythonEnvironmentSetup(packageRoot) {
14933
- const root = packageRoot ?? getPackageRoot();
14934
- const venvPath = getVenvPath(root);
14935
- const pythonPath = (0, import_path.join)(venvPath, "bin", "python");
14936
- return (0, import_fs3.existsSync)(venvPath) && (0, import_fs3.existsSync)(pythonPath);
14937
- }
14938
- async function setupPythonEnvironment(options = {}) {
14939
- const {
14940
- packageRoot = getPackageRoot(),
14941
- force = false,
14942
- verbose = false,
14943
- timeout = 6e5
14944
- // 10 minutes
14945
- } = options;
14946
- if (!force && isPythonEnvironmentSetup(packageRoot)) {
14947
- if (verbose) {
14948
- console.log("\u2713 Python environment already set up");
14949
- }
14950
- return {
14951
- success: true,
14952
- message: "Python environment already exists",
14953
- alreadyExists: true
14954
- };
14955
- }
14956
- const setupScriptPath = getSetupScriptPath(packageRoot);
14957
- if (!(0, import_fs3.existsSync)(setupScriptPath)) {
14958
- return {
14959
- success: false,
14960
- message: `Setup script not found at: ${setupScriptPath}`,
14961
- alreadyExists: false
14962
- };
14963
- }
14964
- try {
14965
- if (verbose) {
14966
- console.log("Setting up Python environment...");
14967
- }
14968
- const { stdout, stderr } = await execAsync4(`bash "${setupScriptPath}"`, {
14969
- cwd: packageRoot,
14970
- timeout,
14971
- env: {
14972
- ...process.env,
14973
- // Ensure script can write to the directory
14974
- PYTHONDONTWRITEBYTECODE: "1"
14975
- },
14976
- maxBuffer: 10 * 1024 * 1024
14977
- // 10MB buffer
14978
- });
14979
- const output = stdout + stderr;
14980
- const versionMatch = output.match(/Python (\d+\.\d+\.\d+)/);
14981
- const pythonVersion = versionMatch ? versionMatch[1] : void 0;
14982
- if (verbose) {
14983
- console.log(output);
14984
- }
14985
- return {
14986
- success: true,
14987
- message: "Python environment set up successfully",
14988
- alreadyExists: false,
14989
- pythonVersion,
14990
- output
14991
- };
14992
- } catch (error) {
14993
- const errorOutput = error.stdout + error.stderr;
14994
- return {
14995
- success: false,
14996
- message: `Setup failed: ${error.message}`,
14997
- alreadyExists: false,
14998
- output: errorOutput
14999
- };
15000
- }
15001
- }
15002
- function getPythonSetupInstructions() {
15003
- return `
15004
- Python environment not set up. Please run one of the following commands:
15005
-
15006
- Option 1 (Automatic):
15007
- import { setupPythonEnvironment } from '@exulu/backend';
15008
- await setupPythonEnvironment();
15009
-
15010
- Option 2 (Manual - for package consumers):
15011
- npx @exulu/backend setup-python
15012
-
15013
- Option 3 (Manual - for contributors):
15014
- npm run python:setup
15015
-
15016
- These commands will automatically create a Python virtual environment (.venv)
15017
- in the @exulu/backend package and install all required dependencies.
15018
-
15019
- Requirements:
15020
- - Python 3.10 or higher must be installed
15021
- - pip must be available
15022
- - venv module must be available (for creating virtual environments)
15023
-
15024
- If Python dependencies are not installed, install them first, then run one of the commands above:
15025
- - macOS: brew install python@3.12
15026
- - Ubuntu/Debian: sudo apt-get install python3.12 python3-pip python3-venv
15027
- - Alpine Linux: apk add python3 py3-pip python3-dev
15028
- - Windows: Download from https://www.python.org/downloads/
15029
-
15030
- Note: In Docker containers, ensure you install all three components:
15031
- Ubuntu/Debian: apt-get install -y python3 python3-pip python3-venv
15032
- Alpine: apk add python3 py3-pip python3-dev
15033
- `.trim();
15034
- }
15035
- async function validatePythonEnvironment(packageRoot, checkPackages = true) {
15036
- const root = packageRoot ?? getPackageRoot();
15037
- const venvPath = getVenvPath(root);
15038
- const pythonPath = (0, import_path.join)(venvPath, "bin", "python");
15039
- if (!(0, import_fs3.existsSync)(venvPath)) {
15040
- return {
15041
- valid: false,
15042
- message: getPythonSetupInstructions()
15043
- };
15044
- }
15045
- if (!(0, import_fs3.existsSync)(pythonPath)) {
15046
- return {
15047
- valid: false,
15048
- message: "Python virtual environment is corrupted. Please run:\n await setupPythonEnvironment({ force: true })"
15049
- };
15050
- }
15051
- try {
15052
- await execAsync4(`"${pythonPath}" --version`, { cwd: root });
15053
- } catch {
15054
- return {
15055
- valid: false,
15056
- message: "Python executable is not working. Please run:\n await setupPythonEnvironment({ force: true })"
15057
- };
15058
- }
15059
- if (checkPackages) {
15060
- const criticalPackages = ["docling", "transformers"];
15061
- const missingPackages = [];
15062
- for (const pkg of criticalPackages) {
15063
- try {
15064
- await execAsync4(`"${pythonPath}" -c "import ${pkg}"`, {
15065
- cwd: root,
15066
- timeout: 1e4
15067
- // 10 second timeout per import check
15068
- });
15069
- } catch {
15070
- missingPackages.push(pkg);
15071
- }
15072
- }
15073
- if (missingPackages.length > 0) {
15074
- return {
15075
- valid: false,
15076
- message: `Python environment exists but required packages are not installed: ${missingPackages.join(", ")}
15077
-
15078
- This usually happens when:
15079
- 1. The .venv folder was copied but dependencies were not installed
15080
- 2. The package was installed via npm but setup script was not run
15081
-
15082
- Please run:
15083
- await setupPythonEnvironment({ force: true })
15084
-
15085
- Or manually run the setup script:
15086
- bash ` + getSetupScriptPath(root)
15087
- };
15088
- }
15089
- }
15090
- return {
15091
- valid: true,
15092
- message: "Python environment is valid"
15093
- };
15094
- }
15095
-
15096
- // src/exulu/routes.ts
15097
14883
  init_tags();
15098
14884
  var import_multer = __toESM(require("multer"), 1);
15099
14885
 
@@ -15769,7 +15555,7 @@ var REQUEST_SIZE_LIMIT = "50mb";
15769
15555
  var getExuluVersionNumber = async () => {
15770
15556
  try {
15771
15557
  const path3 = process.cwd();
15772
- const packageJson = import_fs4.default.readFileSync(path3 + "/package.json", "utf8");
15558
+ const packageJson = import_fs3.default.readFileSync(path3 + "/package.json", "utf8");
15773
15559
  const packageData = JSON.parse(packageJson);
15774
15560
  const exuluVersion = packageData.dependencies["@exulu/backend"];
15775
15561
  console.log(`[EXULU] Installed exulu-backend version: ${exuluVersion}`);
@@ -16689,7 +16475,7 @@ ${customInstructions}` : agent.instructions;
16689
16475
  const imageModelsByName = (() => {
16690
16476
  if (!isLiteLLMEnabled() || !config?.fileUploads) return /* @__PURE__ */ new Map();
16691
16477
  try {
16692
- const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path5.resolve)(getPackageRoot(), "./config.litellm.yaml");
16478
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path5.resolve)(process.cwd(), "./config.litellm.yaml");
16693
16479
  const models2 = parseImageGenerationModels(configPath);
16694
16480
  return new Map(models2.map((m) => [m.model_name, m]));
16695
16481
  } catch (err) {
@@ -17167,6 +16953,80 @@ ${style.markdown}` : params.prompt;
17167
16953
  }));
17168
16954
  res.status(200).json({ history });
17169
16955
  });
16956
+ const litellmUiPath = "/litellm-admin";
16957
+ if (isLiteLLMEnabled() && litellmUiPath) {
16958
+ console.log("[EXULU] Registering LiteLLM UI at", litellmUiPath);
16959
+ app.use(litellmUiPath, async (req, res) => {
16960
+ const host = process.env.LITELLM_HOST ?? "127.0.0.1";
16961
+ const port = process.env.LITELLM_PORT ?? "4000";
16962
+ const upstreamUrl = `http://${host}:${port}${litellmUiPath}${req.url}`;
16963
+ const upstreamHeaders = {};
16964
+ for (const [name, value] of Object.entries(req.headers)) {
16965
+ if (value === void 0) continue;
16966
+ const lower = name.toLowerCase();
16967
+ if (lower === "host" || lower === "content-length" || lower === "connection" || lower === "transfer-encoding" || lower === "accept-encoding")
16968
+ continue;
16969
+ upstreamHeaders[name] = Array.isArray(value) ? value.join(", ") : value;
16970
+ }
16971
+ const methodHasBody = !["GET", "HEAD"].includes(req.method);
16972
+ let body;
16973
+ if (methodHasBody && req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
16974
+ body = JSON.stringify(req.body);
16975
+ upstreamHeaders["content-type"] = "application/json";
16976
+ }
16977
+ try {
16978
+ const upstream = await fetch(upstreamUrl, {
16979
+ method: req.method,
16980
+ headers: upstreamHeaders,
16981
+ body,
16982
+ // Pass redirects through to the browser so LiteLLM's post-login
16983
+ // redirect lands the user on the right URL (the Location already
16984
+ // includes SERVER_ROOT_PATH).
16985
+ redirect: "manual"
16986
+ });
16987
+ res.status(upstream.status);
16988
+ const upstreamOrigin = `http://${host}:${port}`;
16989
+ upstream.headers.forEach((value, name) => {
16990
+ const lower = name.toLowerCase();
16991
+ if (lower === "content-encoding" || lower === "content-length" || lower === "transfer-encoding" || lower === "connection")
16992
+ return;
16993
+ if (lower === "location") {
16994
+ let loc = value.startsWith(upstreamOrigin) ? value.slice(upstreamOrigin.length) : value;
16995
+ if (loc.startsWith("/") && loc !== litellmUiPath && !loc.startsWith(`${litellmUiPath}/`)) {
16996
+ loc = `${litellmUiPath}${loc}`;
16997
+ }
16998
+ res.setHeader(name, loc);
16999
+ return;
17000
+ }
17001
+ res.setHeader(name, value);
17002
+ });
17003
+ if (!upstream.body) {
17004
+ res.end();
17005
+ return;
17006
+ }
17007
+ const reader = upstream.body.getReader();
17008
+ try {
17009
+ while (true) {
17010
+ const { done, value } = await reader.read();
17011
+ if (done) break;
17012
+ if (value) res.write(value);
17013
+ }
17014
+ } finally {
17015
+ reader.releaseLock();
17016
+ }
17017
+ res.end();
17018
+ } catch (err) {
17019
+ console.error("[EXULU] LiteLLM UI proxy failed", err);
17020
+ if (!res.headersSent) {
17021
+ res.status(502).json({
17022
+ detail: err instanceof Error ? err.message : "LiteLLM UI proxy failed."
17023
+ });
17024
+ } else {
17025
+ res.end();
17026
+ }
17027
+ }
17028
+ });
17029
+ }
17170
17030
  app.use("/litellm/:project", async (req, res) => {
17171
17031
  if (!isLiteLLMEnabled()) {
17172
17032
  res.status(503).json({
@@ -20676,6 +20536,210 @@ init_entitlements();
20676
20536
  init_system_dependencies();
20677
20537
  init_supervisor();
20678
20538
 
20539
+ // src/utils/python-setup.ts
20540
+ init_cjs_shims();
20541
+ var import_child_process = require("child_process");
20542
+ var import_util = require("util");
20543
+ var import_path = require("path");
20544
+ var import_fs4 = require("fs");
20545
+ var import_url = require("url");
20546
+ var execAsync4 = (0, import_util.promisify)(import_child_process.exec);
20547
+ function getPackageRoot() {
20548
+ const currentFile = (0, import_url.fileURLToPath)(importMetaUrl);
20549
+ let currentDir = (0, import_path.dirname)(currentFile);
20550
+ let attempts = 0;
20551
+ const maxAttempts = 10;
20552
+ while (attempts < maxAttempts) {
20553
+ const packageJsonPath = (0, import_path.join)(currentDir, "package.json");
20554
+ if ((0, import_fs4.existsSync)(packageJsonPath)) {
20555
+ try {
20556
+ const packageJson = JSON.parse((0, import_fs4.readFileSync)(packageJsonPath, "utf-8"));
20557
+ if (packageJson.name === "@exulu/backend") {
20558
+ return currentDir;
20559
+ }
20560
+ } catch {
20561
+ }
20562
+ }
20563
+ const parentDir = (0, import_path.resolve)(currentDir, "..");
20564
+ if (parentDir === currentDir) {
20565
+ break;
20566
+ }
20567
+ currentDir = parentDir;
20568
+ attempts++;
20569
+ }
20570
+ const fallback = (0, import_path.resolve)((0, import_path.dirname)((0, import_url.fileURLToPath)(importMetaUrl)), "../..");
20571
+ return fallback;
20572
+ }
20573
+ function getSetupScriptPath(packageRoot) {
20574
+ return (0, import_path.resolve)(packageRoot, "ee/python/setup.sh");
20575
+ }
20576
+ function getVenvPath(packageRoot) {
20577
+ return (0, import_path.resolve)(packageRoot, "ee/python/.venv");
20578
+ }
20579
+ function isPythonEnvironmentSetup(packageRoot) {
20580
+ const root = packageRoot ?? getPackageRoot();
20581
+ const venvPath = getVenvPath(root);
20582
+ const pythonPath = (0, import_path.join)(venvPath, "bin", "python");
20583
+ return (0, import_fs4.existsSync)(venvPath) && (0, import_fs4.existsSync)(pythonPath);
20584
+ }
20585
+ async function setupPythonEnvironment(options = {}) {
20586
+ const {
20587
+ packageRoot = getPackageRoot(),
20588
+ force = false,
20589
+ verbose = false,
20590
+ timeout = 6e5
20591
+ // 10 minutes
20592
+ } = options;
20593
+ if (!force && isPythonEnvironmentSetup(packageRoot)) {
20594
+ if (verbose) {
20595
+ console.log("\u2713 Python environment already set up");
20596
+ }
20597
+ return {
20598
+ success: true,
20599
+ message: "Python environment already exists",
20600
+ alreadyExists: true
20601
+ };
20602
+ }
20603
+ const setupScriptPath = getSetupScriptPath(packageRoot);
20604
+ if (!(0, import_fs4.existsSync)(setupScriptPath)) {
20605
+ return {
20606
+ success: false,
20607
+ message: `Setup script not found at: ${setupScriptPath}`,
20608
+ alreadyExists: false
20609
+ };
20610
+ }
20611
+ try {
20612
+ if (verbose) {
20613
+ console.log("Setting up Python environment...");
20614
+ }
20615
+ const { stdout, stderr } = await execAsync4(`bash "${setupScriptPath}"`, {
20616
+ cwd: packageRoot,
20617
+ timeout,
20618
+ env: {
20619
+ ...process.env,
20620
+ // Ensure script can write to the directory
20621
+ PYTHONDONTWRITEBYTECODE: "1"
20622
+ },
20623
+ maxBuffer: 10 * 1024 * 1024
20624
+ // 10MB buffer
20625
+ });
20626
+ const output = stdout + stderr;
20627
+ const versionMatch = output.match(/Python (\d+\.\d+\.\d+)/);
20628
+ const pythonVersion = versionMatch ? versionMatch[1] : void 0;
20629
+ if (verbose) {
20630
+ console.log(output);
20631
+ }
20632
+ return {
20633
+ success: true,
20634
+ message: "Python environment set up successfully",
20635
+ alreadyExists: false,
20636
+ pythonVersion,
20637
+ output
20638
+ };
20639
+ } catch (error) {
20640
+ const errorOutput = error.stdout + error.stderr;
20641
+ return {
20642
+ success: false,
20643
+ message: `Setup failed: ${error.message}`,
20644
+ alreadyExists: false,
20645
+ output: errorOutput
20646
+ };
20647
+ }
20648
+ }
20649
+ function getPythonSetupInstructions() {
20650
+ return `
20651
+ Python environment not set up. Please run one of the following commands:
20652
+
20653
+ Option 1 (Automatic):
20654
+ import { setupPythonEnvironment } from '@exulu/backend';
20655
+ await setupPythonEnvironment();
20656
+
20657
+ Option 2 (Manual - for package consumers):
20658
+ npx @exulu/backend setup-python
20659
+
20660
+ Option 3 (Manual - for contributors):
20661
+ npm run python:setup
20662
+
20663
+ These commands will automatically create a Python virtual environment (.venv)
20664
+ in the @exulu/backend package and install all required dependencies.
20665
+
20666
+ Requirements:
20667
+ - Python 3.10 or higher must be installed
20668
+ - pip must be available
20669
+ - venv module must be available (for creating virtual environments)
20670
+
20671
+ If Python dependencies are not installed, install them first, then run one of the commands above:
20672
+ - macOS: brew install python@3.12
20673
+ - Ubuntu/Debian: sudo apt-get install python3.12 python3-pip python3-venv
20674
+ - Alpine Linux: apk add python3 py3-pip python3-dev
20675
+ - Windows: Download from https://www.python.org/downloads/
20676
+
20677
+ Note: In Docker containers, ensure you install all three components:
20678
+ Ubuntu/Debian: apt-get install -y python3 python3-pip python3-venv
20679
+ Alpine: apk add python3 py3-pip python3-dev
20680
+ `.trim();
20681
+ }
20682
+ async function validatePythonEnvironment(packageRoot, checkPackages = true) {
20683
+ const root = packageRoot ?? getPackageRoot();
20684
+ const venvPath = getVenvPath(root);
20685
+ const pythonPath = (0, import_path.join)(venvPath, "bin", "python");
20686
+ if (!(0, import_fs4.existsSync)(venvPath)) {
20687
+ return {
20688
+ valid: false,
20689
+ message: getPythonSetupInstructions()
20690
+ };
20691
+ }
20692
+ if (!(0, import_fs4.existsSync)(pythonPath)) {
20693
+ return {
20694
+ valid: false,
20695
+ message: "Python virtual environment is corrupted. Please run:\n await setupPythonEnvironment({ force: true })"
20696
+ };
20697
+ }
20698
+ try {
20699
+ await execAsync4(`"${pythonPath}" --version`, { cwd: root });
20700
+ } catch {
20701
+ return {
20702
+ valid: false,
20703
+ message: "Python executable is not working. Please run:\n await setupPythonEnvironment({ force: true })"
20704
+ };
20705
+ }
20706
+ if (checkPackages) {
20707
+ const criticalPackages = ["docling", "transformers"];
20708
+ const missingPackages = [];
20709
+ for (const pkg of criticalPackages) {
20710
+ try {
20711
+ await execAsync4(`"${pythonPath}" -c "import ${pkg}"`, {
20712
+ cwd: root,
20713
+ timeout: 1e4
20714
+ // 10 second timeout per import check
20715
+ });
20716
+ } catch {
20717
+ missingPackages.push(pkg);
20718
+ }
20719
+ }
20720
+ if (missingPackages.length > 0) {
20721
+ return {
20722
+ valid: false,
20723
+ message: `Python environment exists but required packages are not installed: ${missingPackages.join(", ")}
20724
+
20725
+ This usually happens when:
20726
+ 1. The .venv folder was copied but dependencies were not installed
20727
+ 2. The package was installed via npm but setup script was not run
20728
+
20729
+ Please run:
20730
+ await setupPythonEnvironment({ force: true })
20731
+
20732
+ Or manually run the setup script:
20733
+ bash ` + getSetupScriptPath(root)
20734
+ };
20735
+ }
20736
+ }
20737
+ return {
20738
+ valid: true,
20739
+ message: "Python environment is valid"
20740
+ };
20741
+ }
20742
+
20679
20743
  // src/templates/contexts/index.ts
20680
20744
  init_cjs_shims();
20681
20745
 
@@ -20838,6 +20902,12 @@ var ExuluApp = class {
20838
20902
  ...providers ?? []
20839
20903
  ];
20840
20904
  this._config = config;
20905
+ if (isLiteLLMEnabled()) {
20906
+ const uiPath = "/litellm-admin";
20907
+ if (uiPath) {
20908
+ process.env.EXULU_LITELLM_UI_PATH = uiPath;
20909
+ }
20910
+ }
20841
20911
  const transcriptionTools = [];
20842
20912
  if (process.env.TRANSCRIPTION_MODEL && config?.fileUploads && config?.fileUploads?.s3region && config?.fileUploads?.s3key && config?.fileUploads?.s3secret && config?.fileUploads?.s3Bucket) {
20843
20913
  transcriptionTools.push(transcribeTool);
@@ -20845,7 +20915,7 @@ var ExuluApp = class {
20845
20915
  const imageGenerationTools = [];
20846
20916
  const s3Configured = !!config?.fileUploads && !!config.fileUploads.s3region && !!config.fileUploads.s3key && !!config.fileUploads.s3secret && !!config.fileUploads.s3Bucket;
20847
20917
  if (isLiteLLMEnabled() && s3Configured) {
20848
- const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path7.resolve)(getPackageRoot(), "./config.litellm.yaml");
20918
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path7.resolve)(process.cwd(), "./config.litellm.yaml");
20849
20919
  const imageModels = parseImageGenerationModels(configPath);
20850
20920
  if (imageModels.length > 0) {
20851
20921
  console.log(
@@ -23119,7 +23189,7 @@ ${WARNING_BANNER}`);
23119
23189
  };
23120
23190
  var log3 = (line) => console.log(`[EXULU-LITELLM] ${line}`);
23121
23191
  var initLiteLLMDatabase = async (packageRoot) => {
23122
- const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path8.resolve)(packageRoot, "./config.litellm.yaml");
23192
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? (0, import_node_path8.resolve)(process.cwd(), "./config.litellm.yaml");
23123
23193
  const safety = checkLiteLLMDatabaseSafety(configPath);
23124
23194
  if (safety.ok && safety.reason === "no-litellm-db-mode") return;
23125
23195
  if (!safety.ok && safety.reason === "unparseable-url") {
package/dist/index.js CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  vectorSearch,
54
54
  waitForLiteLLMReady,
55
55
  withRetry
56
- } from "./chunk-PFKAWGB6.js";
56
+ } from "./chunk-4TCN467I.js";
57
57
  import {
58
58
  findLiteLLMModel
59
59
  } from "./chunk-ILAHW4UT.js";
@@ -5182,30 +5182,6 @@ type LiteLLMModel {
5182
5182
  pageInfo: PageInfo!
5183
5183
  }
5184
5184
  `;
5185
- typeDefs += `
5186
- agentWorldAgents: [AgentWorldAgent!]!
5187
- `;
5188
- resolvers.Query["agentWorldAgents"] = async (_, _args, context) => {
5189
- const { db } = context;
5190
- const sessions = await db("agent_sessions as s").select([
5191
- "s.id as sessionId",
5192
- "s.agent as agentId",
5193
- "s.currenttask as currentTask",
5194
- "s.createdAt as lastActivityAt",
5195
- "s.created_by as userId"
5196
- ]).whereNotNull("s.currenttask").limit(20).orderBy("s.createdAt", "desc");
5197
- return sessions.map((row) => {
5198
- const agent = providers.find((p) => p.id === row.agentId);
5199
- return {
5200
- sessionId: row.sessionId,
5201
- agentId: row.agentId ?? "",
5202
- agentName: agent?.name ?? row.agentId ?? "Agent",
5203
- agentImage: agent?.image ?? null,
5204
- currentTask: row.currentTask,
5205
- lastActivityAt: row.lastActivityAt
5206
- };
5207
- });
5208
- };
5209
5185
  typeDefs += "}\n";
5210
5186
  mutationDefs += "}\n";
5211
5187
  const genericTypes = `
@@ -5420,15 +5396,6 @@ type StatisticsResult {
5420
5396
  group: String!
5421
5397
  count: Int!
5422
5398
  }
5423
-
5424
- type AgentWorldAgent {
5425
- sessionId: ID!
5426
- agentId: ID!
5427
- agentName: String!
5428
- agentImage: String
5429
- currentTask: String
5430
- lastActivityAt: String
5431
- }
5432
5399
  `;
5433
5400
  const fullSDL = typeDefs + mutationDefs + modelDefs + genericTypes;
5434
5401
  const schema = makeExecutableSchema({
@@ -5703,7 +5670,7 @@ async function clearSessionCurrentTask(session) {
5703
5670
  }
5704
5671
 
5705
5672
  // src/exulu/provider.ts
5706
- import fs2 from "fs";
5673
+ import "fs";
5707
5674
  var ExuluProvider = class {
5708
5675
  // Must begin with a letter (a-z) or underscore (_). Subsequent characters in a name can be letters, digits (0-9), or
5709
5676
  // underscores and be a max length of 80 characters and at least 5 characters long.
@@ -6366,7 +6333,6 @@ ${extractedText}
6366
6333
  // todo make this configurable?
6367
6334
  page: 1
6368
6335
  });
6369
- fs2.writeFileSync("pre-fetched-relevant-information.json", JSON.stringify(result2, null, 2));
6370
6336
  if (result2?.chunks?.length) {
6371
6337
  memoryItems = result2.chunks;
6372
6338
  memoryContext = `
@@ -8594,7 +8560,7 @@ ${customInstructions}` : agent.instructions;
8594
8560
  const imageModelsByName = (() => {
8595
8561
  if (!isLiteLLMEnabled() || !config?.fileUploads) return /* @__PURE__ */ new Map();
8596
8562
  try {
8597
- const configPath = process.env.LITELLM_CONFIG_PATH ?? resolvePath(getPackageRoot(), "./config.litellm.yaml");
8563
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? resolvePath(process.cwd(), "./config.litellm.yaml");
8598
8564
  const models2 = parseImageGenerationModels(configPath);
8599
8565
  return new Map(models2.map((m) => [m.model_name, m]));
8600
8566
  } catch (err) {
@@ -9072,6 +9038,80 @@ ${style.markdown}` : params.prompt;
9072
9038
  }));
9073
9039
  res.status(200).json({ history });
9074
9040
  });
9041
+ const litellmUiPath = "/litellm-admin";
9042
+ if (isLiteLLMEnabled() && litellmUiPath) {
9043
+ console.log("[EXULU] Registering LiteLLM UI at", litellmUiPath);
9044
+ app.use(litellmUiPath, async (req, res) => {
9045
+ const host = process.env.LITELLM_HOST ?? "127.0.0.1";
9046
+ const port = process.env.LITELLM_PORT ?? "4000";
9047
+ const upstreamUrl = `http://${host}:${port}${litellmUiPath}${req.url}`;
9048
+ const upstreamHeaders = {};
9049
+ for (const [name, value] of Object.entries(req.headers)) {
9050
+ if (value === void 0) continue;
9051
+ const lower = name.toLowerCase();
9052
+ if (lower === "host" || lower === "content-length" || lower === "connection" || lower === "transfer-encoding" || lower === "accept-encoding")
9053
+ continue;
9054
+ upstreamHeaders[name] = Array.isArray(value) ? value.join(", ") : value;
9055
+ }
9056
+ const methodHasBody = !["GET", "HEAD"].includes(req.method);
9057
+ let body;
9058
+ if (methodHasBody && req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
9059
+ body = JSON.stringify(req.body);
9060
+ upstreamHeaders["content-type"] = "application/json";
9061
+ }
9062
+ try {
9063
+ const upstream = await fetch(upstreamUrl, {
9064
+ method: req.method,
9065
+ headers: upstreamHeaders,
9066
+ body,
9067
+ // Pass redirects through to the browser so LiteLLM's post-login
9068
+ // redirect lands the user on the right URL (the Location already
9069
+ // includes SERVER_ROOT_PATH).
9070
+ redirect: "manual"
9071
+ });
9072
+ res.status(upstream.status);
9073
+ const upstreamOrigin = `http://${host}:${port}`;
9074
+ upstream.headers.forEach((value, name) => {
9075
+ const lower = name.toLowerCase();
9076
+ if (lower === "content-encoding" || lower === "content-length" || lower === "transfer-encoding" || lower === "connection")
9077
+ return;
9078
+ if (lower === "location") {
9079
+ let loc = value.startsWith(upstreamOrigin) ? value.slice(upstreamOrigin.length) : value;
9080
+ if (loc.startsWith("/") && loc !== litellmUiPath && !loc.startsWith(`${litellmUiPath}/`)) {
9081
+ loc = `${litellmUiPath}${loc}`;
9082
+ }
9083
+ res.setHeader(name, loc);
9084
+ return;
9085
+ }
9086
+ res.setHeader(name, value);
9087
+ });
9088
+ if (!upstream.body) {
9089
+ res.end();
9090
+ return;
9091
+ }
9092
+ const reader = upstream.body.getReader();
9093
+ try {
9094
+ while (true) {
9095
+ const { done, value } = await reader.read();
9096
+ if (done) break;
9097
+ if (value) res.write(value);
9098
+ }
9099
+ } finally {
9100
+ reader.releaseLock();
9101
+ }
9102
+ res.end();
9103
+ } catch (err) {
9104
+ console.error("[EXULU] LiteLLM UI proxy failed", err);
9105
+ if (!res.headersSent) {
9106
+ res.status(502).json({
9107
+ detail: err instanceof Error ? err.message : "LiteLLM UI proxy failed."
9108
+ });
9109
+ } else {
9110
+ res.end();
9111
+ }
9112
+ }
9113
+ });
9114
+ }
9075
9115
  app.use("/litellm/:project", async (req, res) => {
9076
9116
  if (!isLiteLLMEnabled()) {
9077
9117
  res.status(503).json({
@@ -12677,6 +12717,12 @@ var ExuluApp = class {
12677
12717
  ...providers ?? []
12678
12718
  ];
12679
12719
  this._config = config;
12720
+ if (isLiteLLMEnabled()) {
12721
+ const uiPath = "/litellm-admin";
12722
+ if (uiPath) {
12723
+ process.env.EXULU_LITELLM_UI_PATH = uiPath;
12724
+ }
12725
+ }
12680
12726
  const transcriptionTools = [];
12681
12727
  if (process.env.TRANSCRIPTION_MODEL && config?.fileUploads && config?.fileUploads?.s3region && config?.fileUploads?.s3key && config?.fileUploads?.s3secret && config?.fileUploads?.s3Bucket) {
12682
12728
  transcriptionTools.push(transcribeTool);
@@ -12684,7 +12730,7 @@ var ExuluApp = class {
12684
12730
  const imageGenerationTools = [];
12685
12731
  const s3Configured = !!config?.fileUploads && !!config.fileUploads.s3region && !!config.fileUploads.s3key && !!config.fileUploads.s3secret && !!config.fileUploads.s3Bucket;
12686
12732
  if (isLiteLLMEnabled() && s3Configured) {
12687
- const configPath = process.env.LITELLM_CONFIG_PATH ?? resolve(getPackageRoot(), "./config.litellm.yaml");
12733
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? resolve(process.cwd(), "./config.litellm.yaml");
12688
12734
  const imageModels = parseImageGenerationModels(configPath);
12689
12735
  if (imageModels.length > 0) {
12690
12736
  console.log(
@@ -14919,7 +14965,7 @@ ${WARNING_BANNER}`);
14919
14965
  };
14920
14966
  var log2 = (line) => console.log(`[EXULU-LITELLM] ${line}`);
14921
14967
  var initLiteLLMDatabase = async (packageRoot) => {
14922
- const configPath = process.env.LITELLM_CONFIG_PATH ?? resolve2(packageRoot, "./config.litellm.yaml");
14968
+ const configPath = process.env.LITELLM_CONFIG_PATH ?? resolve2(process.cwd(), "./config.litellm.yaml");
14923
14969
  const safety = checkLiteLLMDatabaseSafety(configPath);
14924
14970
  if (safety.ok && safety.reason === "no-litellm-db-mode") return;
14925
14971
  if (!safety.ok && safety.reason === "unparseable-url") {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exulu/backend",
3
3
  "author": "Qventu Bv.",
4
- "version": "1.61.3",
4
+ "version": "1.62.1",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
7
7
  "publishConfig": {