@smythos/sre 1.5.43 → 1.5.45

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 (233) hide show
  1. package/CHANGELOG +90 -90
  2. package/LICENSE +18 -18
  3. package/README.md +135 -135
  4. package/dist/index.js +13 -13
  5. package/dist/index.js.map +1 -1
  6. package/dist/types/Components/GenAILLM.class.d.ts +6 -0
  7. package/dist/types/helpers/AWSLambdaCode.helper.d.ts +8 -5
  8. package/dist/types/index.d.ts +1 -0
  9. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Groq.class.d.ts +5 -0
  10. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.d.ts +13 -1
  11. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.d.ts +0 -4
  12. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.d.ts +44 -29
  13. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.d.ts +4 -2
  14. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.d.ts +6 -0
  15. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/types.d.ts +0 -4
  16. package/dist/types/subsystems/LLMManager/ModelsProvider.service/connectors/SmythModelsProvider.class.d.ts +39 -0
  17. package/dist/types/types/LLM.types.d.ts +4 -1
  18. package/package.json +5 -2
  19. package/src/Components/APICall/APICall.class.ts +156 -156
  20. package/src/Components/APICall/AccessTokenManager.ts +130 -130
  21. package/src/Components/APICall/ArrayBufferResponse.helper.ts +58 -58
  22. package/src/Components/APICall/OAuth.helper.ts +294 -294
  23. package/src/Components/APICall/mimeTypeCategories.ts +46 -46
  24. package/src/Components/APICall/parseData.ts +167 -167
  25. package/src/Components/APICall/parseHeaders.ts +41 -41
  26. package/src/Components/APICall/parseProxy.ts +68 -68
  27. package/src/Components/APICall/parseUrl.ts +91 -91
  28. package/src/Components/APIEndpoint.class.ts +234 -234
  29. package/src/Components/APIOutput.class.ts +58 -58
  30. package/src/Components/AgentPlugin.class.ts +102 -102
  31. package/src/Components/Async.class.ts +155 -155
  32. package/src/Components/Await.class.ts +90 -90
  33. package/src/Components/Classifier.class.ts +158 -158
  34. package/src/Components/Component.class.ts +132 -132
  35. package/src/Components/ComponentHost.class.ts +38 -38
  36. package/src/Components/DataSourceCleaner.class.ts +92 -92
  37. package/src/Components/DataSourceIndexer.class.ts +181 -181
  38. package/src/Components/DataSourceLookup.class.ts +161 -161
  39. package/src/Components/ECMASandbox.class.ts +71 -71
  40. package/src/Components/FEncDec.class.ts +29 -29
  41. package/src/Components/FHash.class.ts +33 -33
  42. package/src/Components/FSign.class.ts +80 -80
  43. package/src/Components/FSleep.class.ts +25 -25
  44. package/src/Components/FTimestamp.class.ts +25 -25
  45. package/src/Components/FileStore.class.ts +78 -78
  46. package/src/Components/ForEach.class.ts +97 -97
  47. package/src/Components/GPTPlugin.class.ts +70 -70
  48. package/src/Components/GenAILLM.class.ts +586 -579
  49. package/src/Components/HuggingFace.class.ts +314 -314
  50. package/src/Components/Image/imageSettings.config.ts +70 -70
  51. package/src/Components/ImageGenerator.class.ts +502 -502
  52. package/src/Components/JSONFilter.class.ts +54 -54
  53. package/src/Components/LLMAssistant.class.ts +213 -213
  54. package/src/Components/LogicAND.class.ts +28 -28
  55. package/src/Components/LogicAtLeast.class.ts +85 -85
  56. package/src/Components/LogicAtMost.class.ts +86 -86
  57. package/src/Components/LogicOR.class.ts +29 -29
  58. package/src/Components/LogicXOR.class.ts +34 -34
  59. package/src/Components/MCPClient.class.ts +112 -112
  60. package/src/Components/MemoryDeleteKeyVal.class.ts +70 -70
  61. package/src/Components/MemoryReadKeyVal.class.ts +66 -66
  62. package/src/Components/MemoryWriteKeyVal.class.ts +62 -62
  63. package/src/Components/MemoryWriteObject.class.ts +97 -97
  64. package/src/Components/MultimodalLLM.class.ts +128 -128
  65. package/src/Components/OpenAPI.class.ts +72 -72
  66. package/src/Components/PromptGenerator.class.ts +122 -122
  67. package/src/Components/ScrapflyWebScrape.class.ts +159 -159
  68. package/src/Components/ServerlessCode.class.ts +123 -123
  69. package/src/Components/TavilyWebSearch.class.ts +98 -98
  70. package/src/Components/VisionLLM.class.ts +104 -104
  71. package/src/Components/ZapierAction.class.ts +127 -127
  72. package/src/Components/index.ts +97 -97
  73. package/src/Core/AgentProcess.helper.ts +240 -240
  74. package/src/Core/Connector.class.ts +123 -123
  75. package/src/Core/ConnectorsService.ts +197 -197
  76. package/src/Core/DummyConnector.ts +49 -49
  77. package/src/Core/HookService.ts +105 -105
  78. package/src/Core/SmythRuntime.class.ts +235 -235
  79. package/src/Core/SystemEvents.ts +16 -16
  80. package/src/Core/boot.ts +56 -56
  81. package/src/config.ts +15 -15
  82. package/src/constants.ts +126 -126
  83. package/src/data/hugging-face.params.json +579 -579
  84. package/src/helpers/AWSLambdaCode.helper.ts +588 -528
  85. package/src/helpers/BinaryInput.helper.ts +331 -331
  86. package/src/helpers/Conversation.helper.ts +1119 -1119
  87. package/src/helpers/ECMASandbox.helper.ts +54 -54
  88. package/src/helpers/JsonContent.helper.ts +97 -97
  89. package/src/helpers/LocalCache.helper.ts +97 -97
  90. package/src/helpers/Log.helper.ts +274 -274
  91. package/src/helpers/OpenApiParser.helper.ts +150 -150
  92. package/src/helpers/S3Cache.helper.ts +147 -147
  93. package/src/helpers/SmythURI.helper.ts +5 -5
  94. package/src/helpers/Sysconfig.helper.ts +77 -77
  95. package/src/helpers/TemplateString.helper.ts +243 -243
  96. package/src/helpers/TypeChecker.helper.ts +329 -329
  97. package/src/index.ts +4 -3
  98. package/src/index.ts.bak +4 -3
  99. package/src/subsystems/AgentManager/Agent.class.ts +1114 -1114
  100. package/src/subsystems/AgentManager/Agent.helper.ts +3 -3
  101. package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +230 -230
  102. package/src/subsystems/AgentManager/AgentData.service/connectors/CLIAgentDataConnector.class.ts +66 -66
  103. package/src/subsystems/AgentManager/AgentData.service/connectors/LocalAgentDataConnector.class.ts +142 -142
  104. package/src/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.ts +39 -39
  105. package/src/subsystems/AgentManager/AgentData.service/index.ts +18 -18
  106. package/src/subsystems/AgentManager/AgentLogger.class.ts +297 -297
  107. package/src/subsystems/AgentManager/AgentRequest.class.ts +51 -51
  108. package/src/subsystems/AgentManager/AgentRuntime.class.ts +559 -559
  109. package/src/subsystems/AgentManager/AgentSSE.class.ts +101 -101
  110. package/src/subsystems/AgentManager/AgentSettings.class.ts +52 -52
  111. package/src/subsystems/AgentManager/Component.service/ComponentConnector.ts +32 -32
  112. package/src/subsystems/AgentManager/Component.service/connectors/LocalComponentConnector.class.ts +60 -60
  113. package/src/subsystems/AgentManager/Component.service/index.ts +11 -11
  114. package/src/subsystems/AgentManager/EmbodimentSettings.class.ts +47 -47
  115. package/src/subsystems/AgentManager/ForkedAgent.class.ts +154 -154
  116. package/src/subsystems/AgentManager/OSResourceMonitor.ts +77 -77
  117. package/src/subsystems/ComputeManager/Code.service/CodeConnector.ts +98 -98
  118. package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +172 -170
  119. package/src/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.ts +131 -131
  120. package/src/subsystems/ComputeManager/Code.service/index.ts +13 -13
  121. package/src/subsystems/IO/CLI.service/CLIConnector.ts +47 -47
  122. package/src/subsystems/IO/CLI.service/index.ts +9 -9
  123. package/src/subsystems/IO/Log.service/LogConnector.ts +32 -32
  124. package/src/subsystems/IO/Log.service/connectors/ConsoleLog.class.ts +28 -28
  125. package/src/subsystems/IO/Log.service/index.ts +13 -13
  126. package/src/subsystems/IO/NKV.service/NKVConnector.ts +43 -43
  127. package/src/subsystems/IO/NKV.service/connectors/NKVLocalStorage.class.ts +234 -234
  128. package/src/subsystems/IO/NKV.service/connectors/NKVRAM.class.ts +204 -204
  129. package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +182 -182
  130. package/src/subsystems/IO/NKV.service/index.ts +14 -14
  131. package/src/subsystems/IO/Router.service/RouterConnector.ts +21 -21
  132. package/src/subsystems/IO/Router.service/connectors/ExpressRouter.class.ts +48 -48
  133. package/src/subsystems/IO/Router.service/connectors/NullRouter.class.ts +40 -40
  134. package/src/subsystems/IO/Router.service/index.ts +11 -11
  135. package/src/subsystems/IO/Storage.service/SmythFS.class.ts +489 -489
  136. package/src/subsystems/IO/Storage.service/StorageConnector.ts +66 -66
  137. package/src/subsystems/IO/Storage.service/connectors/LocalStorage.class.ts +327 -327
  138. package/src/subsystems/IO/Storage.service/connectors/S3Storage.class.ts +482 -482
  139. package/src/subsystems/IO/Storage.service/index.ts +13 -13
  140. package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +108 -108
  141. package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +454 -454
  142. package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +384 -384
  143. package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +421 -421
  144. package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +107 -107
  145. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +109 -109
  146. package/src/subsystems/IO/VectorDB.service/embed/index.ts +21 -21
  147. package/src/subsystems/IO/VectorDB.service/index.ts +14 -14
  148. package/src/subsystems/LLMManager/LLM.helper.ts +251 -251
  149. package/src/subsystems/LLMManager/LLM.inference.ts +339 -339
  150. package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +489 -489
  151. package/src/subsystems/LLMManager/LLM.service/LLMCredentials.helper.ts +171 -171
  152. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +659 -659
  153. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +400 -400
  154. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +77 -77
  155. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +757 -757
  156. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +304 -291
  157. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +250 -250
  158. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +423 -423
  159. package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +488 -455
  160. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +528 -528
  161. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.ts +100 -100
  162. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.ts +81 -81
  163. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +1168 -853
  164. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.ts +13 -37
  165. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.ts +4 -4
  166. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.ts +11 -0
  167. package/src/subsystems/LLMManager/LLM.service/connectors/openai/types.ts +32 -37
  168. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +471 -471
  169. package/src/subsystems/LLMManager/LLM.service/index.ts +44 -44
  170. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +300 -300
  171. package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +252 -252
  172. package/src/subsystems/LLMManager/ModelsProvider.service/index.ts +11 -11
  173. package/src/subsystems/LLMManager/custom-models.ts +854 -854
  174. package/src/subsystems/LLMManager/models.ts +2540 -2540
  175. package/src/subsystems/LLMManager/paramMappings.ts +69 -69
  176. package/src/subsystems/MemoryManager/Cache.service/CacheConnector.ts +86 -86
  177. package/src/subsystems/MemoryManager/Cache.service/connectors/LocalStorageCache.class.ts +297 -297
  178. package/src/subsystems/MemoryManager/Cache.service/connectors/RAMCache.class.ts +201 -201
  179. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +252 -252
  180. package/src/subsystems/MemoryManager/Cache.service/connectors/S3Cache.class.ts +373 -373
  181. package/src/subsystems/MemoryManager/Cache.service/index.ts +15 -15
  182. package/src/subsystems/MemoryManager/LLMCache.ts +72 -72
  183. package/src/subsystems/MemoryManager/LLMContext.ts +124 -124
  184. package/src/subsystems/MemoryManager/LLMMemory.service/LLMMemoryConnector.ts +26 -26
  185. package/src/subsystems/MemoryManager/RuntimeContext.ts +266 -266
  186. package/src/subsystems/Security/AccessControl/ACL.class.ts +208 -208
  187. package/src/subsystems/Security/AccessControl/AccessCandidate.class.ts +82 -82
  188. package/src/subsystems/Security/AccessControl/AccessRequest.class.ts +52 -52
  189. package/src/subsystems/Security/Account.service/AccountConnector.ts +44 -44
  190. package/src/subsystems/Security/Account.service/connectors/AWSAccount.class.ts +76 -76
  191. package/src/subsystems/Security/Account.service/connectors/DummyAccount.class.ts +130 -130
  192. package/src/subsystems/Security/Account.service/connectors/JSONFileAccount.class.ts +159 -159
  193. package/src/subsystems/Security/Account.service/index.ts +14 -14
  194. package/src/subsystems/Security/Credentials.helper.ts +62 -62
  195. package/src/subsystems/Security/ManagedVault.service/ManagedVaultConnector.ts +38 -38
  196. package/src/subsystems/Security/ManagedVault.service/connectors/NullManagedVault.class.ts +53 -53
  197. package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +154 -154
  198. package/src/subsystems/Security/ManagedVault.service/index.ts +12 -12
  199. package/src/subsystems/Security/SecureConnector.class.ts +110 -110
  200. package/src/subsystems/Security/Vault.service/Vault.helper.ts +30 -30
  201. package/src/subsystems/Security/Vault.service/VaultConnector.ts +29 -29
  202. package/src/subsystems/Security/Vault.service/connectors/HashicorpVault.class.ts +46 -46
  203. package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +221 -221
  204. package/src/subsystems/Security/Vault.service/connectors/NullVault.class.ts +54 -54
  205. package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +140 -140
  206. package/src/subsystems/Security/Vault.service/index.ts +12 -12
  207. package/src/types/ACL.types.ts +104 -104
  208. package/src/types/AWS.types.ts +10 -10
  209. package/src/types/Agent.types.ts +61 -61
  210. package/src/types/AgentLogger.types.ts +17 -17
  211. package/src/types/Cache.types.ts +1 -1
  212. package/src/types/Common.types.ts +2 -2
  213. package/src/types/LLM.types.ts +496 -491
  214. package/src/types/Redis.types.ts +8 -8
  215. package/src/types/SRE.types.ts +64 -64
  216. package/src/types/Security.types.ts +14 -14
  217. package/src/types/Storage.types.ts +5 -5
  218. package/src/types/VectorDB.types.ts +86 -86
  219. package/src/utils/base64.utils.ts +275 -275
  220. package/src/utils/cli.utils.ts +68 -68
  221. package/src/utils/data.utils.ts +322 -322
  222. package/src/utils/date-time.utils.ts +22 -22
  223. package/src/utils/general.utils.ts +238 -238
  224. package/src/utils/index.ts +12 -12
  225. package/src/utils/lazy-client.ts +261 -261
  226. package/src/utils/numbers.utils.ts +13 -13
  227. package/src/utils/oauth.utils.ts +35 -35
  228. package/src/utils/string.utils.ts +414 -414
  229. package/src/utils/url.utils.ts +19 -19
  230. package/src/utils/validation.utils.ts +74 -74
  231. package/dist/bundle-analysis-lazy.html +0 -4949
  232. package/dist/bundle-analysis.html +0 -4949
  233. package/dist/types/utils/package-manager.utils.d.ts +0 -26
@@ -1,528 +1,588 @@
1
- import crypto from 'crypto';
2
- import { ConnectorService } from '@sre/Core/ConnectorsService';
3
- import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
4
- import zl from 'zip-lib';
5
- import { InvokeCommand, Runtime, LambdaClient, UpdateFunctionCodeCommand, CreateFunctionCommand, GetFunctionCommand, GetFunctionCommandOutput, InvokeCommandOutput } from '@aws-sdk/client-lambda';
6
- import { GetRoleCommand, CreateRoleCommand, IAMClient, GetRoleCommandOutput, CreateRoleCommandOutput } from '@aws-sdk/client-iam';
7
- import fs from 'fs';
8
- import { AWSConfig, AWSCredentials, AWSRegionConfig } from '@sre/types/AWS.types';
9
- import { VaultHelper } from '@sre/Security/Vault.service/Vault.helper';
10
- import { IAgent } from '@sre/types/Agent.types';
11
- import { SystemEvents } from '@sre/Core/SystemEvents';
12
- import * as acorn from 'acorn';
13
-
14
- export const cachePrefix = 'serverless_code';
15
- export const cacheTTL = 60 * 60 * 24 * 16; // 16 days
16
- const PER_SECOND_COST = 0.0001;
17
-
18
- export function getLambdaFunctionName(agentId: string, componentId: string) {
19
- return `${agentId}-${componentId}`;
20
- }
21
-
22
-
23
- export function generateCodeHash(code_body: string, codeInputs: string[]) {
24
- const bodyHash = getSanitizeCodeHash(code_body);
25
- const inputsHash = getSanitizeCodeHash(JSON.stringify(codeInputs));
26
- return `body-${bodyHash}__inputs-${inputsHash}`;
27
- }
28
-
29
- export function getSanitizeCodeHash(code: string) {
30
- let output = '';
31
- let isSingleQuote = false;
32
- let isDoubleQuote = false;
33
- let isTemplateLiteral = false;
34
- let isRegex = false;
35
- let isComment = false;
36
- let prevChar = '';
37
-
38
- for (let i = 0; i < code.length; i++) {
39
- let char = code[i];
40
- let nextChar = code[i + 1];
41
-
42
- // Toggle string flags
43
- if (char === "'" && !isDoubleQuote && !isTemplateLiteral && prevChar !== '\\') isSingleQuote = !isSingleQuote;
44
- if (char === '"' && !isSingleQuote && !isTemplateLiteral && prevChar !== '\\') isDoubleQuote = !isDoubleQuote;
45
- if (char === '`' && !isSingleQuote && !isDoubleQuote && prevChar !== '\\') isTemplateLiteral = !isTemplateLiteral;
46
-
47
- // Handle regex cases
48
- if (char === '/' && nextChar === '/' && !isSingleQuote && !isDoubleQuote && !isTemplateLiteral && !isRegex) {
49
- isComment = true; // Single-line comment
50
- }
51
- if (char === '/' && nextChar === '*' && !isSingleQuote && !isDoubleQuote && !isTemplateLiteral) {
52
- isComment = true; // Multi-line comment start
53
- }
54
- if (char === '*' && nextChar === '/' && isComment) {
55
- isComment = false; // Multi-line comment end
56
- i++; // Skip ending slash
57
- continue;
58
- }
59
- if (char === '\n' && isComment) {
60
- isComment = false; // End single-line comment
61
- }
62
-
63
- if (!isComment) {
64
- output += char;
65
- }
66
- prevChar = char;
67
- }
68
-
69
- return crypto.createHash('md5').update(output.replace(/\s+/g, ' ').trim()).digest('hex');
70
- }
71
-
72
- export async function getDeployedCodeHash(agentId: string, componentId: string) {
73
- const redisCache = ConnectorService.getCacheConnector();
74
- const cachedCodeHash = await redisCache.user(AccessCandidate.agent(agentId)).get(`${cachePrefix}_${agentId}-${componentId}`);
75
- return cachedCodeHash;
76
- }
77
-
78
- export async function setDeployedCodeHash(agentId: string, componentId: string, codeHash: string) {
79
- const redisCache = ConnectorService.getCacheConnector();
80
- await redisCache
81
- .user(AccessCandidate.agent(agentId))
82
- .set(`${cachePrefix}_${agentId}-${componentId}`, codeHash, null, null, cacheTTL);
83
- }
84
-
85
- export function generateLambdaCode(code: string, parameters: string[]) {
86
- const lambdaCode = `
87
- ${code}
88
- export const handler = async (event, context) => {
89
- try {
90
- context.callbackWaitsForEmptyEventLoop = false;
91
- let startTime = Date.now();
92
-
93
- ${parameters && parameters.length ? parameters.map((variable) => `const ${variable} = event.${variable};`).join('\n') : ''}
94
- const result = await main(${parameters.join(', ')});
95
-
96
- let endTime = Date.now();
97
- return {
98
- result,
99
- executionTime: endTime - startTime
100
- }
101
- } catch (e) {
102
- throw e;
103
- }
104
- };`;
105
- return lambdaCode;
106
- }
107
-
108
- export async function zipCode(directory: string) {
109
- return new Promise((resolve, reject) => {
110
- zl.archiveFolder(directory, `${directory}.zip`).then(
111
- function () {
112
- resolve(`${directory}.zip`);
113
- },
114
- function (err) {
115
- reject(err);
116
- },
117
- );
118
- });
119
- }
120
-
121
- export async function createOrUpdateLambdaFunction(functionName, zipFilePath, awsConfigs) {
122
- const client = new LambdaClient({
123
- region: awsConfigs.region,
124
- credentials: {
125
- accessKeyId: awsConfigs.accessKeyId,
126
- secretAccessKey: awsConfigs.secretAccessKey,
127
- },
128
- });
129
- const functionContent = fs.readFileSync(zipFilePath);
130
-
131
- try {
132
- // Check if the function exists
133
- const exisitingFunction = await getDeployedFunction(functionName, awsConfigs);
134
- if (exisitingFunction) {
135
- if (exisitingFunction.status === 'InProgress') {
136
- await verifyFunctionDeploymentStatus(functionName, client);
137
- }
138
- // Update function code if it exists
139
- const updateCodeParams = {
140
- FunctionName: functionName,
141
- ZipFile: functionContent,
142
- };
143
- const updateFunctionCodeCommand = new UpdateFunctionCodeCommand(updateCodeParams);
144
- await client.send(updateFunctionCodeCommand);
145
- // Update function configuration to attach layer
146
- await verifyFunctionDeploymentStatus(functionName, client);
147
- // console.log('Lambda function code and configuration updated successfully!');
148
- } else {
149
- // Create function if it does not exist
150
- let roleArn = '';
151
- // check if the role exists
152
- try {
153
- const iamClient = new IAMClient({
154
- region: awsConfigs.region,
155
- credentials: { accessKeyId: awsConfigs.accessKeyId, secretAccessKey: awsConfigs.secretAccessKey },
156
- });
157
- const getRoleCommand = new GetRoleCommand({ RoleName: `smyth-${functionName}-role` });
158
- const roleResponse: GetRoleCommandOutput = await iamClient.send(getRoleCommand);
159
- roleArn = roleResponse.Role.Arn;
160
- } catch (error) {
161
- if (error.name === 'NoSuchEntityException') {
162
- // create role
163
- const iamClient = new IAMClient({
164
- region: awsConfigs.region,
165
- credentials: { accessKeyId: awsConfigs.accessKeyId, secretAccessKey: awsConfigs.secretAccessKey },
166
- });
167
- const createRoleCommand = new CreateRoleCommand({
168
- RoleName: `smyth-${functionName}-role`,
169
- AssumeRolePolicyDocument: getLambdaRolePolicy(),
170
- });
171
- const roleResponse: CreateRoleCommandOutput = await iamClient.send(createRoleCommand);
172
- await waitForRoleDeploymentStatus(`smyth-${functionName}-role`, iamClient);
173
- roleArn = roleResponse.Role.Arn;
174
- } else {
175
- throw error;
176
- }
177
- }
178
-
179
- const functionParams = {
180
- Code: { ZipFile: functionContent },
181
- FunctionName: functionName,
182
- Handler: 'index.handler',
183
- Role: roleArn,
184
- Runtime: Runtime.nodejs18x,
185
- Layers: [],
186
- Timeout: 900,
187
- Tags: {
188
- 'auto-delete': 'true',
189
- },
190
- MemorySize: 256,
191
- };
192
-
193
- const functionCreateCommand = new CreateFunctionCommand(functionParams);
194
- const functionResponse = await client.send(functionCreateCommand);
195
- // console.log('Function ARN:', functionResponse.FunctionArn);
196
- await verifyFunctionDeploymentStatus(functionName, client);
197
- }
198
- } catch (error) {
199
- throw error;
200
- }
201
- }
202
-
203
- export async function waitForRoleDeploymentStatus(roleName, client): Promise<boolean> {
204
- return new Promise((resolve, reject) => {
205
- try {
206
- let interval = setInterval(async () => {
207
- const getRoleCommand = new GetRoleCommand({ RoleName: roleName });
208
- const roleResponse = await client.send(getRoleCommand);
209
- if (roleResponse.Role.AssumeRolePolicyDocument) {
210
- clearInterval(interval);
211
- return resolve(true);
212
- }
213
- }, 7000);
214
- } catch (error) {
215
- return false;
216
- }
217
- });
218
- }
219
-
220
- export async function verifyFunctionDeploymentStatus(functionName, client): Promise<boolean> {
221
- return new Promise((resolve, reject) => {
222
- try {
223
- let interval = setInterval(async () => {
224
- const getFunctionCommand = new GetFunctionCommand({ FunctionName: functionName });
225
- const lambdaResponse = await client.send(getFunctionCommand);
226
-
227
- if (lambdaResponse.Configuration.LastUpdateStatus === 'Successful') {
228
- clearInterval(interval);
229
- return resolve(true);
230
- }
231
- }, 5000);
232
- } catch (error) {
233
- return false;
234
- }
235
- });
236
- }
237
-
238
- export function getLambdaRolePolicy() {
239
- return JSON.stringify({
240
- Version: '2012-10-17',
241
- Statement: [
242
- {
243
- Effect: 'Allow',
244
- Principal: {
245
- Service: 'lambda.amazonaws.com',
246
- },
247
- Action: 'sts:AssumeRole',
248
- },
249
- ],
250
- });
251
- }
252
-
253
-
254
- export async function updateDeployedCodeTTL(agentId: string, componentId: string, ttl: number) {
255
- const redisCache = ConnectorService.getCacheConnector();
256
- await redisCache.user(AccessCandidate.agent(agentId)).updateTTL(`${cachePrefix}_${agentId}-${componentId}`, ttl);
257
- }
258
-
259
- export async function invokeLambdaFunction(
260
- functionName: string,
261
- inputs: { [key: string]: any },
262
- awsCredentials: AWSCredentials & AWSRegionConfig,
263
- ): Promise<any> {
264
- try {
265
- const client = new LambdaClient({
266
- region: awsCredentials.region as string,
267
- ...(awsCredentials.accessKeyId && {
268
- credentials: {
269
- accessKeyId: awsCredentials.accessKeyId as string,
270
- secretAccessKey: awsCredentials.secretAccessKey as string,
271
- },
272
- }),
273
- });
274
-
275
- const invokeCommand = new InvokeCommand({
276
- FunctionName: functionName,
277
- Payload: new TextEncoder().encode(`${JSON.stringify(inputs)}`),
278
- InvocationType: 'RequestResponse',
279
- });
280
-
281
- const response: InvokeCommandOutput = await client.send(invokeCommand);
282
- if (response.FunctionError) {
283
- throw new Error(new TextDecoder().decode(response.Payload));
284
- }
285
- return new TextDecoder().decode(response.Payload);
286
- } catch (error) {
287
- throw error;
288
- }
289
- }
290
-
291
- export async function getDeployedFunction(functionName: string, awsConfigs: AWSCredentials & AWSRegionConfig) {
292
- try {
293
- const client = new LambdaClient({
294
- region: awsConfigs.region as string,
295
- credentials: {
296
- accessKeyId: awsConfigs.accessKeyId as string,
297
- secretAccessKey: awsConfigs.secretAccessKey as string,
298
- },
299
- });
300
- const getFunctionCommand = new GetFunctionCommand({ FunctionName: functionName });
301
- const lambdaResponse: GetFunctionCommandOutput = await client.send(getFunctionCommand);
302
- return {
303
- status: lambdaResponse.Configuration.LastUpdateStatus,
304
- functionName: lambdaResponse.Configuration.FunctionName,
305
- functionVersion: lambdaResponse.Configuration.Version,
306
- updatedAt: lambdaResponse.Configuration.LastModified,
307
- role: lambdaResponse.Configuration.Role,
308
- runtime: lambdaResponse.Configuration.Runtime,
309
- version: lambdaResponse.Configuration.Version,
310
- };
311
- } catch (error) {
312
- return null;
313
- }
314
- }
315
-
316
- export async function getLambdaCredentials(agent: IAgent, config: any): Promise<AWSConfig & { isUserProvidedKeys: boolean }> {
317
- let awsAccessKeyId = null;
318
- let awsSecretAccessKey = null;
319
- let awsRegion = null;
320
- let userProvidedKeys = false;
321
- if (config.data.accessKeyId && config.data.secretAccessKey && config.data.region && config.data.use_own_keys) {
322
- userProvidedKeys = true;
323
- [awsAccessKeyId, awsSecretAccessKey] = await Promise.all([
324
- VaultHelper.getTeamKey(extractKeyFromTemplateVar(config.data.accessKeyId), agent?.teamId),
325
- VaultHelper.getTeamKey(extractKeyFromTemplateVar(config.data.secretAccessKey), agent?.teamId),
326
- ]);
327
- awsRegion = config.data.region;
328
- }
329
- const awsCredentials = {
330
- accessKeyId: awsAccessKeyId,
331
- secretAccessKey: awsSecretAccessKey,
332
- region: awsRegion,
333
- isUserProvidedKeys: userProvidedKeys,
334
- };
335
- return awsCredentials;
336
- }
337
-
338
- export function calculateExecutionCost(executionTime: number) {
339
- // executionTime in milliseconds
340
- const cost = (executionTime / 1000) * Number(PER_SECOND_COST);
341
- return cost;
342
- }
343
-
344
- export function extractKeyFromTemplateVar(input: string) {
345
- const regex = /\{\{KEY\((.*?)\)\}\}/;
346
- const match = input.match(regex);
347
- return match ? match[1] : input;
348
- }
349
-
350
- export function reportUsage({ cost, agentId, teamId }: { cost: number; agentId: string; teamId: string }) {
351
- SystemEvents.emit('USAGE:API', {
352
- sourceId: 'api:serverless_code.smyth',
353
- cost,
354
- agentId,
355
- teamId,
356
- });
357
- }
358
-
359
- export function validateAsyncMainFunction(code: string): { isValid: boolean; error?: string; parameters?: string[]; dependencies?: string[] } {
360
- try {
361
- // Parse the code using acorn
362
- const ast = acorn.parse(code, {
363
- ecmaVersion: 'latest',
364
- sourceType: 'module'
365
- });
366
-
367
- // Extract library imports
368
- const libraries = new Set<string>();
369
- function extractPackageName(modulePath: string): string {
370
- if (modulePath.startsWith('@')) {
371
- // Handle scoped packages (e.g., @babel/core)
372
- return modulePath.split('/').slice(0, 2).join('/');
373
- }
374
- return modulePath.split('/')[0]; // Extract the first part (main package)
375
- }
376
-
377
- function processNodeForImports(node: any): void {
378
- if (!node) return;
379
-
380
- // Handle ImportDeclaration (ES6 imports)
381
- if (node.type === 'ImportDeclaration') {
382
- const modulePath = node.source.value;
383
- if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
384
- // Skip relative imports and absolute paths
385
- libraries.add(extractPackageName(modulePath));
386
- }
387
- }
388
-
389
- // Handle CallExpression (require() calls)
390
- if (node.type === 'CallExpression' &&
391
- node.callee.type === 'Identifier' &&
392
- node.callee.name === 'require' &&
393
- node.arguments.length > 0 &&
394
- node.arguments[0].type === 'Literal') {
395
- const modulePath = node.arguments[0].value;
396
- if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
397
- libraries.add(extractPackageName(modulePath));
398
- }
399
- }
400
-
401
- // Handle dynamic import() calls
402
- if (node.type === 'CallExpression' &&
403
- node.callee.type === 'Import' &&
404
- node.arguments.length > 0 &&
405
- node.arguments[0].type === 'Literal') {
406
- const modulePath = node.arguments[0].value;
407
- if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
408
- libraries.add(extractPackageName(modulePath));
409
- }
410
- }
411
-
412
- // Recursively process child nodes
413
- for (const key in node) {
414
- if (node[key] && typeof node[key] === 'object') {
415
- if (Array.isArray(node[key])) {
416
- (node[key] as any[]).forEach(processNodeForImports);
417
- } else {
418
- processNodeForImports(node[key]);
419
- }
420
- }
421
- }
422
- }
423
-
424
- // Extract dependencies from the entire AST
425
- processNodeForImports(ast);
426
- const dependencies = Array.from(libraries) as string[];
427
-
428
- // Check if there's a function declaration or function expression named 'main' at the root level
429
- let hasAsyncMain = false;
430
- let hasMain = false;
431
- let mainParameters: string[] = [];
432
-
433
- for (const node of ast.body) {
434
- if (node.type === 'FunctionDeclaration') {
435
- if (node.id?.name === 'main') {
436
- hasMain = true;
437
- if (node.async) {
438
- hasAsyncMain = true;
439
- mainParameters = extractParameters(node.params);
440
- break;
441
- }
442
- }
443
- } else if (node.type === 'VariableDeclaration') {
444
- // Check for const/let/var main = async function() or const/let/var main = async () =>
445
- for (const declarator of node.declarations) {
446
- if (declarator.id.type === 'Identifier' && declarator.id.name === 'main') {
447
- hasMain = true;
448
- if (declarator.init) {
449
- if (declarator.init.type === 'FunctionExpression' && declarator.init.async) {
450
- hasAsyncMain = true;
451
- mainParameters = extractParameters(declarator.init.params);
452
- break;
453
- } else if (declarator.init.type === 'ArrowFunctionExpression' && declarator.init.async) {
454
- hasAsyncMain = true;
455
- mainParameters = extractParameters(declarator.init.params);
456
- break;
457
- }
458
- }
459
- }
460
- }
461
- } else if (node.type === 'ExpressionStatement' && node.expression.type === 'AssignmentExpression') {
462
- // Check for main = async function() or main = async () =>
463
- if (node.expression.left.type === 'Identifier' && node.expression.left.name === 'main') {
464
- hasMain = true;
465
- const right = node.expression.right;
466
- if ((right.type === 'FunctionExpression' || right.type === 'ArrowFunctionExpression') && right.async) {
467
- hasAsyncMain = true;
468
- mainParameters = extractParameters(right.params);
469
- break;
470
- }
471
- }
472
- }
473
- }
474
-
475
- if (!hasMain) {
476
- return {
477
- isValid: false,
478
- error: 'No main function found at root level',
479
- dependencies
480
- };
481
- }
482
-
483
- if (!hasAsyncMain) {
484
- return {
485
- isValid: false,
486
- error: 'Main function exists but is not async',
487
- dependencies
488
- };
489
- }
490
-
491
- return { isValid: true, parameters: mainParameters, dependencies };
492
- } catch (error) {
493
- return {
494
- isValid: false,
495
- error: `Failed to parse code: ${error.message}`
496
- };
497
- }
498
- }
499
-
500
- function extractParameters(params: any[]): string[] {
501
- return params.map((param: any): string => {
502
- if (param.type === 'Identifier') {
503
- return param.name;
504
- } else if (param.type === 'AssignmentPattern' && param.left.type === 'Identifier') {
505
- return param.left.name;
506
- } else if (param.type === 'RestElement' && param.argument.type === 'Identifier') {
507
- return param.argument.name;
508
- } else if (param.type === 'ObjectPattern') {
509
- // For destructured objects, return the object name or a placeholder
510
- return param.name || '[object]';
511
- } else if (param.type === 'ArrayPattern') {
512
- // For destructured arrays, return a placeholder
513
- return '[array]';
514
- }
515
- return '[unknown]';
516
- });
517
- }
518
-
519
- export function generateCodeFromLegacyComponent(code_body: string, code_imports: string, codeInputs: string[]) {
520
- const code = `
521
- ${code_imports}
522
- async function main(${codeInputs.join(', ')}) {
523
- ${code_body}
524
- }
525
- `
526
- return code;
527
- }
528
-
1
+ import crypto from 'crypto';
2
+ import { ConnectorService } from '@sre/Core/ConnectorsService';
3
+ import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
4
+ import zl from 'zip-lib';
5
+ import { InvokeCommand, Runtime, LambdaClient, UpdateFunctionCodeCommand, CreateFunctionCommand, GetFunctionCommand, GetFunctionCommandOutput, InvokeCommandOutput, UpdateFunctionConfigurationCommand } from '@aws-sdk/client-lambda';
6
+ import { GetRoleCommand, CreateRoleCommand, IAMClient, GetRoleCommandOutput, CreateRoleCommandOutput } from '@aws-sdk/client-iam';
7
+ import fs from 'fs';
8
+ import { AWSConfig, AWSCredentials, AWSRegionConfig } from '@sre/types/AWS.types';
9
+ import { VaultHelper } from '@sre/Security/Vault.service/Vault.helper';
10
+ import { IAgent } from '@sre/types/Agent.types';
11
+ import { SystemEvents } from '@sre/Core/SystemEvents';
12
+ import * as acorn from 'acorn';
13
+
14
+ export const cachePrefix = 'serverless_code';
15
+ export const cacheTTL = 60 * 60 * 24 * 16; // 16 days
16
+ const PER_SECOND_COST = 0.0001;
17
+
18
+ export function getLambdaFunctionName(agentId: string, componentId: string) {
19
+ return `${agentId}-${componentId}`;
20
+ }
21
+
22
+
23
+ export function generateCodeHash(code_body: string, codeInputs: string[], envVariables: string[]) {
24
+ const bodyHash = getSanitizeCodeHash(code_body);
25
+ const inputsHash = getSanitizeCodeHash(JSON.stringify(codeInputs));
26
+ const envVariablesHash = getSanitizeCodeHash(JSON.stringify(envVariables));
27
+ return `body-${bodyHash}__inputs-${inputsHash}__env-${envVariablesHash}`;
28
+ }
29
+
30
+ export function getSanitizeCodeHash(rawCode: string) {
31
+ const code = replaceVaultKeysTemplateVars(rawCode, {});
32
+ let output = '';
33
+ let isSingleQuote = false;
34
+ let isDoubleQuote = false;
35
+ let isTemplateLiteral = false;
36
+ let isRegex = false;
37
+ let isComment = false;
38
+ let prevChar = '';
39
+
40
+ for (let i = 0; i < code.length; i++) {
41
+ let char = code[i];
42
+ let nextChar = code[i + 1];
43
+
44
+ // Toggle string flags
45
+ if (char === "'" && !isDoubleQuote && !isTemplateLiteral && prevChar !== '\\') isSingleQuote = !isSingleQuote;
46
+ if (char === '"' && !isSingleQuote && !isTemplateLiteral && prevChar !== '\\') isDoubleQuote = !isDoubleQuote;
47
+ if (char === '`' && !isSingleQuote && !isDoubleQuote && prevChar !== '\\') isTemplateLiteral = !isTemplateLiteral;
48
+
49
+ // Handle regex cases
50
+ if (char === '/' && nextChar === '/' && !isSingleQuote && !isDoubleQuote && !isTemplateLiteral && !isRegex) {
51
+ isComment = true; // Single-line comment
52
+ }
53
+ if (char === '/' && nextChar === '*' && !isSingleQuote && !isDoubleQuote && !isTemplateLiteral) {
54
+ isComment = true; // Multi-line comment start
55
+ }
56
+ if (char === '*' && nextChar === '/' && isComment) {
57
+ isComment = false; // Multi-line comment end
58
+ i++; // Skip ending slash
59
+ continue;
60
+ }
61
+ if (char === '\n' && isComment) {
62
+ isComment = false; // End single-line comment
63
+ }
64
+
65
+ if (!isComment) {
66
+ output += char;
67
+ }
68
+ prevChar = char;
69
+ }
70
+
71
+ return crypto.createHash('md5').update(output.replace(/\s+/g, ' ').trim()).digest('hex');
72
+ }
73
+
74
+ export async function getDeployedCodeHash(agentId: string, componentId: string) {
75
+ const redisCache = ConnectorService.getCacheConnector();
76
+ const cachedCodeHash = await redisCache.user(AccessCandidate.agent(agentId)).get(`${cachePrefix}_${agentId}-${componentId}`);
77
+ return cachedCodeHash;
78
+ }
79
+
80
+ export async function setDeployedCodeHash(agentId: string, componentId: string, codeHash: string) {
81
+ const redisCache = ConnectorService.getCacheConnector();
82
+ await redisCache
83
+ .user(AccessCandidate.agent(agentId))
84
+ .set(`${cachePrefix}_${agentId}-${componentId}`, codeHash, null, null, cacheTTL);
85
+ }
86
+
87
+ function replaceVaultKeysTemplateVars(code: string, envVariables: Record<string, string>) {
88
+ const regex = /\{\{KEY\((.*?)\)\}\}/g;
89
+ return code.replaceAll(regex, (match, p1) => `process.env.${p1}`);
90
+ }
91
+
92
+ export function generateLambdaCode(code: string, parameters: string[], envVariables: Record<string, string>) {
93
+ const codeWithEnvVariables = envVariables && Object.keys(envVariables).length ? replaceVaultKeysTemplateVars(code, envVariables) : code;
94
+ const lambdaCode = `
95
+ ${codeWithEnvVariables}
96
+ export const handler = async (event, context) => {
97
+ try {
98
+ context.callbackWaitsForEmptyEventLoop = false;
99
+ let startTime = Date.now();
100
+
101
+ ${parameters && parameters.length ? parameters.map((variable) => `const ${variable} = event.${variable};`).join('\n') : ''}
102
+ const result = await main(${parameters.join(', ')});
103
+
104
+ let endTime = Date.now();
105
+ return {
106
+ result,
107
+ executionTime: endTime - startTime
108
+ }
109
+ } catch (e) {
110
+ throw e;
111
+ }
112
+ };`;
113
+ return lambdaCode;
114
+ }
115
+
116
+ export async function zipCode(directory: string) {
117
+ return new Promise((resolve, reject) => {
118
+ zl.archiveFolder(directory, `${directory}.zip`).then(
119
+ function () {
120
+ resolve(`${directory}.zip`);
121
+ },
122
+ function (err) {
123
+ reject(err);
124
+ },
125
+ );
126
+ });
127
+ }
128
+
129
+ export async function createOrUpdateLambdaFunction(functionName, zipFilePath, awsConfigs, envVariables: Record<string, string>) {
130
+ const client = new LambdaClient({
131
+ region: awsConfigs.region,
132
+ credentials: {
133
+ accessKeyId: awsConfigs.accessKeyId,
134
+ secretAccessKey: awsConfigs.secretAccessKey,
135
+ },
136
+ });
137
+ const functionContent = fs.readFileSync(zipFilePath);
138
+
139
+ try {
140
+ // Check if the function exists
141
+ const exisitingFunction = await getDeployedFunction(functionName, awsConfigs);
142
+ if (exisitingFunction) {
143
+ if (exisitingFunction.status === 'InProgress') {
144
+ await verifyFunctionDeploymentStatus(functionName, client);
145
+ }
146
+ // Update function code if it exists
147
+ const updateCodeParams = {
148
+ FunctionName: functionName,
149
+ ZipFile: functionContent,
150
+ };
151
+ const updateFunctionCodeCommand = new UpdateFunctionCodeCommand(updateCodeParams);
152
+ await client.send(updateFunctionCodeCommand);
153
+ await verifyFunctionDeploymentStatus(functionName, client);
154
+
155
+ if (envVariables && Object.keys(envVariables).length) {
156
+ await updateLambdaFunctionConfiguration(client, functionName, envVariables);
157
+ await verifyFunctionDeploymentStatus(functionName, client);
158
+ }
159
+ } else {
160
+ // Create function if it does not exist
161
+ let roleArn = '';
162
+ // check if the role exists
163
+ try {
164
+ const iamClient = new IAMClient({
165
+ region: awsConfigs.region,
166
+ credentials: { accessKeyId: awsConfigs.accessKeyId, secretAccessKey: awsConfigs.secretAccessKey },
167
+ });
168
+ const getRoleCommand = new GetRoleCommand({ RoleName: `smyth-${functionName}-role` });
169
+ const roleResponse: GetRoleCommandOutput = await iamClient.send(getRoleCommand);
170
+ roleArn = roleResponse.Role.Arn;
171
+ } catch (error) {
172
+ if (error.name === 'NoSuchEntityException') {
173
+ // create role
174
+ const iamClient = new IAMClient({
175
+ region: awsConfigs.region,
176
+ credentials: { accessKeyId: awsConfigs.accessKeyId, secretAccessKey: awsConfigs.secretAccessKey },
177
+ });
178
+ const createRoleCommand = new CreateRoleCommand({
179
+ RoleName: `smyth-${functionName}-role`,
180
+ AssumeRolePolicyDocument: getLambdaRolePolicy(),
181
+ });
182
+ const roleResponse: CreateRoleCommandOutput = await iamClient.send(createRoleCommand);
183
+ await waitForRoleDeploymentStatus(`smyth-${functionName}-role`, iamClient);
184
+ roleArn = roleResponse.Role.Arn;
185
+ } else {
186
+ throw error;
187
+ }
188
+ }
189
+
190
+ const functionParams = {
191
+ Code: { ZipFile: functionContent },
192
+ FunctionName: functionName,
193
+ Handler: 'index.handler',
194
+ Role: roleArn,
195
+ Runtime: Runtime.nodejs18x,
196
+ Layers: [],
197
+ Timeout: 900,
198
+ Tags: {
199
+ 'auto-delete': 'true',
200
+ },
201
+ MemorySize: 256,
202
+ ...(envVariables && Object.keys(envVariables).length ? { Environment: { Variables: envVariables } } : {}),
203
+ };
204
+
205
+ const functionCreateCommand = new CreateFunctionCommand(functionParams);
206
+ const functionResponse = await client.send(functionCreateCommand);
207
+ // console.log('Function ARN:', functionResponse.FunctionArn);
208
+ await verifyFunctionDeploymentStatus(functionName, client);
209
+ }
210
+ } catch (error) {
211
+ throw error;
212
+ }
213
+ }
214
+
215
+ function updateLambdaFunctionConfiguration(client: LambdaClient, functionName: string, envVariables: Record<string, string>) {
216
+ const updateFunctionConfigurationParams = {
217
+ FunctionName: functionName,
218
+ Environment: {
219
+ Variables: envVariables,
220
+ },
221
+ };
222
+ const updateFunctionConfigurationCommand = new UpdateFunctionConfigurationCommand(updateFunctionConfigurationParams);
223
+ return client.send(updateFunctionConfigurationCommand);
224
+ }
225
+
226
+ export async function waitForRoleDeploymentStatus(roleName, client): Promise<boolean> {
227
+ return new Promise((resolve, reject) => {
228
+ try {
229
+ let interval = setInterval(async () => {
230
+ const getRoleCommand = new GetRoleCommand({ RoleName: roleName });
231
+ const roleResponse = await client.send(getRoleCommand);
232
+ if (roleResponse.Role.AssumeRolePolicyDocument) {
233
+ clearInterval(interval);
234
+ return resolve(true);
235
+ }
236
+ }, 7000);
237
+ } catch (error) {
238
+ return false;
239
+ }
240
+ });
241
+ }
242
+
243
+ export async function verifyFunctionDeploymentStatus(functionName, client): Promise<boolean> {
244
+ return new Promise((resolve, reject) => {
245
+ try {
246
+ let interval = setInterval(async () => {
247
+ const getFunctionCommand = new GetFunctionCommand({ FunctionName: functionName });
248
+ const lambdaResponse = await client.send(getFunctionCommand);
249
+
250
+ if (lambdaResponse.Configuration.LastUpdateStatus === 'Successful') {
251
+ clearInterval(interval);
252
+ return resolve(true);
253
+ }
254
+ }, 5000);
255
+ } catch (error) {
256
+ return false;
257
+ }
258
+ });
259
+ }
260
+
261
+ export function getLambdaRolePolicy() {
262
+ return JSON.stringify({
263
+ Version: '2012-10-17',
264
+ Statement: [
265
+ {
266
+ Effect: 'Allow',
267
+ Principal: {
268
+ Service: 'lambda.amazonaws.com',
269
+ },
270
+ Action: 'sts:AssumeRole',
271
+ },
272
+ ],
273
+ });
274
+ }
275
+
276
+
277
+ export async function updateDeployedCodeTTL(agentId: string, componentId: string, ttl: number) {
278
+ const redisCache = ConnectorService.getCacheConnector();
279
+ await redisCache.user(AccessCandidate.agent(agentId)).updateTTL(`${cachePrefix}_${agentId}-${componentId}`, ttl);
280
+ }
281
+
282
+ export async function invokeLambdaFunction(
283
+ functionName: string,
284
+ inputs: { [key: string]: any },
285
+ awsCredentials: AWSCredentials & AWSRegionConfig,
286
+ ): Promise<any> {
287
+ try {
288
+ const client = new LambdaClient({
289
+ region: awsCredentials.region as string,
290
+ ...(awsCredentials.accessKeyId && {
291
+ credentials: {
292
+ accessKeyId: awsCredentials.accessKeyId as string,
293
+ secretAccessKey: awsCredentials.secretAccessKey as string,
294
+ },
295
+ }),
296
+ });
297
+
298
+ const invokeCommand = new InvokeCommand({
299
+ FunctionName: functionName,
300
+ Payload: new TextEncoder().encode(`${JSON.stringify(inputs)}`),
301
+ InvocationType: 'RequestResponse',
302
+ });
303
+
304
+ const response: InvokeCommandOutput = await client.send(invokeCommand);
305
+ if (response.FunctionError) {
306
+ throw new Error(new TextDecoder().decode(response.Payload));
307
+ }
308
+ return new TextDecoder().decode(response.Payload);
309
+ } catch (error) {
310
+ throw error;
311
+ }
312
+ }
313
+
314
+ export async function getDeployedFunction(functionName: string, awsConfigs: AWSCredentials & AWSRegionConfig) {
315
+ try {
316
+ const client = new LambdaClient({
317
+ region: awsConfigs.region as string,
318
+ credentials: {
319
+ accessKeyId: awsConfigs.accessKeyId as string,
320
+ secretAccessKey: awsConfigs.secretAccessKey as string,
321
+ },
322
+ });
323
+ const getFunctionCommand = new GetFunctionCommand({ FunctionName: functionName });
324
+ const lambdaResponse: GetFunctionCommandOutput = await client.send(getFunctionCommand);
325
+ return {
326
+ status: lambdaResponse.Configuration.LastUpdateStatus,
327
+ functionName: lambdaResponse.Configuration.FunctionName,
328
+ functionVersion: lambdaResponse.Configuration.Version,
329
+ updatedAt: lambdaResponse.Configuration.LastModified,
330
+ role: lambdaResponse.Configuration.Role,
331
+ runtime: lambdaResponse.Configuration.Runtime,
332
+ version: lambdaResponse.Configuration.Version,
333
+ };
334
+ } catch (error) {
335
+ return null;
336
+ }
337
+ }
338
+
339
+ export async function getLambdaCredentials(agent: IAgent, config: any): Promise<AWSConfig & { isUserProvidedKeys: boolean }> {
340
+ let awsAccessKeyId = null;
341
+ let awsSecretAccessKey = null;
342
+ let awsRegion = null;
343
+ let userProvidedKeys = false;
344
+ if (config.data.accessKeyId && config.data.secretAccessKey && config.data.region && config.data.use_own_keys) {
345
+ userProvidedKeys = true;
346
+ [awsAccessKeyId, awsSecretAccessKey] = await Promise.all([
347
+ VaultHelper.getTeamKey(extractKeyFromTemplateVar(config.data.accessKeyId), agent?.teamId),
348
+ VaultHelper.getTeamKey(extractKeyFromTemplateVar(config.data.secretAccessKey), agent?.teamId),
349
+ ]);
350
+ awsRegion = config.data.region;
351
+ }
352
+ const awsCredentials = {
353
+ accessKeyId: awsAccessKeyId,
354
+ secretAccessKey: awsSecretAccessKey,
355
+ region: awsRegion,
356
+ isUserProvidedKeys: userProvidedKeys,
357
+ };
358
+ return awsCredentials;
359
+ }
360
+
361
+ export function calculateExecutionCost(executionTime: number) {
362
+ // executionTime in milliseconds
363
+ const cost = (executionTime / 1000) * Number(PER_SECOND_COST);
364
+ return cost;
365
+ }
366
+
367
+ export function extractKeyFromTemplateVar(input: string) {
368
+ const regex = /\{\{KEY\((.*?)\)\}\}/;
369
+ const match = input.match(regex);
370
+ return match ? match[1] : input;
371
+ }
372
+
373
+ export function reportUsage({ cost, agentId, teamId }: { cost: number; agentId: string; teamId: string }) {
374
+ SystemEvents.emit('USAGE:API', {
375
+ sourceId: 'api:serverless_code.smyth',
376
+ cost,
377
+ agentId,
378
+ teamId,
379
+ });
380
+ }
381
+
382
+ export function validateAsyncMainFunction(rawCode: string): { isValid: boolean; error?: string; parameters?: string[]; dependencies?: string[] } {
383
+ try {
384
+ const code = replaceVaultKeysTemplateVars(rawCode, {});
385
+ // Parse the code using acorn
386
+ const ast = acorn.parse(code, {
387
+ ecmaVersion: 'latest',
388
+ sourceType: 'module'
389
+ });
390
+
391
+ // Extract library imports
392
+ const libraries = new Set<string>();
393
+ function extractPackageName(modulePath: string): string {
394
+ if (modulePath.startsWith('@')) {
395
+ // Handle scoped packages (e.g., @babel/core)
396
+ return modulePath.split('/').slice(0, 2).join('/');
397
+ }
398
+ return modulePath.split('/')[0]; // Extract the first part (main package)
399
+ }
400
+
401
+ function processNodeForImports(node: any): void {
402
+ if (!node) return;
403
+
404
+ // Handle ImportDeclaration (ES6 imports)
405
+ if (node.type === 'ImportDeclaration') {
406
+ const modulePath = node.source.value;
407
+ if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
408
+ // Skip relative imports and absolute paths
409
+ libraries.add(extractPackageName(modulePath));
410
+ }
411
+ }
412
+
413
+ // Handle CallExpression (require() calls)
414
+ if (node.type === 'CallExpression' &&
415
+ node.callee.type === 'Identifier' &&
416
+ node.callee.name === 'require' &&
417
+ node.arguments.length > 0 &&
418
+ node.arguments[0].type === 'Literal') {
419
+ const modulePath = node.arguments[0].value;
420
+ if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
421
+ libraries.add(extractPackageName(modulePath));
422
+ }
423
+ }
424
+
425
+ // Handle dynamic import() calls
426
+ if (node.type === 'CallExpression' &&
427
+ node.callee.type === 'Import' &&
428
+ node.arguments.length > 0 &&
429
+ node.arguments[0].type === 'Literal') {
430
+ const modulePath = node.arguments[0].value;
431
+ if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
432
+ libraries.add(extractPackageName(modulePath));
433
+ }
434
+ }
435
+
436
+ // Recursively process child nodes
437
+ for (const key in node) {
438
+ if (node[key] && typeof node[key] === 'object') {
439
+ if (Array.isArray(node[key])) {
440
+ (node[key] as any[]).forEach(processNodeForImports);
441
+ } else {
442
+ processNodeForImports(node[key]);
443
+ }
444
+ }
445
+ }
446
+ }
447
+
448
+ // Extract dependencies from the entire AST
449
+ processNodeForImports(ast);
450
+ const dependencies = Array.from(libraries) as string[];
451
+
452
+ // Check if there's a function declaration or function expression named 'main' at the root level
453
+ let hasAsyncMain = false;
454
+ let hasMain = false;
455
+ let mainParameters: string[] = [];
456
+
457
+ for (const node of ast.body) {
458
+ if (node.type === 'FunctionDeclaration') {
459
+ if (node.id?.name === 'main') {
460
+ hasMain = true;
461
+ if (node.async) {
462
+ hasAsyncMain = true;
463
+ mainParameters = extractParameters(node.params);
464
+ break;
465
+ }
466
+ }
467
+ } else if (node.type === 'VariableDeclaration') {
468
+ // Check for const/let/var main = async function() or const/let/var main = async () =>
469
+ for (const declarator of node.declarations) {
470
+ if (declarator.id.type === 'Identifier' && declarator.id.name === 'main') {
471
+ hasMain = true;
472
+ if (declarator.init) {
473
+ if (declarator.init.type === 'FunctionExpression' && declarator.init.async) {
474
+ hasAsyncMain = true;
475
+ mainParameters = extractParameters(declarator.init.params);
476
+ break;
477
+ } else if (declarator.init.type === 'ArrowFunctionExpression' && declarator.init.async) {
478
+ hasAsyncMain = true;
479
+ mainParameters = extractParameters(declarator.init.params);
480
+ break;
481
+ }
482
+ }
483
+ }
484
+ }
485
+ } else if (node.type === 'ExpressionStatement' && node.expression.type === 'AssignmentExpression') {
486
+ // Check for main = async function() or main = async () =>
487
+ if (node.expression.left.type === 'Identifier' && node.expression.left.name === 'main') {
488
+ hasMain = true;
489
+ const right = node.expression.right;
490
+ if ((right.type === 'FunctionExpression' || right.type === 'ArrowFunctionExpression') && right.async) {
491
+ hasAsyncMain = true;
492
+ mainParameters = extractParameters(right.params);
493
+ break;
494
+ }
495
+ }
496
+ }
497
+ }
498
+
499
+ if (!hasMain) {
500
+ return {
501
+ isValid: false,
502
+ error: 'No main function found at root level',
503
+ dependencies
504
+ };
505
+ }
506
+
507
+ if (!hasAsyncMain) {
508
+ return {
509
+ isValid: false,
510
+ error: 'Main function exists but is not async',
511
+ dependencies
512
+ };
513
+ }
514
+
515
+ return { isValid: true, parameters: mainParameters, dependencies };
516
+ } catch (error) {
517
+ return {
518
+ isValid: false,
519
+ error: `Failed to parse code: ${error.message}`
520
+ };
521
+ }
522
+ }
523
+
524
+ function extractParameters(params: any[]): string[] {
525
+ return params.map((param: any): string => {
526
+ if (param.type === 'Identifier') {
527
+ return param.name;
528
+ } else if (param.type === 'AssignmentPattern' && param.left.type === 'Identifier') {
529
+ return param.left.name;
530
+ } else if (param.type === 'RestElement' && param.argument.type === 'Identifier') {
531
+ return param.argument.name;
532
+ } else if (param.type === 'ObjectPattern') {
533
+ // For destructured objects, return the object name or a placeholder
534
+ return param.name || '[object]';
535
+ } else if (param.type === 'ArrayPattern') {
536
+ // For destructured arrays, return a placeholder
537
+ return '[array]';
538
+ }
539
+ return '[unknown]';
540
+ });
541
+ }
542
+
543
+ export function generateCodeFromLegacyComponent(code_body: string, code_imports: string, codeInputs: string[]) {
544
+ const code = `
545
+ ${code_imports}
546
+ async function main(${codeInputs.join(', ')}) {
547
+ ${code_body}
548
+ }
549
+ `
550
+ return code;
551
+ }
552
+
553
+ export function extractAllKeyNamesFromTemplateVars(input: string): string[] {
554
+ const regex = /\{\{KEY\((.*?)\)\}\}/g;
555
+ const matches = [];
556
+ let match;
557
+ while ((match = regex.exec(input)) !== null) {
558
+ if (match[1]) {
559
+ matches.push(match[1]);
560
+ }
561
+ }
562
+ return matches;
563
+ }
564
+
565
+
566
+ async function fetchVaultSecret(keyName: string, agentTeamId: string): Promise<{ value: string, key: string }> {
567
+ const vaultSecret = await VaultHelper.getAgentKey(keyName, agentTeamId);
568
+ return {
569
+ value: vaultSecret,
570
+ key: keyName,
571
+ };
572
+
573
+ }
574
+
575
+ export async function getCurrentEnvironmentVariables(agentTeamId: string, code: string): Promise<Record<string, string>> {
576
+ const allKeyNames = extractAllKeyNamesFromTemplateVars(code);
577
+ const envVariables: Record<string, string> = {};
578
+ const vaultSecrets = await Promise.all(allKeyNames.map((keyName) => fetchVaultSecret(keyName, agentTeamId)));
579
+ vaultSecrets.forEach((secret) => {
580
+ envVariables[secret.key] = secret.value;
581
+ });
582
+ return envVariables;
583
+ }
584
+
585
+ export function getSortedObjectValues(obj: Record<string, string>): string[] {
586
+ const sortedKeys = Object.keys(obj).sort();
587
+ return sortedKeys.map((key) => obj[key]);
588
+ }