@exulu/backend 1.64.0 → 1.66.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.
@@ -1562,7 +1562,10 @@ var createUppyRoutes = async (app, config) => {
1562
1562
  Bucket: config.fileUploads.s3Bucket,
1563
1563
  Key: fullKey,
1564
1564
  ContentType: type,
1565
- Metadata: metadata
1565
+ // S3 metadata values must be US-ASCII. Sanitize here (same as uploadFile)
1566
+ // so non-ASCII characters in the filename — e.g. the en-dash "–" in
1567
+ // "… CEST – Recording.mp4" — don't trigger a SignatureDoesNotMatch.
1568
+ Metadata: sanitizeMetadata(metadata)
1566
1569
  };
1567
1570
  const command = new CreateMultipartUploadCommand(params);
1568
1571
  return client2.send(command, (err, data) => {
@@ -5700,7 +5703,7 @@ function createAgenticRetrievalToolV3({
5700
5703
  return void 0;
5701
5704
  }
5702
5705
  const contextNames = contexts.map((c) => c.id).join(", ");
5703
- return new ExuluTool({
5706
+ return ExuluTool.internal({
5704
5707
  id: "agentic_context_search",
5705
5708
  name: "Context Search",
5706
5709
  description: `Intelligent context search with query classification, strategy-based retrieval, and virtual filesystem filtering. Searches: ${contextNames}`,
@@ -6040,7 +6043,7 @@ var createProjectItemsRetrievalTool = async ({
6040
6043
  if (!project.project_items?.length) {
6041
6044
  return;
6042
6045
  }
6043
- const projectRetrievalTool = new ExuluTool({
6046
+ const projectRetrievalTool = ExuluTool.internal({
6044
6047
  id: "context_search_in_knowledge_items_added_to_project_" + projectId,
6045
6048
  name: "context_search in knowledge items added to project " + project.name,
6046
6049
  description: "This tool retrieves information about a project from conversations and items that were added to the project " + project.name + ".",
@@ -12379,7 +12382,7 @@ var ExuluProvider = class {
12379
12382
  if (!license["multi-agent-tooling"]) {
12380
12383
  console.warn(`[EXULU] You are not licensed to use multi-agent tooling so cannot export this agent as a tool. Please set your EXULU_ENTERPRISE_LICENSE env variable.`);
12381
12384
  }
12382
- return new ExuluTool({
12385
+ return ExuluTool.internal({
12383
12386
  id: agent.id,
12384
12387
  name: `${agent.name}`,
12385
12388
  type: "agent",
@@ -18543,7 +18546,6 @@ var ResolveModelError = class extends Error {
18543
18546
  this.name = "ResolveModelError";
18544
18547
  }
18545
18548
  };
18546
- var _litellmProvider;
18547
18549
  var getLiteLLMProvider = ({
18548
18550
  user,
18549
18551
  role,
@@ -18551,7 +18553,6 @@ var getLiteLLMProvider = ({
18551
18553
  agent,
18552
18554
  team
18553
18555
  }) => {
18554
- if (_litellmProvider) return _litellmProvider;
18555
18556
  const host = process.env.LITELLM_HOST ?? "127.0.0.1";
18556
18557
  const port = process.env.LITELLM_PORT ?? "4000";
18557
18558
  const masterKey = process.env.LITELLM_MASTER_KEY;
@@ -18573,7 +18574,7 @@ var getLiteLLMProvider = ({
18573
18574
  "LITELLM_MASTER_KEY is required when EXULU_USE_LITELLM=true"
18574
18575
  );
18575
18576
  }
18576
- _litellmProvider = createOpenAICompatible({
18577
+ return createOpenAICompatible({
18577
18578
  name: "litellm",
18578
18579
  baseURL: `http://${host}:${port}/v1`,
18579
18580
  apiKey: masterKey,
@@ -18589,7 +18590,6 @@ var getLiteLLMProvider = ({
18589
18590
  // proxy contract.
18590
18591
  supportsStructuredOutputs: true
18591
18592
  });
18592
- return _litellmProvider;
18593
18593
  };
18594
18594
  async function resolveModel(input) {
18595
18595
  const { modelId, user, providers, agent, project, rbacBypass } = input;
@@ -18686,7 +18686,8 @@ async function resolveModel(input) {
18686
18686
  }
18687
18687
 
18688
18688
  // src/exulu/tool.ts
18689
- var ExuluTool = class {
18689
+ var PUBLIC_TOOL_TYPES = ["function", "web_search", "skill"];
18690
+ var ExuluTool = class _ExuluTool {
18690
18691
  // Must begin with a letter (a-z) or underscore (_). Subsequent characters in a name can be letters, digits (0-9), or
18691
18692
  // underscores and be a max length of 80 characters and at least 5 characters long.
18692
18693
  // The ID is used for storing references to tools so it is important it does not change.
@@ -18710,6 +18711,13 @@ var ExuluTool = class {
18710
18711
  config,
18711
18712
  needsApproval
18712
18713
  }) {
18714
+ if (!PUBLIC_TOOL_TYPES.includes(type)) {
18715
+ throw new Error(
18716
+ `ExuluTool "${id}": invalid type "${type}". Allowed types are ${PUBLIC_TOOL_TYPES.join(
18717
+ ", "
18718
+ )}. The "agent" and "context" types are managed by Exulu internally and cannot be set on a tool.`
18719
+ );
18720
+ }
18713
18721
  this.id = id;
18714
18722
  this.config = config;
18715
18723
  this.needsApproval = needsApproval ?? true;
@@ -18724,6 +18732,19 @@ var ExuluTool = class {
18724
18732
  execute
18725
18733
  });
18726
18734
  }
18735
+ /**
18736
+ * Framework-only factory for tools whose `type` is managed by Exulu itself —
18737
+ * "agent" (agent-as-tool instrumentation) and "context" (internal retrieval
18738
+ * tools). NOT part of the public API: package consumers must use
18739
+ * `new ExuluTool(...)`, which only accepts a {@link PublicToolType}. Building
18740
+ * the tool as a "function" and then setting the managed type bypasses the
18741
+ * constructor guard without weakening it for consumers.
18742
+ */
18743
+ static internal(params) {
18744
+ const instance2 = new _ExuluTool({ ...params, type: "function" });
18745
+ instance2.type = params.type;
18746
+ return instance2;
18747
+ }
18727
18748
  execute = async ({
18728
18749
  agent: agentId,
18729
18750
  config,
@@ -18756,7 +18777,7 @@ var ExuluTool = class {
18756
18777
  });
18757
18778
  providerapikey = resolved.apiKey;
18758
18779
  }
18759
- const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-D35XXTKW.js");
18780
+ const { convertExuluToolsToAiSdkTools: convertExuluToolsToAiSdkTools2 } = await import("./convert-exulu-tools-to-ai-sdk-tools-ZFIN7A5V.js");
18760
18781
  const tools = await convertExuluToolsToAiSdkTools2(
18761
18782
  [this],
18762
18783
  [],
@@ -18816,7 +18837,7 @@ var createSessionItemsRetrievalTool = async ({
18816
18837
  items
18817
18838
  }) => {
18818
18839
  console.log("[EXULU] Session search tool created for session", items);
18819
- const sessionItemsRetrievalTool = new ExuluTool({
18840
+ const sessionItemsRetrievalTool = ExuluTool.internal({
18820
18841
  id: "session_items_information_context_search",
18821
18842
  name: "context_search in knowledge items added to session.",
18822
18843
  description: "Context search in knowledge items added to session.",
@@ -19252,9 +19273,10 @@ var convertExuluToolsToAiSdkTools = async (currentTools, currentSkills, approved
19252
19273
  if (!s3Client2) {
19253
19274
  throw new Error("S3 client not initialized");
19254
19275
  }
19255
- const response2 = await s3Client2.send(command);
19256
- console.log(response2);
19257
- return response2;
19276
+ await s3Client2.send(command);
19277
+ const bucket = exuluConfig?.fileUploads?.s3Bucket ?? "";
19278
+ const presignedUrl = await getPresignedUrl(bucket, key, exuluConfig);
19279
+ return { url: presignedUrl, key: `${bucket}/${key}` };
19258
19280
  } catch (caught) {
19259
19281
  if (caught instanceof S3ServiceException && caught.name === "EntityTooLarge") {
19260
19282
  throw new Error(`[EXULU] Error from S3 while uploading object to ${exuluConfig?.fileUploads?.s3Bucket}. The object was too large. To upload objects larger than 5GB, use the S3 console (160GB max) or the multipart upload API (5TB max).`);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  convertExuluToolsToAiSdkTools
3
- } from "./chunk-A5AZEDLP.js";
3
+ } from "./chunk-KQDNL5WU.js";
4
4
  import "./chunk-YCE44CMU.js";
5
5
  export {
6
6
  convertExuluToolsToAiSdkTools
package/dist/index.cjs CHANGED
@@ -1695,7 +1695,7 @@ async function resolveModel(input) {
1695
1695
  });
1696
1696
  return { languageModel, model, exuluProvider, apiKey };
1697
1697
  }
1698
- var import_crypto_js, import_openai_compatible, LITELLM_PROVIDER_SENTINEL, ResolveModelError, _litellmProvider, getLiteLLMProvider;
1698
+ var import_crypto_js, import_openai_compatible, LITELLM_PROVIDER_SENTINEL, ResolveModelError, getLiteLLMProvider;
1699
1699
  var init_resolve_model = __esm({
1700
1700
  "src/exulu/resolve-model.ts"() {
1701
1701
  "use strict";
@@ -1736,7 +1736,6 @@ var init_resolve_model = __esm({
1736
1736
  agent,
1737
1737
  team
1738
1738
  }) => {
1739
- if (_litellmProvider) return _litellmProvider;
1740
1739
  const host = process.env.LITELLM_HOST ?? "127.0.0.1";
1741
1740
  const port = process.env.LITELLM_PORT ?? "4000";
1742
1741
  const masterKey = process.env.LITELLM_MASTER_KEY;
@@ -1758,7 +1757,7 @@ var init_resolve_model = __esm({
1758
1757
  "LITELLM_MASTER_KEY is required when EXULU_USE_LITELLM=true"
1759
1758
  );
1760
1759
  }
1761
- _litellmProvider = (0, import_openai_compatible.createOpenAICompatible)({
1760
+ return (0, import_openai_compatible.createOpenAICompatible)({
1762
1761
  name: "litellm",
1763
1762
  baseURL: `http://${host}:${port}/v1`,
1764
1763
  apiKey: masterKey,
@@ -1774,7 +1773,6 @@ var init_resolve_model = __esm({
1774
1773
  // proxy contract.
1775
1774
  supportsStructuredOutputs: true
1776
1775
  });
1777
- return _litellmProvider;
1778
1776
  };
1779
1777
  }
1780
1778
  });
@@ -1845,7 +1843,7 @@ var init_project_retrieval_tool = __esm({
1845
1843
  if (!project.project_items?.length) {
1846
1844
  return;
1847
1845
  }
1848
- const projectRetrievalTool = new ExuluTool({
1846
+ const projectRetrievalTool = ExuluTool.internal({
1849
1847
  id: "context_search_in_knowledge_items_added_to_project_" + projectId,
1850
1848
  name: "context_search in knowledge items added to project " + project.name,
1851
1849
  description: "This tool retrieves information about a project from conversations and items that were added to the project " + project.name + ".",
@@ -1947,7 +1945,7 @@ var init_session_items_retrieval_tool = __esm({
1947
1945
  items
1948
1946
  }) => {
1949
1947
  console.log("[EXULU] Session search tool created for session", items);
1950
- const sessionItemsRetrievalTool = new ExuluTool({
1948
+ const sessionItemsRetrievalTool = ExuluTool.internal({
1951
1949
  id: "session_items_information_context_search",
1952
1950
  name: "context_search in knowledge items added to session.",
1953
1951
  description: "Context search in knowledge items added to session.",
@@ -2779,7 +2777,10 @@ var init_uppy = __esm({
2779
2777
  Bucket: config.fileUploads.s3Bucket,
2780
2778
  Key: fullKey,
2781
2779
  ContentType: type,
2782
- Metadata: metadata
2780
+ // S3 metadata values must be US-ASCII. Sanitize here (same as uploadFile)
2781
+ // so non-ASCII characters in the filename — e.g. the en-dash "–" in
2782
+ // "… CEST – Recording.mp4" — don't trigger a SignatureDoesNotMatch.
2783
+ Metadata: sanitizeMetadata(metadata)
2783
2784
  };
2784
2785
  const command = new import_client_s3.CreateMultipartUploadCommand(params);
2785
2786
  return client2.send(command, (err, data) => {
@@ -3893,9 +3894,10 @@ var init_convert_exulu_tools_to_ai_sdk_tools = __esm({
3893
3894
  if (!s3Client2) {
3894
3895
  throw new Error("S3 client not initialized");
3895
3896
  }
3896
- const response2 = await s3Client2.send(command);
3897
- console.log(response2);
3898
- return response2;
3897
+ await s3Client2.send(command);
3898
+ const bucket = exuluConfig?.fileUploads?.s3Bucket ?? "";
3899
+ const presignedUrl = await getPresignedUrl(bucket, key, exuluConfig);
3900
+ return { url: presignedUrl, key: `${bucket}/${key}` };
3899
3901
  } catch (caught) {
3900
3902
  if (caught instanceof import_client_s32.S3ServiceException && caught.name === "EntityTooLarge") {
3901
3903
  throw new Error(`[EXULU] Error from S3 while uploading object to ${exuluConfig?.fileUploads?.s3Bucket}. The object was too large. To upload objects larger than 5GB, use the S3 console (160GB max) or the multipart upload API (5TB max).`);
@@ -3970,7 +3972,7 @@ var init_convert_exulu_tools_to_ai_sdk_tools = __esm({
3970
3972
  });
3971
3973
 
3972
3974
  // src/exulu/tool.ts
3973
- var import_ai2, import_zod5, import_node_crypto3, ExuluTool;
3975
+ var import_ai2, import_zod5, import_node_crypto3, PUBLIC_TOOL_TYPES, ExuluTool;
3974
3976
  var init_tool = __esm({
3975
3977
  "src/exulu/tool.ts"() {
3976
3978
  "use strict";
@@ -3982,7 +3984,8 @@ var init_tool = __esm({
3982
3984
  import_node_crypto3 = require("crypto");
3983
3985
  init_singleton();
3984
3986
  init_resolve_model();
3985
- ExuluTool = class {
3987
+ PUBLIC_TOOL_TYPES = ["function", "web_search", "skill"];
3988
+ ExuluTool = class _ExuluTool {
3986
3989
  // Must begin with a letter (a-z) or underscore (_). Subsequent characters in a name can be letters, digits (0-9), or
3987
3990
  // underscores and be a max length of 80 characters and at least 5 characters long.
3988
3991
  // The ID is used for storing references to tools so it is important it does not change.
@@ -4006,6 +4009,13 @@ var init_tool = __esm({
4006
4009
  config,
4007
4010
  needsApproval
4008
4011
  }) {
4012
+ if (!PUBLIC_TOOL_TYPES.includes(type)) {
4013
+ throw new Error(
4014
+ `ExuluTool "${id}": invalid type "${type}". Allowed types are ${PUBLIC_TOOL_TYPES.join(
4015
+ ", "
4016
+ )}. The "agent" and "context" types are managed by Exulu internally and cannot be set on a tool.`
4017
+ );
4018
+ }
4009
4019
  this.id = id;
4010
4020
  this.config = config;
4011
4021
  this.needsApproval = needsApproval ?? true;
@@ -4020,6 +4030,19 @@ var init_tool = __esm({
4020
4030
  execute: execute2
4021
4031
  });
4022
4032
  }
4033
+ /**
4034
+ * Framework-only factory for tools whose `type` is managed by Exulu itself —
4035
+ * "agent" (agent-as-tool instrumentation) and "context" (internal retrieval
4036
+ * tools). NOT part of the public API: package consumers must use
4037
+ * `new ExuluTool(...)`, which only accepts a {@link PublicToolType}. Building
4038
+ * the tool as a "function" and then setting the managed type bypasses the
4039
+ * constructor guard without weakening it for consumers.
4040
+ */
4041
+ static internal(params) {
4042
+ const instance2 = new _ExuluTool({ ...params, type: "function" });
4043
+ instance2.type = params.type;
4044
+ return instance2;
4045
+ }
4023
4046
  execute = async ({
4024
4047
  agent: agentId,
4025
4048
  config,
@@ -8305,7 +8328,7 @@ function createAgenticRetrievalToolV3({
8305
8328
  return void 0;
8306
8329
  }
8307
8330
  const contextNames = contexts.map((c) => c.id).join(", ");
8308
- return new ExuluTool({
8331
+ return ExuluTool.internal({
8309
8332
  id: "agentic_context_search",
8310
8333
  name: "Context Search",
8311
8334
  description: `Intelligent context search with query classification, strategy-based retrieval, and virtual filesystem filtering. Searches: ${contextNames}`,
@@ -14179,7 +14202,7 @@ var init_provider = __esm({
14179
14202
  if (!license["multi-agent-tooling"]) {
14180
14203
  console.warn(`[EXULU] You are not licensed to use multi-agent tooling so cannot export this agent as a tool. Please set your EXULU_ENTERPRISE_LICENSE env variable.`);
14181
14204
  }
14182
- return new ExuluTool({
14205
+ return ExuluTool.internal({
14183
14206
  id: agent.id,
14184
14207
  name: `${agent.name}`,
14185
14208
  type: "agent",
package/dist/index.d.cts CHANGED
@@ -184,13 +184,16 @@ interface Item {
184
184
  [key: string]: any;
185
185
  }
186
186
 
187
+ declare const PUBLIC_TOOL_TYPES: readonly ["function", "web_search", "skill"];
188
+ type PublicToolType = (typeof PUBLIC_TOOL_TYPES)[number];
189
+ type ToolType = PublicToolType | "agent" | "context";
187
190
  declare class ExuluTool {
188
191
  id: string;
189
192
  name: string;
190
193
  description: string;
191
194
  category: string;
192
195
  inputSchema?: z.ZodType;
193
- type: "context" | "function" | "agent" | "web_search" | "skill";
196
+ type: ToolType;
194
197
  tool: Tool;
195
198
  needsApproval: boolean;
196
199
  config: {
@@ -205,7 +208,7 @@ declare class ExuluTool {
205
208
  description: string;
206
209
  category?: string;
207
210
  inputSchema?: z.ZodType;
208
- type: "context" | "function" | "agent" | "web_search" | "skill";
211
+ type: PublicToolType;
209
212
  config: {
210
213
  name: string;
211
214
  description: string;
@@ -223,6 +226,17 @@ declare class ExuluTool {
223
226
  items?: Item[];
224
227
  }>;
225
228
  });
229
+ /**
230
+ * Framework-only factory for tools whose `type` is managed by Exulu itself —
231
+ * "agent" (agent-as-tool instrumentation) and "context" (internal retrieval
232
+ * tools). NOT part of the public API: package consumers must use
233
+ * `new ExuluTool(...)`, which only accepts a {@link PublicToolType}. Building
234
+ * the tool as a "function" and then setting the managed type bypasses the
235
+ * constructor guard without weakening it for consumers.
236
+ */
237
+ static internal(params: Omit<ConstructorParameters<typeof ExuluTool>[0], "type"> & {
238
+ type: ToolType;
239
+ }): ExuluTool;
226
240
  execute: ({ agent: agentId, config, user, inputs, project, items, }: {
227
241
  agent: string;
228
242
  config: ExuluConfig;
package/dist/index.d.ts CHANGED
@@ -184,13 +184,16 @@ interface Item {
184
184
  [key: string]: any;
185
185
  }
186
186
 
187
+ declare const PUBLIC_TOOL_TYPES: readonly ["function", "web_search", "skill"];
188
+ type PublicToolType = (typeof PUBLIC_TOOL_TYPES)[number];
189
+ type ToolType = PublicToolType | "agent" | "context";
187
190
  declare class ExuluTool {
188
191
  id: string;
189
192
  name: string;
190
193
  description: string;
191
194
  category: string;
192
195
  inputSchema?: z.ZodType;
193
- type: "context" | "function" | "agent" | "web_search" | "skill";
196
+ type: ToolType;
194
197
  tool: Tool;
195
198
  needsApproval: boolean;
196
199
  config: {
@@ -205,7 +208,7 @@ declare class ExuluTool {
205
208
  description: string;
206
209
  category?: string;
207
210
  inputSchema?: z.ZodType;
208
- type: "context" | "function" | "agent" | "web_search" | "skill";
211
+ type: PublicToolType;
209
212
  config: {
210
213
  name: string;
211
214
  description: string;
@@ -223,6 +226,17 @@ declare class ExuluTool {
223
226
  items?: Item[];
224
227
  }>;
225
228
  });
229
+ /**
230
+ * Framework-only factory for tools whose `type` is managed by Exulu itself —
231
+ * "agent" (agent-as-tool instrumentation) and "context" (internal retrieval
232
+ * tools). NOT part of the public API: package consumers must use
233
+ * `new ExuluTool(...)`, which only accepts a {@link PublicToolType}. Building
234
+ * the tool as a "function" and then setting the managed type bypasses the
235
+ * constructor guard without weakening it for consumers.
236
+ */
237
+ static internal(params: Omit<ConstructorParameters<typeof ExuluTool>[0], "type"> & {
238
+ type: ToolType;
239
+ }): ExuluTool;
226
240
  execute: ({ agent: agentId, config, user, inputs, project, items, }: {
227
241
  agent: string;
228
242
  config: ExuluConfig;
package/dist/index.js CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  uploadFile,
54
54
  validateHermesAtBoot,
55
55
  withRetry
56
- } from "./chunk-A5AZEDLP.js";
56
+ } from "./chunk-KQDNL5WU.js";
57
57
  import "./chunk-YCE44CMU.js";
58
58
 
59
59
  // src/index.ts
@@ -213,7 +213,7 @@ export function createAgenticRetrievalToolV3({
213
213
 
214
214
  const contextNames = contexts.map((c) => c.id).join(", ");
215
215
 
216
- return new ExuluTool({
216
+ return ExuluTool.internal({
217
217
  id: "agentic_context_search",
218
218
  name: "Context Search",
219
219
  description: `Intelligent context search with query classification, strategy-based retrieval, and virtual filesystem filtering. Searches: ${contextNames}`,
@@ -152,7 +152,7 @@ export function createAgenticRetrievalToolV4({
152
152
 
153
153
  const contextNames = contexts.map((c) => c.id).join(", ");
154
154
 
155
- return new ExuluTool({
155
+ return ExuluTool.internal({
156
156
  id: "agentic_context_search",
157
157
  name: "Context Search",
158
158
  description: `Intelligent context search with query classification, strategy-based retrieval, and virtual filesystem filtering. Searches: ${contextNames}`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@exulu/backend",
3
3
  "author": "Qventu Bv.",
4
- "version": "1.64.0",
4
+ "version": "1.66.0",
5
5
  "main": "./dist/index.js",
6
6
  "private": false,
7
7
  "publishConfig": {