@smythos/sre 1.5.68 → 1.5.71

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 (27) hide show
  1. package/dist/index.js +13 -14
  2. package/dist/index.js.map +1 -1
  3. package/dist/types/Components/MemoryDeleteKeyVal.class.d.ts +8 -0
  4. package/dist/types/Components/MemoryReadKeyVal.class.d.ts +7 -0
  5. package/dist/types/subsystems/IO/Storage.service/connectors/AzureBlobStorage.class.d.ts +211 -0
  6. package/dist/types/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.d.ts +3 -7
  7. package/dist/types/subsystems/LLMManager/models.d.ts +0 -1
  8. package/dist/types/types/LLM.types.d.ts +1 -1
  9. package/package.json +5 -1
  10. package/src/Components/ECMASandbox.class.ts +4 -3
  11. package/src/Components/MemoryDeleteKeyVal.class.ts +3 -3
  12. package/src/Components/MemoryReadKeyVal.class.ts +5 -4
  13. package/src/Components/MemoryWriteObject.class.ts +1 -1
  14. package/src/helpers/AWSLambdaCode.helper.ts +30 -22
  15. package/src/helpers/Conversation.helper.ts +19 -9
  16. package/src/helpers/ECMASandbox.helper.ts +17 -7
  17. package/src/helpers/Sysconfig.helper.ts +18 -0
  18. package/src/index.ts +194 -194
  19. package/src/index.ts.bak +194 -194
  20. package/src/subsystems/AgentManager/AgentData.service/connectors/LocalAgentDataConnector.class.ts +3 -0
  21. package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +93 -108
  22. package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +1 -1
  23. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +1 -1
  24. package/src/subsystems/LLMManager/LLM.inference.ts +3 -0
  25. package/src/subsystems/LLMManager/models.ts +2 -2
  26. package/src/subsystems/Security/Account.service/connectors/JSONFileAccount.class.ts +6 -0
  27. package/src/types/LLM.types.ts +1 -1
@@ -6,13 +6,21 @@ export declare class MemoryDeleteKeyVal extends Component {
6
6
  constructor();
7
7
  init(): void;
8
8
  process(input: any, config: any, agent: Agent): Promise<{
9
+ _warning: string;
10
+ _debug: string;
11
+ Key?: undefined;
12
+ deleted?: undefined;
13
+ _error?: undefined;
14
+ } | {
9
15
  Key: string;
10
16
  deleted: boolean;
11
17
  _debug: string;
18
+ _warning?: undefined;
12
19
  _error?: undefined;
13
20
  } | {
14
21
  _error: any;
15
22
  _debug: string;
23
+ _warning?: undefined;
16
24
  Key?: undefined;
17
25
  deleted?: undefined;
18
26
  }>;
@@ -6,12 +6,19 @@ export declare class MemoryReadKeyVal extends Component {
6
6
  constructor();
7
7
  init(): void;
8
8
  process(input: any, config: any, agent: Agent): Promise<{
9
+ _warning: string;
10
+ _debug: string;
11
+ Value?: undefined;
12
+ _error?: undefined;
13
+ } | {
9
14
  Value: any;
10
15
  _debug: string;
16
+ _warning?: undefined;
11
17
  _error?: undefined;
12
18
  } | {
13
19
  _error: any;
14
20
  _debug: string;
21
+ _warning?: undefined;
15
22
  Value?: undefined;
16
23
  }>;
17
24
  }
@@ -0,0 +1,211 @@
1
+ import { StorageConnector } from '@sre/IO/Storage.service/StorageConnector';
2
+ import { ACL } from '@sre/Security/AccessControl/ACL.class';
3
+ import { IAccessCandidate, IACL } from '@sre/types/ACL.types';
4
+ import { StorageData, StorageMetadata } from '@sre/types/Storage.types';
5
+ import { AccessRequest } from '@sre/Security/AccessControl/AccessRequest.class';
6
+ export type AzureBlobConfig = {
7
+ storageAccountName: string;
8
+ storageAccountAccessKey: string;
9
+ blobContainerName: string;
10
+ };
11
+ export declare class AzureBlobStorage extends StorageConnector {
12
+ protected _settings: AzureBlobConfig;
13
+ name: string;
14
+ private blobServiceClient;
15
+ private containerClient;
16
+ private isInitialized;
17
+ private initializationPromise;
18
+ constructor(_settings: AzureBlobConfig);
19
+ private ensureInitialized;
20
+ private initialize;
21
+ /**
22
+ * Reads a blob's content from the Azure Storage container.
23
+ * This method fetches the entire blob content into a Buffer. If the specified
24
+ * blob does not exist, it gracefully returns undefined.
25
+ *
26
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
27
+ * @param {string} resourceId - The unique identifier (name) of the blob to be read from the container.
28
+ * @returns {Promise<StorageData | undefined>} A promise that resolves with the blob's content as a Buffer (`StorageData`), or undefined if the blob is not found.
29
+ * @throws Throws an error if any other issue occurs during the download process (e.g., network issues, permissions problems).
30
+ */
31
+ read(acRequest: AccessRequest, resourceId: string): Promise<StorageData | undefined>;
32
+ /**
33
+ * Writes or overwrites a blob in the Azure Storage container.
34
+ *
35
+ * This method uploads data to a specified blob. It automatically handles the SmythOS
36
+ * Access Control List (ACL) by ensuring the writer is made the owner of the object.
37
+ * Any provided metadata is merged with this ACL and stored with the blob.
38
+ * If a blob with the same `resourceId` already exists, this operation will completely replace its content and metadata.
39
+ *
40
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
41
+ * @param {string} resourceId - The unique identifier (name) of the blob to be written or overwritten.
42
+ * @param {StorageData} value - The content to be written to the blob, typically a Buffer.
43
+ * @param {IACL} [acl] - An optional Access Control List to apply to the blob. If not provided, a default ACL is generated.
44
+ * @param {StorageMetadata} [metadata] - Optional key-value metadata to associate with the blob, including properties like `ContentType`.
45
+ * @returns {Promise<void>} A promise that resolves when the upload operation is complete.
46
+ * @throws Throws an error if the upload fails due to network issues, invalid credentials, or other storage-related problems.
47
+ */
48
+ write(acRequest: AccessRequest, resourceId: string, value: StorageData, acl?: IACL, metadata?: StorageMetadata): Promise<void>;
49
+ /**
50
+ * Deletes a blob from the Azure Storage container.
51
+ *
52
+ * This method permanently removes the specified blob. The operation is idempotent,
53
+ * meaning it will complete successfully without error even if the blob does not
54
+ * already exist. This is useful for ensuring a resource is gone without needing to
55
+ * check for its existence first.
56
+ *
57
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
58
+ * @param {string} resourceId - The unique identifier (name) of the blob to be deleted.
59
+ * @returns {Promise<void>} A promise that resolves when the delete operation is complete.
60
+ * @throws Throws an error if the deletion fails for reasons other than the blob not existing (e.g., network issues, permissions problems).
61
+ */
62
+ delete(acRequest: AccessRequest, resourceId: string): Promise<void>;
63
+ /**
64
+ * Checks for the existence of a blob in the Azure Storage container.
65
+ *
66
+ * This method efficiently verifies if a blob with the specified `resourceId` is
67
+ * present without downloading its content. It's the most performant way to
68
+ * check for a blob's presence before performing other operations.
69
+ *
70
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
71
+ * @param {string} resourceId - The unique identifier (name) of the blob to check.
72
+ * @returns {Promise<boolean>} A promise that resolves with `true` if the blob exists, and `false` otherwise.
73
+ * @throws Throws an error for any issue other than the blob not being found (e.g., network issues, invalid credentials).
74
+ */
75
+ exists(acRequest: AccessRequest, resourceId: string): Promise<boolean>;
76
+ /**
77
+ * Retrieves the user-defined metadata for a specific blob.
78
+ *
79
+ * This method fetches the key-value metadata associated with a blob without
80
+ * downloading the blob's content. It's an efficient way to read custom
81
+ * information stored with an object. If the blob is not found, it returns undefined.
82
+ *
83
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
84
+ * @param {string} resourceId - The unique identifier (name) of the blob whose metadata is to be retrieved.
85
+ * @returns {Promise<StorageMetadata | undefined>} A promise that resolves with the blob's metadata object, or undefined if the blob does not exist.
86
+ * @throws Throws an error for any issue other than the blob not being found (e.g., network issues, invalid credentials).
87
+ */
88
+ getMetadata(acRequest: AccessRequest, resourceId: string): Promise<StorageMetadata | undefined>;
89
+ /**
90
+ * Sets or updates the user-defined metadata for a specific blob.
91
+ *
92
+ * This method applies new metadata to an existing blob. It performs a "merge and
93
+ * update" operation: it first reads the blob's current metadata, then merges
94
+ * the provided metadata with it (new values overwrite existing ones).
95
+ * This operation does not affect the blob's content.
96
+ *
97
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
98
+ * @param {string} resourceId - The unique identifier (name) of the blob whose metadata is to be updated.
99
+ * @param {StorageMetadata} metadata - An object containing the key-value pairs to set. These will be merged with any existing metadata.
100
+ * @returns {Promise<void>} A promise that resolves when the metadata has been successfully updated.
101
+ * @throws Throws an error if the blob does not exist, or if the update fails for other reasons (e.g., network issues).
102
+ */
103
+ setMetadata(acRequest: AccessRequest, resourceId: string, metadata: StorageMetadata): Promise<void>;
104
+ /**
105
+ * Retrieves the Access Control List (ACL) for a specific blob.
106
+ *
107
+ * This method fetches the blob's metadata and specifically extracts the
108
+ * SmythOS-native ACL object. It provides a direct way to inspect the
109
+ * permissions of a blob without downloading its content.
110
+ *
111
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
112
+ * @param {string} resourceId - The unique identifier (name) of the blob whose ACL is to be retrieved.
113
+ * @returns {Promise<ACL | undefined>} A promise that resolves with the `ACL` object for the blob. Returns undefined if the blob does not exist or has no ACL.
114
+ * @throws Throws an error for any issue other than the blob not being found (e.g., network issues, invalid credentials).
115
+ */
116
+ getACL(acRequest: AccessRequest, resourceId: string): Promise<ACL | undefined>;
117
+ /**
118
+ * Sets or updates the Access Control List (ACL) for a specific blob.
119
+ *
120
+ * This method applies a new SmythOS ACL to an existing blob. It reads the blob's
121
+ * full metadata, replaces the ACL portion, and writes the updated metadata back.
122
+ * A crucial security feature of this method is that it automatically ensures the
123
+ * user/agent making the request always retains ownership of the blob.
124
+ *
125
+ * @param {AccessRequest} acRequest - The access request object, used to identify the user/agent to ensure they retain ownership.
126
+ * @param {string} resourceId - The unique identifier (name) of the blob whose ACL is to be updated.
127
+ * @param {IACL} acl - The new Access Control List object to apply to the blob.
128
+ * @returns {Promise<void>} A promise that resolves when the ACL has been successfully updated.
129
+ * @throws Throws an error if the blob does not exist or if the update fails for other reasons.
130
+ */
131
+ setACL(acRequest: AccessRequest, resourceId: string, acl: IACL): Promise<void>;
132
+ /**
133
+ * Determines the effective Access Control List (ACL) for a given resource.
134
+ *
135
+ * This crucial security method is called by the access control system to fetch a
136
+ * resource's ACL before making an authorization decision. If the resource does
137
+ * not exist (and thus has no ACL), this method dynamically generates a new ACL
138
+ * that grants 'Owner' access to the requesting candidate. This is the mechanism
139
+ * that allows authorized users to create new resources.
140
+ *
141
+ * @param {string} resourceId - The unique identifier (name) of the blob whose ACL is to be determined.
142
+ * @param {IAccessCandidate} candidate - The user or agent attempting to access the resource, used to grant ownership if the resource is new.
143
+ * @returns {Promise<ACL>} A promise that resolves with the existing ACL object if the blob is found, or a new ACL object granting ownership if the blob does not exist.
144
+ * @throws Throws an error if there is an unexpected issue fetching the blob's metadata (e.g., network issues).
145
+ */
146
+ getResourceACL(resourceId: string, candidate: IAccessCandidate): Promise<ACL>;
147
+ /**
148
+ * Schedules a blob for automatic deletion after a specified time-to-live (TTL).
149
+ *
150
+ * This method applies a Blob Index Tag ('deleteAfterDays') to an existing blob.
151
+ * It does not delete the blob immediately. Instead, it relies on a pre-configured
152
+ * Lifecycle Management rule on the Azure Storage Account to automatically delete the
153
+ * blob after the specified number of days.
154
+ *
155
+ * @param {AccessRequest} acRequest - The access request object, handled by the @SecureConnector decorator to authorize the operation.
156
+ * @param {string} resourceId - The unique identifier (name) of the blob to schedule for deletion.
157
+ * @param {number} ttl - The time-to-live for the blob, in seconds. Must be a positive number.
158
+ * @returns {Promise<void>} A promise that resolves when the expiration tag has been successfully applied.
159
+ * @throws Throws an error if the blob does not exist, if the TTL is invalid, or if applying the tag fails.
160
+ */
161
+ expire(acRequest: AccessRequest, resourceId: string, ttl: number): Promise<void>;
162
+ /**
163
+ * Migrates legacy ACL metadata to the new structured format.
164
+ *
165
+ * This internal helper function checks for an outdated ACL format where permissions
166
+ * were stored in separate keys like `userid`, `teamid`, or `agentid`. If found,
167
+ * it converts them into the modern, structured `azure-acl` object, granting full
168
+ * ownership. This ensures seamless backward compatibility with older data.
169
+ *
170
+ * @param {Record<string, string>} metadata - The raw metadata object which may contain legacy ACL keys.
171
+ * @returns {Record<string, any>} The metadata object, with legacy keys converted into a new `azure-acl` property.
172
+ * @private
173
+ */
174
+ private _migrateMetadata;
175
+ /**
176
+ * Serializes the internal metadata object into a format compatible with Azure Blob Storage.
177
+ *
178
+ * This internal helper prepares the metadata for upload. It converts the `ACL` object
179
+ * into its serialized string representation and stringifies any other non-string
180
+ * metadata values. The `ContentType` property is intentionally excluded as it's
181
+ * handled separately in the blob's HTTP headers.
182
+ *
183
+ * @param {Record<string, any>} metadata - The internal metadata object, containing mixed-type values.
184
+ * @returns {Record<string, string>} A flat key-value object where all values are strings.
185
+ * @private
186
+ */
187
+ private _serializeAzureMetadata;
188
+ /**
189
+ * Deserializes a flat metadata object from Azure into the rich internal format.
190
+ *
191
+ * This internal helper processes the raw string-based metadata retrieved from a blob.
192
+ * It reconstructs the `ACL` object from its string representation and parses any
193
+ * other JSON-stringified values back into their original object/data types. It then
194
+ * calls the migration helper to ensure backward compatibility with legacy ACL formats.
195
+ *
196
+ * @param {Record<string, string>} metadata - The flat, string-only key-value metadata from the Azure SDK.
197
+ * @returns {Record<string, any>} The rich internal metadata object with complex data types restored.
198
+ * @private
199
+ */
200
+ private _deserializeAzureMetadata;
201
+ /**
202
+ * Private helper to fetch and deserialize metadata from Azure.
203
+ * @private
204
+ */
205
+ private _getAzureMetadata;
206
+ /**
207
+ * Private helper to serialize and write metadata to Azure.
208
+ * @private
209
+ */
210
+ private _setAzureMetadata;
211
+ }
@@ -1,7 +1,7 @@
1
1
  import { ACL } from '@sre/Security/AccessControl/ACL.class';
2
2
  import { IAccessCandidate } from '@sre/types/ACL.types';
3
3
  import { AccessRequest } from '@sre/Security/AccessControl/AccessRequest.class';
4
- import { VectorDBConnector } from '../VectorDBConnector';
4
+ import { VectorDBConnector, DeleteTarget } from '../VectorDBConnector';
5
5
  import { DatasourceDto, IStorageVectorDataSource, IStorageVectorNamespace, IVectorDataSourceDto, QueryOptions, VectorsResultData } from '@sre/types/VectorDB.types';
6
6
  import { BaseEmbedding, TEmbeddings } from '../embed/BaseEmbedding';
7
7
  export type RAMVectorDBConfig = {
@@ -36,17 +36,13 @@ export declare class RAMVectorDB extends VectorDBConnector {
36
36
  protected deleteNamespace(acRequest: AccessRequest, namespace: string): Promise<void>;
37
37
  protected search(acRequest: AccessRequest, namespace: string, query: string | number[], options?: QueryOptions): Promise<VectorsResultData>;
38
38
  protected insert(acRequest: AccessRequest, namespace: string, sourceWrapper: IVectorDataSourceDto | IVectorDataSourceDto[]): Promise<string[]>;
39
- protected delete(acRequest: AccessRequest, namespace: string, id: string | string[]): Promise<void>;
39
+ protected delete(acRequest: AccessRequest, namespace: string, deleteTarget: DeleteTarget): Promise<void>;
40
40
  protected createDatasource(acRequest: AccessRequest, namespace: string, datasource: DatasourceDto): Promise<IStorageVectorDataSource>;
41
41
  protected deleteDatasource(acRequest: AccessRequest, namespace: string, datasourceId: string): Promise<void>;
42
42
  protected listDatasources(acRequest: AccessRequest, namespace: string): Promise<IStorageVectorDataSource[]>;
43
- protected getDatasource(acRequest: AccessRequest, namespace: string, datasourceId: string): Promise<IStorageVectorDataSource>;
43
+ protected getDatasource(acRequest: AccessRequest, namespace: string, datasourceId: string): Promise<IStorageVectorDataSource | undefined>;
44
44
  /**
45
45
  * Calculate cosine similarity between two vectors
46
46
  */
47
47
  private cosineSimilarity;
48
- /**
49
- * Split text into chunks with overlap
50
- */
51
- private splitTextIntoChunks;
52
48
  }
@@ -55,7 +55,6 @@ export declare const models: {
55
55
  };
56
56
  'gpt-4o-mini': {
57
57
  llm: string;
58
- alias: string;
59
58
  components: string[];
60
59
  label: string;
61
60
  modelId: string;
@@ -189,7 +189,7 @@ export type TLLMModel = {
189
189
  tokens: number;
190
190
  completionTokens: number;
191
191
  };
192
- credentials?: TLLMCredentials;
192
+ credentials?: TLLMCredentials | TLLMCredentials[];
193
193
  params?: TLLMParams;
194
194
  /**
195
195
  * Specifies the API interface type to use for this model
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smythos/sre",
3
- "version": "1.5.68",
3
+ "version": "1.5.71",
4
4
  "description": "Smyth Runtime Environment",
5
5
  "author": "Alaa-eddine KADDOURI",
6
6
  "license": "MIT",
@@ -107,6 +107,10 @@
107
107
  "build:types": "tsc --emitDeclarationOnly --declaration --outDir dist/types -p tsconfig.dts.json",
108
108
  "build:jsbundle": "cross-env rollup -c",
109
109
  "build": "pnpm run build:jsbundle && pnpm run build:types",
110
+ "test:unit": "cd ../.. && vitest run packages/core/tests/unit",
111
+ "test:unit:watch": "cd ../.. && vitest watch packages/core/tests/unit",
112
+ "test:integration": "cd ../.. && vitest run packages/core/tests/integration",
113
+ "test:integration:watch": "cd ../.. && vitest watch packages/core/tests/integration",
110
114
  "gen:docs": "typedoc",
111
115
  "doc:graphgen": "npx depcruise src --config ./doc/.dep-minimal.json --output-type dot > ./doc/dep-graph.dot && dot -Tpng ./doc/dep-graph.dot -o ./doc/dep-graph.png",
112
116
  "knip": "knip"
@@ -38,14 +38,15 @@ export class ECMASandbox extends Component {
38
38
  }
39
39
  }
40
40
 
41
- const inputVarsCode = this.generateInputVarCode(codeInputs);
42
- const code = inputVarsCode + '\n' + config.data.code;
41
+ //const inputVarsCode = this.generateInputVarCode(codeInputs);
42
+ //const code = inputVarsCode + '\n' + config.data.code;
43
+ const code = config.data.code;
43
44
 
44
45
  logger.debug(`Running code: \n${code}\n`);
45
46
 
46
47
  const ecmaCodeConnector = ConnectorService.getCodeConnector('ECMASandbox');
47
48
 
48
- const executionResponse: CodeExecutionResult = await ecmaCodeConnector.agent(agent.id).execute(config.id, { code });
49
+ const executionResponse: CodeExecutionResult = await ecmaCodeConnector.agent(agent.id).execute(config.id, { code, inputs: input });
49
50
  if (executionResponse.success) {
50
51
  Output = executionResponse.output;
51
52
  } else {
@@ -37,7 +37,7 @@ export class MemoryDeleteKeyVal extends Component {
37
37
  const scopeStrData = await connectorRequester.get(scopeKeyId);
38
38
 
39
39
  if (!scopeStrData) {
40
- return { _error: 'key not found', _debug: logger.output };
40
+ return { _warning: 'key not found', _debug: logger.output };
41
41
  }
42
42
 
43
43
  logger.debug(`Checking Scope for deletion`);
@@ -46,11 +46,11 @@ export class MemoryDeleteKeyVal extends Component {
46
46
 
47
47
  // Validate scope access like in MemoryReadKeyVal
48
48
  if (scopeData.scope === 'session' && scopeKey !== sessionId) {
49
- return { _error: 'key not found', _debug: logger.output };
49
+ return { _warning: 'key not found', _debug: logger.output };
50
50
  }
51
51
 
52
52
  if (scopeData.scope === 'request' && scopeKey !== workflowId) {
53
- return { _error: 'key not found', _debug: logger.output };
53
+ return { _warning: 'key not found', _debug: logger.output };
54
54
  }
55
55
 
56
56
  logger.debug(`Deleting memory value and scope data`);
@@ -10,6 +10,7 @@ const memory = {};
10
10
  export class MemoryReadKeyVal extends Component {
11
11
  protected configSchema = Joi.object({
12
12
  memoryName: Joi.string().max(255).allow('').label('Memory Name'),
13
+ key: Joi.string().max(255).allow('').label('Key'),
13
14
  });
14
15
  constructor() {
15
16
  super();
@@ -28,7 +29,7 @@ export class MemoryReadKeyVal extends Component {
28
29
 
29
30
  const memoryName = config.data.memoryName;
30
31
 
31
- const key = input.Key;
32
+ const key = TemplateString(config.data.key).parse(input).result;
32
33
 
33
34
  const sessionId = agent.sessionId;
34
35
  const workflowId = agent.agentRuntime.workflowReqId;
@@ -38,18 +39,18 @@ export class MemoryReadKeyVal extends Component {
38
39
  const scopeStrData = await connectorRequester.get(scopeKeyId);
39
40
 
40
41
  if (!scopeStrData) {
41
- return { _error: 'key not found', _debug: logger.output };
42
+ return { _warning: 'key not found', _debug: logger.output };
42
43
  }
43
44
 
44
45
  logger.debug(`Checking Scope`);
45
46
  const scopeData = JSON.parse(scopeStrData);
46
47
  const scopeKey = scopeData.value;
47
48
  if (scopeData.scope === 'session' && scopeKey !== sessionId) {
48
- return { _error: 'key not found', _debug: logger.output };
49
+ return { _warning: 'key not found', _debug: logger.output };
49
50
  }
50
51
 
51
52
  if (scopeData.scope === 'request' && scopeKey !== workflowId) {
52
- return { _error: 'key not found', _debug: logger.output };
53
+ return { _warning: 'key not found', _debug: logger.output };
53
54
  }
54
55
 
55
56
  logger.debug(`Reading Value`);
@@ -35,7 +35,7 @@ export class MemoryWriteObject extends Component {
35
35
  // Parse the JSON data
36
36
  let dataObject;
37
37
  try {
38
- dataObject = JSON.parse(dataString);
38
+ dataObject = typeof dataString === 'object' ? dataString : JSON.parse(dataString);
39
39
  } catch (parseError) {
40
40
  return { _error: 'Invalid JSON data provided', _debug: logger.output };
41
41
  }
@@ -2,7 +2,17 @@ import crypto from 'crypto';
2
2
  import { ConnectorService } from '@sre/Core/ConnectorsService';
3
3
  import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
4
4
  import zl from 'zip-lib';
5
- import { InvokeCommand, Runtime, LambdaClient, UpdateFunctionCodeCommand, CreateFunctionCommand, GetFunctionCommand, GetFunctionCommandOutput, InvokeCommandOutput, UpdateFunctionConfigurationCommand } from '@aws-sdk/client-lambda';
5
+ import {
6
+ InvokeCommand,
7
+ Runtime,
8
+ LambdaClient,
9
+ UpdateFunctionCodeCommand,
10
+ CreateFunctionCommand,
11
+ GetFunctionCommand,
12
+ GetFunctionCommandOutput,
13
+ InvokeCommandOutput,
14
+ UpdateFunctionConfigurationCommand,
15
+ } from '@aws-sdk/client-lambda';
6
16
  import { GetRoleCommand, CreateRoleCommand, IAMClient, GetRoleCommandOutput, CreateRoleCommandOutput } from '@aws-sdk/client-iam';
7
17
  import fs from 'fs';
8
18
  import { AWSConfig, AWSCredentials, AWSRegionConfig } from '@sre/types/AWS.types';
@@ -19,7 +29,6 @@ export function getLambdaFunctionName(agentId: string, componentId: string) {
19
29
  return `${agentId}-${componentId}`;
20
30
  }
21
31
 
22
-
23
32
  export function generateCodeHash(code_body: string, codeInputs: string[], envVariables: string[]) {
24
33
  const bodyHash = getSanitizeCodeHash(code_body);
25
34
  const inputsHash = getSanitizeCodeHash(JSON.stringify(codeInputs));
@@ -79,9 +88,7 @@ export async function getDeployedCodeHash(agentId: string, componentId: string)
79
88
 
80
89
  export async function setDeployedCodeHash(agentId: string, componentId: string, codeHash: string) {
81
90
  const redisCache = ConnectorService.getCacheConnector();
82
- await redisCache
83
- .user(AccessCandidate.agent(agentId))
84
- .set(`${cachePrefix}_${agentId}-${componentId}`, codeHash, null, null, cacheTTL);
91
+ await redisCache.user(AccessCandidate.agent(agentId)).set(`${cachePrefix}_${agentId}-${componentId}`, codeHash, null, null, cacheTTL);
85
92
  }
86
93
 
87
94
  function replaceVaultKeysTemplateVars(code: string, envVariables: Record<string, string>) {
@@ -121,7 +128,7 @@ export async function zipCode(directory: string) {
121
128
  },
122
129
  function (err) {
123
130
  reject(err);
124
- },
131
+ }
125
132
  );
126
133
  });
127
134
  }
@@ -276,7 +283,6 @@ export function getLambdaRolePolicy() {
276
283
  });
277
284
  }
278
285
 
279
-
280
286
  export async function updateDeployedCodeTTL(agentId: string, componentId: string, ttl: number) {
281
287
  const redisCache = ConnectorService.getCacheConnector();
282
288
  await redisCache.user(AccessCandidate.agent(agentId)).updateTTL(`${cachePrefix}_${agentId}-${componentId}`, ttl);
@@ -285,7 +291,7 @@ export async function updateDeployedCodeTTL(agentId: string, componentId: string
285
291
  export async function invokeLambdaFunction(
286
292
  functionName: string,
287
293
  inputs: { [key: string]: any },
288
- awsCredentials: AWSCredentials & AWSRegionConfig,
294
+ awsCredentials: AWSCredentials & AWSRegionConfig
289
295
  ): Promise<any> {
290
296
  try {
291
297
  const client = new LambdaClient({
@@ -384,11 +390,11 @@ export function reportUsage({ cost, agentId, teamId }: { cost: number; agentId:
384
390
 
385
391
  export function validateAsyncMainFunction(rawCode: string): { isValid: boolean; error?: string; parameters?: string[]; dependencies?: string[] } {
386
392
  try {
387
- const code = replaceVaultKeysTemplateVars(rawCode, {});
393
+ const code = replaceVaultKeysTemplateVars(rawCode.trim(), {});
388
394
  // Parse the code using acorn
389
395
  const ast = acorn.parse(code, {
390
396
  ecmaVersion: 'latest',
391
- sourceType: 'module'
397
+ sourceType: 'module',
392
398
  });
393
399
 
394
400
  // Extract library imports
@@ -414,11 +420,13 @@ export function validateAsyncMainFunction(rawCode: string): { isValid: boolean;
414
420
  }
415
421
 
416
422
  // Handle CallExpression (require() calls)
417
- if (node.type === 'CallExpression' &&
423
+ if (
424
+ node.type === 'CallExpression' &&
418
425
  node.callee.type === 'Identifier' &&
419
426
  node.callee.name === 'require' &&
420
427
  node.arguments.length > 0 &&
421
- node.arguments[0].type === 'Literal') {
428
+ node.arguments[0].type === 'Literal'
429
+ ) {
422
430
  const modulePath = node.arguments[0].value;
423
431
  if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
424
432
  libraries.add(extractPackageName(modulePath));
@@ -426,10 +434,12 @@ export function validateAsyncMainFunction(rawCode: string): { isValid: boolean;
426
434
  }
427
435
 
428
436
  // Handle dynamic import() calls
429
- if (node.type === 'CallExpression' &&
437
+ if (
438
+ node.type === 'CallExpression' &&
430
439
  node.callee.type === 'Import' &&
431
440
  node.arguments.length > 0 &&
432
- node.arguments[0].type === 'Literal') {
441
+ node.arguments[0].type === 'Literal'
442
+ ) {
433
443
  const modulePath = node.arguments[0].value;
434
444
  if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
435
445
  libraries.add(extractPackageName(modulePath));
@@ -503,7 +513,7 @@ export function validateAsyncMainFunction(rawCode: string): { isValid: boolean;
503
513
  return {
504
514
  isValid: false,
505
515
  error: 'No main function found at root level',
506
- dependencies
516
+ dependencies,
507
517
  };
508
518
  }
509
519
 
@@ -511,7 +521,7 @@ export function validateAsyncMainFunction(rawCode: string): { isValid: boolean;
511
521
  return {
512
522
  isValid: false,
513
523
  error: 'Main function exists but is not async',
514
- dependencies
524
+ dependencies,
515
525
  };
516
526
  }
517
527
 
@@ -519,7 +529,7 @@ export function validateAsyncMainFunction(rawCode: string): { isValid: boolean;
519
529
  } catch (error) {
520
530
  return {
521
531
  isValid: false,
522
- error: `Failed to parse code: ${error.message}`
532
+ error: `Failed to parse code: ${error.message}`,
523
533
  };
524
534
  }
525
535
  }
@@ -549,7 +559,7 @@ export function generateCodeFromLegacyComponent(code_body: string, code_imports:
549
559
  async function main(${codeInputs.join(', ')}) {
550
560
  ${code_body}
551
561
  }
552
- `
562
+ `;
553
563
  return code;
554
564
  }
555
565
 
@@ -565,14 +575,12 @@ export function extractAllKeyNamesFromTemplateVars(input: string): string[] {
565
575
  return matches;
566
576
  }
567
577
 
568
-
569
- async function fetchVaultSecret(keyName: string, agentTeamId: string): Promise<{ value: string, key: string }> {
578
+ async function fetchVaultSecret(keyName: string, agentTeamId: string): Promise<{ value: string; key: string }> {
570
579
  const vaultSecret = await VaultHelper.getAgentKey(keyName, agentTeamId);
571
580
  return {
572
581
  value: vaultSecret,
573
582
  key: keyName,
574
583
  };
575
-
576
584
  }
577
585
 
578
586
  export async function getCurrentEnvironmentVariables(agentTeamId: string, code: string): Promise<Record<string, string>> {
@@ -588,4 +596,4 @@ export async function getCurrentEnvironmentVariables(agentTeamId: string, code:
588
596
  export function getSortedObjectValues(obj: Record<string, string>): string[] {
589
597
  const sortedKeys = Object.keys(obj).sort();
590
598
  return sortedKeys.map((key) => obj[key]);
591
- }
599
+ }
@@ -132,9 +132,9 @@ export class Conversation extends EventEmitter {
132
132
  console.warn('Conversation Error: ', error?.message);
133
133
  });
134
134
  this._maxContextSize =
135
- _settings.maxContextSize || (this._model as TLLMModel).tokens || (this._model as TLLMModel).keyOptions?.tokens || this._maxContextSize;
135
+ _settings?.maxContextSize || (this._model as TLLMModel).tokens || (this._model as TLLMModel).keyOptions?.tokens || this._maxContextSize;
136
136
  this._maxOutputTokens =
137
- _settings.maxOutputTokens ||
137
+ _settings?.maxOutputTokens ||
138
138
  (this._model as TLLMModel).completionTokens ||
139
139
  (this._model as TLLMModel).keyOptions?.completionTokens ||
140
140
  this._maxOutputTokens;
@@ -281,8 +281,6 @@ export class Conversation extends EventEmitter {
281
281
  let _content = '';
282
282
  const reqMethods = this._reqMethods;
283
283
  const toolsConfig = this._toolsConfig;
284
- //deduplicate tools
285
- toolsConfig.tools = toolsConfig.tools.filter((tool, index, self) => self.findIndex((t) => t.function.name === tool.function.name) === index);
286
284
  const endpoints = this._endpoints;
287
285
  const baseUrl = this._baseUrl;
288
286
  const message_id = 'msg_' + randomUUID();
@@ -832,15 +830,22 @@ export class Conversation extends EventEmitter {
832
830
  this._customToolsDeclarations.push(toolDefinition);
833
831
  this._customToolsHandlers[tool.name] = tool.handler;
834
832
 
833
+ //deduplicate tools
834
+
835
835
  const llmInference: LLMInference = await LLMInference.getInstance(this.model, AccessCandidate.team(this._teamId));
836
+ this._customToolsDeclarations = this._customToolsDeclarations.filter(
837
+ (tool, index, self) => self.findIndex((t) => t.name === tool.name) === index
838
+ );
836
839
  const toolsConfig: any = llmInference.connector.formatToolsConfig({
837
840
  type: 'function',
838
- toolDefinitions: [toolDefinition],
841
+ toolDefinitions: this._customToolsDeclarations,
839
842
  toolChoice: this.toolChoice,
840
843
  });
841
844
 
842
- if (this._toolsConfig) this._toolsConfig.tools.push(...toolsConfig?.tools);
843
- else this._toolsConfig = toolsConfig;
845
+ //if (this._toolsConfig) this._toolsConfig.tools.push(...toolsConfig?.tools);
846
+ //else this._toolsConfig = toolsConfig;
847
+
848
+ this._toolsConfig = toolsConfig;
844
849
  }
845
850
  /**
846
851
  * updates LLM model, if spec is available, it will update the tools config
@@ -857,15 +862,19 @@ export class Conversation extends EventEmitter {
857
862
  this._baseUrl = this._spec?.servers?.[0].url;
858
863
 
859
864
  const functionDeclarations = this.getFunctionDeclarations(this._spec);
860
- functionDeclarations.push(...this._customToolsDeclarations);
865
+ //functionDeclarations.push(...this._customToolsDeclarations);
866
+ this._customToolsDeclarations.push(...functionDeclarations);
861
867
  const llmInference: LLMInference = await LLMInference.getInstance(this._model, AccessCandidate.team(this._teamId));
862
868
  if (!llmInference.connector) {
863
869
  this.emit('error', 'No connector found for model: ' + this._model);
864
870
  return;
865
871
  }
872
+ this._customToolsDeclarations = this._customToolsDeclarations.filter(
873
+ (tool, index, self) => self.findIndex((t) => t.name === tool.name) === index
874
+ );
866
875
  this._toolsConfig = llmInference.connector.formatToolsConfig({
867
876
  type: 'function',
868
- toolDefinitions: functionDeclarations,
877
+ toolDefinitions: this._customToolsDeclarations,
869
878
  toolChoice: this.toolChoice,
870
879
  });
871
880
 
@@ -919,6 +928,7 @@ export class Conversation extends EventEmitter {
919
928
  //is this a valid agent data?
920
929
  if (typeof specSource?.behavior === 'string' && specSource?.components && specSource?.connections) {
921
930
  this.agentData = specSource; //agent loaded from data directly
931
+ this._agentId = specSource.id;
922
932
  return await this.loadSpecFromAgent(specSource);
923
933
  }
924
934