@smythos/sre 1.5.37 → 1.5.40

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.
Files changed (82) hide show
  1. package/dist/index.js +65 -45
  2. package/dist/index.js.map +1 -1
  3. package/dist/types/Components/ECMASandbox.class.d.ts +14 -0
  4. package/dist/types/Components/MemoryDeleteKeyVal.class.d.ts +19 -0
  5. package/dist/types/Components/MemoryReadKeyVal.class.d.ts +17 -0
  6. package/dist/types/Components/MemoryWriteKeyVal.class.d.ts +17 -0
  7. package/dist/types/Components/MemoryWriteObject.class.d.ts +19 -0
  8. package/dist/types/Components/index.d.ts +10 -0
  9. package/dist/types/Core/ConnectorsService.d.ts +2 -1
  10. package/dist/types/helpers/ECMASandbox.helper.d.ts +3 -0
  11. package/dist/types/helpers/Log.helper.d.ts +1 -1
  12. package/dist/types/index.d.ts +8 -1
  13. package/dist/types/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.d.ts +19 -0
  14. package/dist/types/subsystems/LLMManager/LLM.helper.d.ts +21 -10
  15. package/dist/types/subsystems/LLMManager/LLM.service/LLMConnector.d.ts +5 -5
  16. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.d.ts +2 -3
  17. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.d.ts +2 -3
  18. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Echo.class.d.ts +2 -3
  19. package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +2 -3
  20. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Groq.class.d.ts +2 -3
  21. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.d.ts +3 -4
  22. package/dist/types/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.d.ts +19 -14
  23. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.d.ts +95 -0
  24. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.d.ts +87 -0
  25. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.d.ts +85 -0
  26. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.d.ts +49 -0
  27. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.d.ts +146 -0
  28. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.d.ts +10 -0
  29. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.d.ts +4 -0
  30. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/types.d.ts +38 -0
  31. package/dist/types/subsystems/LLMManager/LLM.service/connectors/xAI.class.d.ts +1 -2
  32. package/dist/types/subsystems/Security/Vault.service/connectors/JSONFileVault.class.d.ts +5 -0
  33. package/dist/types/types/LLM.types.d.ts +82 -37
  34. package/dist/types/utils/data.utils.d.ts +2 -1
  35. package/package.json +4 -3
  36. package/src/Components/APICall/APICall.class.ts +2 -1
  37. package/src/Components/Component.class.ts +1 -1
  38. package/src/Components/ECMASandbox.class.ts +71 -0
  39. package/src/Components/GenAILLM.class.ts +1 -1
  40. package/src/Components/MemoryDeleteKeyVal.class.ts +70 -0
  41. package/src/Components/MemoryReadKeyVal.class.ts +66 -0
  42. package/src/Components/MemoryWriteKeyVal.class.ts +62 -0
  43. package/src/Components/MemoryWriteObject.class.ts +97 -0
  44. package/src/Components/index.ts +10 -0
  45. package/src/Core/ConnectorsService.ts +3 -3
  46. package/src/helpers/Conversation.helper.ts +11 -3
  47. package/src/helpers/ECMASandbox.helper.ts +54 -0
  48. package/src/helpers/Log.helper.ts +57 -17
  49. package/src/index.ts +192 -185
  50. package/src/index.ts.bak +192 -185
  51. package/src/subsystems/AgentManager/Agent.class.ts +11 -6
  52. package/src/subsystems/AgentManager/AgentRuntime.class.ts +13 -13
  53. package/src/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.ts +131 -0
  54. package/src/subsystems/ComputeManager/Code.service/index.ts +2 -0
  55. package/src/subsystems/LLMManager/LLM.helper.ts +57 -27
  56. package/src/subsystems/LLMManager/LLM.inference.ts +4 -0
  57. package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +125 -28
  58. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +18 -17
  59. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +2 -7
  60. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +2 -6
  61. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +26 -17
  62. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +2 -7
  63. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +2 -7
  64. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +314 -84
  65. package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +455 -0
  66. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +528 -0
  67. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.ts +100 -0
  68. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.ts +81 -0
  69. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +853 -0
  70. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.ts +37 -0
  71. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.ts +4 -0
  72. package/src/subsystems/LLMManager/LLM.service/connectors/openai/types.ts +37 -0
  73. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +0 -5
  74. package/src/subsystems/LLMManager/LLM.service/index.ts +1 -1
  75. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +2 -2
  76. package/src/subsystems/LLMManager/models.ts +1 -1
  77. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +18 -0
  78. package/src/subsystems/MemoryManager/RuntimeContext.ts +33 -16
  79. package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +68 -42
  80. package/src/types/LLM.types.ts +91 -43
  81. package/src/utils/data.utils.ts +3 -2
  82. package/src/subsystems/LLMManager/LLM.service/connectors/OpenAI.class.ts +0 -848
@@ -0,0 +1,37 @@
1
+ import { SearchToolCostConfig } from '../types';
2
+
3
+ export const MODELS_WITHOUT_TEMPERATURE_SUPPORT = ['o3-pro', 'o4-mini'];
4
+ export const MODELS_WITHOUT_PRESENCE_PENALTY_SUPPORT = ['o4-mini'];
5
+ export const MODELS_WITHOUT_JSON_RESPONSE_SUPPORT = ['o1-preview'];
6
+ export const MODELS_WITHOUT_SYSTEM_MESSAGE_SUPPORT = ['o1-mini', 'o1-preview'];
7
+
8
+ /**
9
+ * Search tool cost configuration
10
+ * Costs are in dollars per 1000 requests
11
+ */
12
+ export const SEARCH_TOOL_COSTS: SearchToolCostConfig = {
13
+ normalModels: {
14
+ 'gpt-4.1': {
15
+ low: 30 / 1000,
16
+ medium: 35 / 1000,
17
+ high: 50 / 1000,
18
+ },
19
+ 'gpt-4o': {
20
+ low: 30 / 1000,
21
+ medium: 35 / 1000,
22
+ high: 50 / 1000,
23
+ },
24
+ },
25
+ miniModels: {
26
+ 'gpt-4.1-mini': {
27
+ low: 25 / 1000,
28
+ medium: 27.5 / 1000,
29
+ high: 30 / 1000,
30
+ },
31
+ 'gpt-4o-mini': {
32
+ low: 25 / 1000,
33
+ medium: 27.5 / 1000,
34
+ high: 30 / 1000,
35
+ },
36
+ },
37
+ };
@@ -0,0 +1,4 @@
1
+ export { OpenAIApiInterface, ToolConfig } from './OpenAIApiInterface';
2
+ export { ResponsesApiInterface } from './ResponsesApiInterface';
3
+ export { ChatCompletionsApiInterface } from './ChatCompletionsApiInterface';
4
+ export { OpenAIApiInterfaceFactory } from './OpenAIApiInterfaceFactory';
@@ -0,0 +1,37 @@
1
+ import EventEmitter from 'events';
2
+ import OpenAI from 'openai';
3
+ import { ILLMRequestContext, APIKeySource } from '@sre/types/LLM.types';
4
+
5
+ export enum TToolType {
6
+ WebSearch = 'web_search_preview',
7
+ }
8
+
9
+ export interface IResponseHandler {
10
+ createStream(body: Record<string, unknown>, context: ILLMRequestContext): Promise<unknown>;
11
+ handleStream(stream: unknown, context: ILLMRequestContext): EventEmitter;
12
+ }
13
+
14
+ export type HandlerDependencies = {
15
+ getClient: (context: ILLMRequestContext) => Promise<OpenAI>;
16
+ reportUsage: (
17
+ usage: OpenAI.Completions.CompletionUsage & {
18
+ input_tokens?: number;
19
+ output_tokens?: number;
20
+ input_tokens_details?: { cached_tokens?: number };
21
+ prompt_tokens_details?: { cached_tokens?: number };
22
+ cost?: number;
23
+ },
24
+ metadata: { modelEntryName: string; keySource: APIKeySource; agentId: string; teamId: string }
25
+ ) => any;
26
+ };
27
+
28
+ export interface CostConfig {
29
+ [modelName: string]: {
30
+ [contextSize: string]: number;
31
+ };
32
+ }
33
+
34
+ export interface SearchToolCostConfig {
35
+ normalModels: CostConfig;
36
+ miniModels: CostConfig;
37
+ }
@@ -266,11 +266,6 @@ export class xAIConnector extends LLMConnector {
266
266
  return emitter;
267
267
  }
268
268
 
269
- // TODO: will be removed when we merge with interface support of OpenAI
270
- protected async webSearchRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
271
- throw new Error('Not implemented');
272
- }
273
-
274
269
  protected async reqBodyAdapter(params: TLLMParams): Promise<ChatCompletionParams> {
275
270
  const messages = params?.messages || [];
276
271
  const modelName = params.model as string;
@@ -3,7 +3,7 @@
3
3
  import { ConnectorService, ConnectorServiceProvider } from '@sre/Core/ConnectorsService';
4
4
  import { TConnectorService } from '@sre/types/SRE.types';
5
5
  import { EchoConnector } from './connectors/Echo.class';
6
- import { OpenAIConnector } from './connectors/OpenAI.class';
6
+ import { OpenAIConnector } from './connectors/openai/OpenAIConnector.class';
7
7
  import { GoogleAIConnector } from './connectors/GoogleAI.class';
8
8
  import { AnthropicConnector } from './connectors/Anthropic.class';
9
9
  import { GroqConnector } from './connectors/Groq.class';
@@ -43,7 +43,7 @@ export abstract class ModelsProviderConnector extends SecureConnector {
43
43
  const cacheKey = `ModelsProviderConnector:${candidate.toString()}`;
44
44
  if (ModelsProviderConnector.localCache.has(cacheKey)) {
45
45
  //update the TTL every time the requester is called
46
- return ModelsProviderConnector.localCache.get(cacheKey, 60 * 60 * 1000) as IModelsProviderRequest;
46
+ return ModelsProviderConnector.localCache.get(cacheKey, 10 * 60 * 1000) as IModelsProviderRequest;
47
47
  }
48
48
 
49
49
  let teamModels = null;
@@ -135,7 +135,7 @@ export abstract class ModelsProviderConnector extends SecureConnector {
135
135
  }
136
136
  },
137
137
  };
138
- ModelsProviderConnector.localCache.set(cacheKey, instance, 60 * 60 * 1000); // cache for 1 hour
138
+ ModelsProviderConnector.localCache.set(cacheKey, instance, 10 * 60 * 1000); // cache for 10 minutes
139
139
  return instance;
140
140
  }
141
141
 
@@ -745,7 +745,7 @@ export const models = {
745
745
  llm: 'GoogleAI',
746
746
 
747
747
  label: 'Gemini 2.5 Flash Preview',
748
- modelId: 'gemini-2.5-flash-preview-04-17',
748
+ modelId: 'gemini-2.5-flash',
749
749
  provider: 'GoogleAI',
750
750
  features: ['text', 'image', 'audio', 'video', 'document'],
751
751
  tags: ['New', 'Personal'],
@@ -26,9 +26,27 @@ export class RedisCache extends CacheConnector {
26
26
  let host = sentinels.length === 1 ? sentinels[0].host : null;
27
27
  let port = sentinels.length === 1 ? sentinels[0].port : null;
28
28
 
29
+ const redisConfig = {
30
+ // HEAVILY OPTIMIZED: Aggressive storm prevention parameters
31
+ maxRetriesPerRequest: 1, // VERY LIMITED retries (official)
32
+ retryDelayOnFailover: 50, // Fast failover (official)
33
+ connectTimeout: 3000, // SHORT timeout (official)
34
+ lazyConnect: false,
35
+ enableReadyCheck: false, // Skip ready check for speed (official)
36
+ commandTimeout: 2000, // VERY SHORT command timeout (official)
37
+ keepAlive: 10000, // Shorter keepalive - 10sec (official)
38
+ family: 4, // Force IPv4 (official)
39
+ maxLoadingTimeout: 2000, // Short loading timeout (official)
40
+ // Additional aggressive settings
41
+ enableOfflineQueue: false, // Disable offline queue (official)
42
+ db: 0, // Explicit DB (official)
43
+ stringNumbers: false, // No string conversion (official)
44
+ };
45
+
29
46
  this.redis = new IORedis({
30
47
  ...(host ? { host, port } : { sentinels, name: _settings.name || process.env.REDIS_MASTER_NAME }),
31
48
  password: _settings.password || process.env.REDIS_PASSWORD,
49
+ ...redisConfig,
32
50
  });
33
51
 
34
52
  this.redis.on('error', (error) => {
@@ -91,7 +91,7 @@ export class RuntimeContext extends EventEmitter {
91
91
  if (this._runtimeFileReady) return;
92
92
 
93
93
  const endpointDBGCall = this.runtime.xDebugId?.startsWith('dbg-'); //weak check for debug session, we need to improve this
94
- console.debug('Init ctxFile', this.ctxFile);
94
+ console.debug('Init Agent Context', this.ctxFile, AccessCandidate.agent(this.runtime.agent.id));
95
95
  const agent = this.runtime.agent;
96
96
  let method = (agent.agentRequest.method || 'POST').toUpperCase();
97
97
  const endpoint = agent.endpoints?.[agent.agentRequest.path]?.[method];
@@ -177,10 +177,9 @@ export class RuntimeContext extends EventEmitter {
177
177
  const exists = await this._cacheConnector.requester(AccessCandidate.agent(this.runtime.agent.id)).exists(this.ctxFile);
178
178
 
179
179
  if (exists) {
180
- if (this.runtime.debug)
181
- this._cacheConnector
182
- .requester(AccessCandidate.agent(this.runtime.agent.id))
183
- .updateTTL(this.ctxFile, 5 * 60); //expires in 5 minute
180
+ console.debug('Agent Context Delete', this.ctxFile, AccessCandidate.agent(this.runtime.agent.id));
181
+ if (this.runtime.debug) this._cacheConnector.requester(AccessCandidate.agent(this.runtime.agent.id)).updateTTL(this.ctxFile, 5 * 60);
182
+ //expires in 5 minute
184
183
  else this._cacheConnector.requester(AccessCandidate.agent(this.runtime.agent.id)).delete(this.ctxFile);
185
184
  //if (this.runtime.debug && fs.existsSync(this.ctxFile)) await delay(1000 * 60); //if we're in debug mode, we keep the file for a while to allow final state read
186
185
  //if (fs.existsSync(this.ctxFile)) fs.unlinkSync(this.ctxFile);
@@ -188,10 +187,13 @@ export class RuntimeContext extends EventEmitter {
188
187
  } else {
189
188
  const data = this.serialize();
190
189
  //if (data) fs.writeFileSync(this.ctxFile, JSON.stringify(data, null, 2));
191
- if (data)
190
+ if (data) {
191
+ const serializedData = JSON.stringify(data, null, 2);
192
+ console.debug('Agent Context Size', this.ctxFile, serializedData.length, AccessCandidate.agent(this.runtime.agent.id));
192
193
  await this._cacheConnector
193
194
  .requester(AccessCandidate.agent(this.runtime.agent.id))
194
- .set(this.ctxFile, JSON.stringify(data, null, 2), null, null, 6 * 60 * 60); //expires in 6 hours max
195
+ .set(this.ctxFile, serializedData, null, null, 3 * 60 * 60); //expires in 3 hours max
196
+ }
195
197
  }
196
198
  }
197
199
 
@@ -206,9 +208,14 @@ export class RuntimeContext extends EventEmitter {
206
208
  const component = ctxData.components[componentId];
207
209
 
208
210
  if (!component) {
209
- console.log('>>>>>>> updateComponent Component debug data not found', componentId, component);
210
- console.log('>>> ctxFile', this.ctxFile);
211
- console.log('>>> ctxData', ctxData);
211
+ console.debug(
212
+ '>>>>>>> updateComponent Component debug data not found',
213
+ componentId,
214
+ component,
215
+ AccessCandidate.agent(this.runtime.agent.id)
216
+ );
217
+ console.debug('>>> ctxFile', this.ctxFile, AccessCandidate.agent(this.runtime.agent.id));
218
+ console.debug('>>> ctxData', ctxData, AccessCandidate.agent(this.runtime.agent.id));
212
219
  }
213
220
  component.ctx = { ...component.ctx, ...data, step: this.step };
214
221
 
@@ -220,9 +227,14 @@ export class RuntimeContext extends EventEmitter {
220
227
  const ctxData = this;
221
228
  const component = ctxData.components[componentId];
222
229
  if (!component) {
223
- console.log('>>>>>>> resetComponent Component debug data not found', componentId, component);
224
- console.log('>>> ctxFile', this.ctxFile);
225
- console.log('>>> ctxData', ctxData);
230
+ console.debug(
231
+ '>>>>>>> resetComponent Component debug data not found',
232
+ componentId,
233
+ component,
234
+ AccessCandidate.agent(this.runtime.agent.id)
235
+ );
236
+ console.debug('>>> ctxFile', this.ctxFile, AccessCandidate.agent(this.runtime.agent.id));
237
+ console.debug('>>> ctxData', ctxData, AccessCandidate.agent(this.runtime.agent.id));
226
238
  }
227
239
  //component.dbg.active = false;
228
240
  //component.dbg.runtimeData = {};
@@ -237,9 +249,14 @@ export class RuntimeContext extends EventEmitter {
237
249
  if (!ctxData) return null;
238
250
  const component = ctxData.components[componentId];
239
251
  if (!component) {
240
- console.log('>>>>>>> getComponentData Component debug data not found', componentId, component);
241
- console.log('>>> ctxFile', this.ctxFile);
242
- console.log('>>> ctxData', ctxData);
252
+ console.debug(
253
+ '>>>>>>> getComponentData Component debug data not found',
254
+ componentId,
255
+ component,
256
+ AccessCandidate.agent(this.runtime.agent.id)
257
+ );
258
+ console.debug('>>> ctxFile', this.ctxFile, AccessCandidate.agent(this.runtime.agent.id));
259
+ console.debug('>>> ctxData', ctxData, AccessCandidate.agent(this.runtime.agent.id));
243
260
  }
244
261
  //const data = this.debug ? component.dbg : component.ctx;
245
262
  const data = component.ctx;
@@ -13,6 +13,7 @@ import crypto from 'crypto';
13
13
  import fs from 'fs';
14
14
  import * as readlineSync from 'readline-sync';
15
15
  import path from 'path';
16
+ import * as chokidar from 'chokidar';
16
17
  import { findSmythPath } from '../../../../helpers/Sysconfig.helper';
17
18
 
18
19
  const console = Logger('JSONFileVault');
@@ -28,6 +29,8 @@ export class JSONFileVault extends VaultConnector {
28
29
  private vaultData: any;
29
30
  private index: any;
30
31
  private shared: string;
32
+ private vaultFile: string;
33
+ private watcher: chokidar.FSWatcher | null = null;
31
34
 
32
35
  constructor(protected _settings: JSONFileVaultConfig) {
33
36
  super(_settings);
@@ -35,48 +38,9 @@ export class JSONFileVault extends VaultConnector {
35
38
 
36
39
  this.shared = _settings.shared || ''; //if config.shared, all keys are accessible to all teams, and they are set under the 'shared' teamId
37
40
 
38
- let vaultFile = this.findVaultFile(_settings.file);
39
- this.vaultData = {};
40
- if (fs.existsSync(vaultFile)) {
41
- try {
42
- if (_settings.fileKey && fs.existsSync(_settings.fileKey)) {
43
- try {
44
- const privateKey = fs.readFileSync(_settings.fileKey, 'utf8');
45
- const encryptedVault = fs.readFileSync(vaultFile, 'utf8').toString();
46
- const decryptedBuffer = crypto.privateDecrypt(
47
- {
48
- key: privateKey,
49
- padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
50
- },
51
- Buffer.from(encryptedVault, 'base64')
52
- );
53
- this.vaultData = JSON.parse(decryptedBuffer.toString('utf8'));
54
- } catch (error) {
55
- throw new Error('Failed to decrypt vault');
56
- }
57
- } else {
58
- this.vaultData = JSON.parse(fs.readFileSync(vaultFile).toString());
59
- }
60
- } catch (e) {
61
- console.error('Error parsing vault file:', e);
62
- console.error('!!! Vault features might not work properly !!!');
63
- this.vaultData = {};
64
- }
65
-
66
- if (this.vaultData?.encrypted && this.vaultData?.algorithm && this.vaultData?.data) {
67
- //this is an encrypted vault we need to request the master key
68
- this.setInteraction(this.getMasterKeyInteractive.bind(this));
69
- }
70
-
71
- for (let teamId in this.vaultData) {
72
- for (let resourceId in this.vaultData[teamId]) {
73
- if (!this.index) this.index = {};
74
- if (!this.index[resourceId]) this.index[resourceId] = {};
75
- const value = this.vaultData[teamId][resourceId];
76
- this.index[resourceId][teamId] = value;
77
- }
78
- }
79
- }
41
+ this.vaultFile = this.findVaultFile(_settings.file);
42
+ this.fetchVaultData(this.vaultFile, _settings);
43
+ this.initFileWatcher();
80
44
  }
81
45
 
82
46
  private findVaultFile(vaultFile) {
@@ -192,4 +156,66 @@ export class JSONFileVault extends VaultConnector {
192
156
 
193
157
  return acl;
194
158
  }
159
+
160
+ private fetchVaultData(vaultFile: string, _settings: JSONFileVaultConfig) {
161
+ if (fs.existsSync(vaultFile)) {
162
+ try {
163
+ if (_settings.fileKey && fs.existsSync(_settings.fileKey)) {
164
+ try {
165
+ const privateKey = fs.readFileSync(_settings.fileKey, 'utf8');
166
+ const encryptedVault = fs.readFileSync(vaultFile, 'utf8').toString();
167
+ const decryptedBuffer = crypto.privateDecrypt(
168
+ {
169
+ key: privateKey,
170
+ padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
171
+ },
172
+ Buffer.from(encryptedVault, 'base64')
173
+ );
174
+ this.vaultData = JSON.parse(decryptedBuffer.toString('utf8'));
175
+ } catch (error) {
176
+ throw new Error('Failed to decrypt vault');
177
+ }
178
+ } else {
179
+ this.vaultData = JSON.parse(fs.readFileSync(vaultFile).toString());
180
+ }
181
+ } catch (e) {
182
+ console.error('Error parsing vault file:', e);
183
+ console.error('!!! Vault features might not work properly !!!');
184
+ this.vaultData = {};
185
+ }
186
+
187
+ if (this.vaultData?.encrypted && this.vaultData?.algorithm && this.vaultData?.data) {
188
+ //this is an encrypted vault we need to request the master key
189
+ this.setInteraction(this.getMasterKeyInteractive.bind(this));
190
+ }
191
+
192
+ for (let teamId in this.vaultData) {
193
+ for (let resourceId in this.vaultData[teamId]) {
194
+ if (!this.index) this.index = {};
195
+ if (!this.index[resourceId]) this.index[resourceId] = {};
196
+ const value = this.vaultData[teamId][resourceId];
197
+ this.index[resourceId][teamId] = value;
198
+ }
199
+ }
200
+ }
201
+ }
202
+
203
+ private initFileWatcher() {
204
+ this.watcher = chokidar.watch(this.vaultFile, {
205
+ persistent: false, // Don't keep the process running
206
+ ignoreInitial: true,
207
+ });
208
+
209
+ this.watcher.on('change', () => {
210
+ this.fetchVaultData(this.vaultFile, this._settings);
211
+ });
212
+ }
213
+
214
+ public async stop() {
215
+ super.stop();
216
+ if (this.watcher) {
217
+ this.watcher.close();
218
+ this.watcher = null;
219
+ }
220
+ }
195
221
  }
@@ -45,10 +45,47 @@ export type ILLMConnectorCredentials = BasicCredentials | BedrockCredentials | V
45
45
  export type TOpenAIResponseToolChoice = OpenAI.Responses.ToolChoiceOptions | OpenAI.Responses.ToolChoiceTypes | OpenAI.Responses.ToolChoiceFunction;
46
46
  export type TLLMToolChoice = OpenAI.ChatCompletionToolChoiceOption;
47
47
 
48
+ export type TOpenAIToolsInfo = {
49
+ webSearch: {
50
+ enabled: boolean;
51
+ contextSize: TSearchContextSize;
52
+ city?: string;
53
+ country?: string;
54
+ region?: string;
55
+ timezone?: string;
56
+ };
57
+ };
58
+
59
+ export type TxAIToolsInfo = {
60
+ search: {
61
+ enabled: boolean;
62
+ mode?: 'auto' | 'on' | 'off';
63
+ returnCitations?: boolean;
64
+ maxResults?: number;
65
+ dataSources?: string[];
66
+ country?: string;
67
+ excludedWebsites?: string[];
68
+ allowedWebsites?: string[];
69
+ includedXHandles?: string[];
70
+ excludedXHandles?: string[];
71
+ postFavoriteCount?: number;
72
+ postViewCount?: number;
73
+ rssLinks?: string;
74
+ safeSearch?: boolean;
75
+ fromDate?: string;
76
+ toDate?: string;
77
+ };
78
+ };
79
+
80
+ export type TToolsInfo = {
81
+ openai: TOpenAIToolsInfo;
82
+ xai: TxAIToolsInfo;
83
+ };
84
+
85
+ export type TSearchContextSize = 'low' | 'medium' | 'high';
86
+
48
87
  export type TLLMParams = {
49
88
  model: TLLMModel | string;
50
- modelEntryName?: string; // for usage reporting
51
- credentials?: ILLMConnectorCredentials;
52
89
 
53
90
  prompt?: string;
54
91
  messages?: any[]; // TODO [Forhad]: apply proper typing
@@ -84,14 +121,15 @@ export type TLLMParams = {
84
121
  maxThinkingTokens?: number;
85
122
 
86
123
  // #region Search
124
+ // Web search parameters (will be organized into toolsInfo.webSearch internally)
87
125
  useWebSearch?: boolean;
88
- webSearchContextSize?: 'high' | 'medium' | 'low';
126
+ webSearchContextSize?: TSearchContextSize;
89
127
  webSearchCity?: string;
90
128
  webSearchCountry?: string;
91
129
  webSearchRegion?: string;
92
130
  webSearchTimezone?: string;
93
131
 
94
- // xAI specific search parameters
132
+ // xAI specific search parameters (consider moving to toolsInfo.xaiSearch)
95
133
  useSearch?: boolean;
96
134
  searchMode?: 'auto' | 'on' | 'off';
97
135
  returnCitations?: boolean;
@@ -111,7 +149,14 @@ export type TLLMParams = {
111
149
  // #endregion
112
150
 
113
151
  useReasoning?: boolean;
152
+ max_output_tokens?: number;
153
+ abortSignal?: AbortSignal;
154
+ };
114
155
 
156
+ export type TLLMPreparedParams = TLLMParams & {
157
+ body: any;
158
+ modelEntryName?: string; // for usage reporting
159
+ credentials?: ILLMConnectorCredentials;
115
160
  isUserKey?: boolean;
116
161
  capabilities?: {
117
162
  search?: boolean;
@@ -119,43 +164,7 @@ export type TLLMParams = {
119
164
  imageGeneration?: boolean;
120
165
  imageEditing?: boolean;
121
166
  };
122
- max_output_tokens?: number;
123
-
124
- abortSignal?: AbortSignal;
125
- };
126
-
127
- export type TLLMParamsV2 = {
128
- model: string;
129
- modelEntryName: string;
130
- messages: any[];
131
- toolsConfig?: {
132
- tools?: OpenAI.Responses.Tool[];
133
- tool_choice?: OpenAI.Responses.ToolChoiceOptions | OpenAI.Responses.ToolChoiceTypes | OpenAI.Responses.ToolChoiceFunction;
134
- };
135
- baseURL?: string;
136
- stream?: boolean;
137
- responseFormat?: any;
138
- credentials?: {
139
- apiKey?: string;
140
- isUserKey?: boolean;
141
- };
142
- max_output_tokens?: number;
143
- temperature?: number;
144
- top_p?: number;
145
- top_k?: number;
146
- frequency_penalty?: number;
147
- presence_penalty?: number;
148
- teamId?: string;
149
- files?: BinaryInput[];
150
-
151
- // #region Search
152
- useWebSearch?: boolean;
153
- webSearchContextSize?: 'high' | 'medium' | 'low';
154
- webSearchCity?: string;
155
- webSearchCountry?: string;
156
- webSearchRegion?: string;
157
- webSearchTimezone?: string;
158
- // #endregion
167
+ toolsInfo?: TToolsInfo;
159
168
  };
160
169
 
161
170
  export type TLLMConnectorParams = Omit<TLLMParams, 'model'> & {
@@ -207,6 +216,12 @@ export type TLLMModel = {
207
216
  //models can come with predefined params
208
217
  //this can also be used to pass a preconfigured model object
209
218
  params?: TLLMParams;
219
+ /**
220
+ * Specifies the API interface type to use for this model
221
+ * Examples: 'chat.completions', 'responses'
222
+ * This determines which OpenAI API endpoint and interface implementation to use
223
+ */
224
+ interface?: 'chat.completions' | 'responses';
210
225
  };
211
226
 
212
227
  // #region [ Handle extendable LLM Providers ] ================================================
@@ -245,6 +260,7 @@ export type TVertexAISettings = {
245
260
  projectId: string;
246
261
  credentialsName: string;
247
262
  jsonCredentialsName: string;
263
+ apiEndpoint?: string;
248
264
  };
249
265
 
250
266
  export type TCustomLLMModel = TLLMModel & {
@@ -269,16 +285,47 @@ export type ToolData = {
269
285
  error?: string; // for Bedrock
270
286
  };
271
287
 
272
- export interface AnthropicToolDefinition {
288
+ /**
289
+ * Base tool definition interface - only truly common properties
290
+ * All provider-specific tool definitions extend from this
291
+ */
292
+ export interface ToolDefinition {
273
293
  name: string;
274
294
  description: string;
295
+ }
296
+
297
+ /**
298
+ * OpenAI-specific tool definition
299
+ * Extends base with OpenAI's parameter format
300
+ */
301
+ export interface OpenAIToolDefinition extends ToolDefinition {
302
+ parameters: {
303
+ type: 'object';
304
+ properties: Record<string, unknown>;
305
+ required?: string[];
306
+ };
307
+ }
308
+
309
+ /**
310
+ * Anthropic-specific tool definition
311
+ * Extends base with Anthropic's input_schema format
312
+ */
313
+ export interface AnthropicToolDefinition extends ToolDefinition {
275
314
  input_schema: {
276
315
  type: 'object';
277
316
  properties: Record<string, unknown>;
278
317
  required: string[];
279
318
  };
280
319
  }
281
- export type ToolDefinition = OpenAI.ChatCompletionTool | AnthropicToolDefinition;
320
+
321
+ /**
322
+ * Legacy tool definition for backward compatibility
323
+ * @deprecated Use provider-specific definitions instead
324
+ */
325
+ export interface LegacyToolDefinition extends ToolDefinition {
326
+ properties?: Record<string, unknown>;
327
+ requiredFields?: string[];
328
+ }
282
329
  export type ToolChoice = OpenAI.ChatCompletionToolChoiceOption | FunctionCallingMode;
283
330
 
284
331
  export interface ToolsConfig {
@@ -397,6 +444,7 @@ export interface ILLMRequestContext {
397
444
  hasFiles?: boolean;
398
445
  modelInfo: TCustomLLMModel | TLLMModel;
399
446
  credentials: ILLMConnectorCredentials;
447
+ toolsInfo?: TToolsInfo;
400
448
  }
401
449
 
402
450
  // Generic interface that can be extended by specific providers
@@ -7,6 +7,7 @@ import { isBinaryFileSync } from 'isbinaryfile';
7
7
  import { fileTypeFromBuffer } from 'file-type';
8
8
  import { BinaryInput } from '@sre/helpers/BinaryInput.helper';
9
9
  import { identifyMimetypeFromString } from './string.utils';
10
+ import { IAccessCandidate } from '@sre/types/ACL.types';
10
11
 
11
12
  // Helper function to convert stream to buffer
12
13
  export async function streamToBuffer(stream: Readable): Promise<Buffer> {
@@ -250,7 +251,7 @@ export async function getMimeType(data: any): Promise<string> {
250
251
 
251
252
  // Mask data like Buffer, FormData, etc. in debug output
252
253
  // TODO [Forhad]: Need to get the size of FormData
253
- export async function formatDataForDebug(data: any) {
254
+ export async function formatDataForDebug(data: any, candidate: IAccessCandidate) {
254
255
  let dataForDebug;
255
256
 
256
257
  if (!data) {
@@ -259,7 +260,7 @@ export async function formatDataForDebug(data: any) {
259
260
 
260
261
  try {
261
262
  if (data.constructor?.name === 'BinaryInput') {
262
- const jsonData = await data.getJsonData();
263
+ const jsonData = await data.getJsonData(candidate);
263
264
  dataForDebug = `[BinaryInput size=${jsonData?.size}]`;
264
265
  } else if (isBuffer(data)) {
265
266
  dataForDebug = `[Buffer size=${data.byteLength}]`;