@smythos/sre 1.5.1 → 1.5.4
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.
- package/LICENSE +18 -0
- package/dist/index.js +22329 -4
- package/dist/index.js.map +1 -1
- package/dist/types/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.d.ts +2 -2
- package/dist/types/subsystems/IO/VectorDB.service/embed/BaseEmbedding.d.ts +11 -7
- package/dist/types/types/VectorDB.types.d.ts +13 -11
- package/package.json +102 -127
- package/src/Components/APICall/APICall.class.ts +155 -0
- package/src/Components/APICall/AccessTokenManager.ts +130 -0
- package/src/Components/APICall/ArrayBufferResponse.helper.ts +58 -0
- package/src/Components/APICall/OAuth.helper.ts +294 -0
- package/src/Components/APICall/mimeTypeCategories.ts +46 -0
- package/src/Components/APICall/parseData.ts +167 -0
- package/src/Components/APICall/parseHeaders.ts +41 -0
- package/src/Components/APICall/parseProxy.ts +68 -0
- package/src/Components/APICall/parseUrl.ts +91 -0
- package/src/Components/APIEndpoint.class.ts +234 -0
- package/src/Components/APIOutput.class.ts +58 -0
- package/src/Components/AgentPlugin.class.ts +102 -0
- package/src/Components/Async.class.ts +155 -0
- package/src/Components/Await.class.ts +90 -0
- package/src/Components/Classifier.class.ts +158 -0
- package/src/Components/Component.class.ts +94 -0
- package/src/Components/ComponentHost.class.ts +38 -0
- package/src/Components/DataSourceCleaner.class.ts +92 -0
- package/src/Components/DataSourceIndexer.class.ts +181 -0
- package/src/Components/DataSourceLookup.class.ts +141 -0
- package/src/Components/FEncDec.class.ts +29 -0
- package/src/Components/FHash.class.ts +33 -0
- package/src/Components/FSign.class.ts +80 -0
- package/src/Components/FSleep.class.ts +25 -0
- package/src/Components/FTimestamp.class.ts +25 -0
- package/src/Components/FileStore.class.ts +75 -0
- package/src/Components/ForEach.class.ts +97 -0
- package/src/Components/GPTPlugin.class.ts +70 -0
- package/src/Components/GenAILLM.class.ts +395 -0
- package/src/Components/HuggingFace.class.ts +314 -0
- package/src/Components/Image/imageSettings.config.ts +70 -0
- package/src/Components/ImageGenerator.class.ts +407 -0
- package/src/Components/JSONFilter.class.ts +54 -0
- package/src/Components/LLMAssistant.class.ts +213 -0
- package/src/Components/LogicAND.class.ts +28 -0
- package/src/Components/LogicAtLeast.class.ts +85 -0
- package/src/Components/LogicAtMost.class.ts +86 -0
- package/src/Components/LogicOR.class.ts +29 -0
- package/src/Components/LogicXOR.class.ts +34 -0
- package/src/Components/MCPClient.class.ts +112 -0
- package/src/Components/PromptGenerator.class.ts +122 -0
- package/src/Components/ScrapflyWebScrape.class.ts +159 -0
- package/src/Components/TavilyWebSearch.class.ts +98 -0
- package/src/Components/index.ts +77 -0
- package/src/Core/AgentProcess.helper.ts +240 -0
- package/src/Core/Connector.class.ts +123 -0
- package/src/Core/ConnectorsService.ts +192 -0
- package/src/Core/DummyConnector.ts +49 -0
- package/src/Core/HookService.ts +105 -0
- package/src/Core/SmythRuntime.class.ts +292 -0
- package/src/Core/SystemEvents.ts +15 -0
- package/src/Core/boot.ts +55 -0
- package/src/config.ts +15 -0
- package/src/constants.ts +125 -0
- package/src/data/hugging-face.params.json +580 -0
- package/src/helpers/BinaryInput.helper.ts +324 -0
- package/src/helpers/Conversation.helper.ts +1094 -0
- package/src/helpers/JsonContent.helper.ts +97 -0
- package/src/helpers/LocalCache.helper.ts +97 -0
- package/src/helpers/Log.helper.ts +234 -0
- package/src/helpers/OpenApiParser.helper.ts +150 -0
- package/src/helpers/S3Cache.helper.ts +129 -0
- package/src/helpers/SmythURI.helper.ts +5 -0
- package/src/helpers/TemplateString.helper.ts +243 -0
- package/src/helpers/TypeChecker.helper.ts +329 -0
- package/src/index.ts +179 -0
- package/src/index.ts.bak +179 -0
- package/src/subsystems/AgentManager/Agent.class.ts +1108 -0
- package/src/subsystems/AgentManager/Agent.helper.ts +3 -0
- package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +230 -0
- package/src/subsystems/AgentManager/AgentData.service/connectors/CLIAgentDataConnector.class.ts +66 -0
- package/src/subsystems/AgentManager/AgentData.service/connectors/LocalAgentDataConnector.class.ts +142 -0
- package/src/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.ts +39 -0
- package/src/subsystems/AgentManager/AgentData.service/index.ts +18 -0
- package/src/subsystems/AgentManager/AgentLogger.class.ts +297 -0
- package/src/subsystems/AgentManager/AgentRequest.class.ts +51 -0
- package/src/subsystems/AgentManager/AgentRuntime.class.ts +559 -0
- package/src/subsystems/AgentManager/AgentSSE.class.ts +101 -0
- package/src/subsystems/AgentManager/AgentSettings.class.ts +52 -0
- package/src/subsystems/AgentManager/Component.service/ComponentConnector.ts +32 -0
- package/src/subsystems/AgentManager/Component.service/connectors/LocalComponentConnector.class.ts +59 -0
- package/src/subsystems/AgentManager/Component.service/index.ts +11 -0
- package/src/subsystems/AgentManager/EmbodimentSettings.class.ts +47 -0
- package/src/subsystems/AgentManager/ForkedAgent.class.ts +153 -0
- package/src/subsystems/AgentManager/OSResourceMonitor.ts +77 -0
- package/src/subsystems/ComputeManager/Code.service/CodeConnector.ts +99 -0
- package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +63 -0
- package/src/subsystems/ComputeManager/Code.service/index.ts +11 -0
- package/src/subsystems/IO/CLI.service/CLIConnector.ts +47 -0
- package/src/subsystems/IO/CLI.service/index.ts +9 -0
- package/src/subsystems/IO/Log.service/LogConnector.ts +32 -0
- package/src/subsystems/IO/Log.service/connectors/ConsoleLog.class.ts +28 -0
- package/src/subsystems/IO/Log.service/index.ts +13 -0
- package/src/subsystems/IO/NKV.service/NKVConnector.ts +41 -0
- package/src/subsystems/IO/NKV.service/connectors/NKVRAM.class.ts +204 -0
- package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +182 -0
- package/src/subsystems/IO/NKV.service/index.ts +12 -0
- package/src/subsystems/IO/Router.service/RouterConnector.ts +21 -0
- package/src/subsystems/IO/Router.service/connectors/ExpressRouter.class.ts +48 -0
- package/src/subsystems/IO/Router.service/connectors/NullRouter.class.ts +40 -0
- package/src/subsystems/IO/Router.service/index.ts +11 -0
- package/src/subsystems/IO/Storage.service/SmythFS.class.ts +472 -0
- package/src/subsystems/IO/Storage.service/StorageConnector.ts +66 -0
- package/src/subsystems/IO/Storage.service/connectors/LocalStorage.class.ts +305 -0
- package/src/subsystems/IO/Storage.service/connectors/S3Storage.class.ts +418 -0
- package/src/subsystems/IO/Storage.service/index.ts +13 -0
- package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +108 -0
- package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +454 -0
- package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +384 -0
- package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +421 -0
- package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +107 -0
- package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +109 -0
- package/src/subsystems/IO/VectorDB.service/embed/index.ts +21 -0
- package/src/subsystems/IO/VectorDB.service/index.ts +14 -0
- package/src/subsystems/LLMManager/LLM.helper.ts +221 -0
- package/src/subsystems/LLMManager/LLM.inference.ts +335 -0
- package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +375 -0
- package/src/subsystems/LLMManager/LLM.service/LLMCredentials.helper.ts +145 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +632 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +405 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +81 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +689 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +257 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/OpenAI.class.ts +848 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +255 -0
- package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +193 -0
- package/src/subsystems/LLMManager/LLM.service/index.ts +43 -0
- package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +281 -0
- package/src/subsystems/LLMManager/ModelsProvider.service/connectors/SmythModelsProvider.class.ts +229 -0
- package/src/subsystems/LLMManager/ModelsProvider.service/index.ts +11 -0
- package/src/subsystems/LLMManager/custom-models.ts +854 -0
- package/src/subsystems/LLMManager/models.ts +2539 -0
- package/src/subsystems/LLMManager/paramMappings.ts +69 -0
- package/src/subsystems/MemoryManager/Cache.service/CacheConnector.ts +86 -0
- package/src/subsystems/MemoryManager/Cache.service/connectors/LocalStorageCache.class.ts +297 -0
- package/src/subsystems/MemoryManager/Cache.service/connectors/RAMCache.class.ts +201 -0
- package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +252 -0
- package/src/subsystems/MemoryManager/Cache.service/connectors/S3Cache.class.ts +373 -0
- package/src/subsystems/MemoryManager/Cache.service/index.ts +15 -0
- package/src/subsystems/MemoryManager/LLMCache.ts +72 -0
- package/src/subsystems/MemoryManager/LLMContext.ts +125 -0
- package/src/subsystems/MemoryManager/RuntimeContext.ts +249 -0
- package/src/subsystems/Security/AccessControl/ACL.class.ts +208 -0
- package/src/subsystems/Security/AccessControl/AccessCandidate.class.ts +76 -0
- package/src/subsystems/Security/AccessControl/AccessRequest.class.ts +52 -0
- package/src/subsystems/Security/Account.service/AccountConnector.ts +41 -0
- package/src/subsystems/Security/Account.service/connectors/AWSAccount.class.ts +76 -0
- package/src/subsystems/Security/Account.service/connectors/DummyAccount.class.ts +130 -0
- package/src/subsystems/Security/Account.service/connectors/JSONFileAccount.class.ts +159 -0
- package/src/subsystems/Security/Account.service/index.ts +14 -0
- package/src/subsystems/Security/Credentials.helper.ts +62 -0
- package/src/subsystems/Security/ManagedVault.service/ManagedVaultConnector.ts +34 -0
- package/src/subsystems/Security/ManagedVault.service/connectors/NullManagedVault.class.ts +57 -0
- package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +154 -0
- package/src/subsystems/Security/ManagedVault.service/index.ts +12 -0
- package/src/subsystems/Security/SecureConnector.class.ts +110 -0
- package/src/subsystems/Security/Vault.service/Vault.helper.ts +30 -0
- package/src/subsystems/Security/Vault.service/VaultConnector.ts +26 -0
- package/src/subsystems/Security/Vault.service/connectors/HashicorpVault.class.ts +46 -0
- package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +166 -0
- package/src/subsystems/Security/Vault.service/connectors/NullVault.class.ts +54 -0
- package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +140 -0
- package/src/subsystems/Security/Vault.service/index.ts +12 -0
- package/src/types/ACL.types.ts +104 -0
- package/src/types/AWS.types.ts +9 -0
- package/src/types/Agent.types.ts +61 -0
- package/src/types/AgentLogger.types.ts +17 -0
- package/src/types/Cache.types.ts +1 -0
- package/src/types/Common.types.ts +3 -0
- package/src/types/LLM.types.ts +419 -0
- package/src/types/Redis.types.ts +8 -0
- package/src/types/SRE.types.ts +64 -0
- package/src/types/Security.types.ts +18 -0
- package/src/types/Storage.types.ts +5 -0
- package/src/types/VectorDB.types.ts +86 -0
- package/src/utils/base64.utils.ts +275 -0
- package/src/utils/cli.utils.ts +68 -0
- package/src/utils/data.utils.ts +263 -0
- package/src/utils/date-time.utils.ts +22 -0
- package/src/utils/general.utils.ts +238 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/numbers.utils.ts +13 -0
- package/src/utils/oauth.utils.ts +35 -0
- package/src/utils/string.utils.ts +414 -0
- package/src/utils/url.utils.ts +19 -0
- package/src/utils/validation.utils.ts +74 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { SREConnectorConfig, TConnectorService, TServiceRegistry } from '@sre/types/SRE.types';
|
|
2
|
+
import { DummyConnector } from './DummyConnector';
|
|
3
|
+
import { Logger } from '../helpers/Log.helper';
|
|
4
|
+
import { Connector } from './Connector.class';
|
|
5
|
+
import { getFormattedStackTrace, isSubclassOf, printStackTrace } from '@sre/utils';
|
|
6
|
+
import { SystemEvents } from './SystemEvents';
|
|
7
|
+
import { StorageConnector } from '@sre/IO/Storage.service/StorageConnector';
|
|
8
|
+
import { CacheConnector } from '@sre/MemoryManager/Cache.service/CacheConnector';
|
|
9
|
+
import { LLMConnector } from '@sre/LLMManager/LLM.service/LLMConnector';
|
|
10
|
+
import { VaultConnector } from '@sre/Security/Vault.service/VaultConnector';
|
|
11
|
+
import { AccountConnector } from '@sre/Security/Account.service/AccountConnector';
|
|
12
|
+
import { AgentDataConnector } from '@sre/AgentManager/AgentData.service/AgentDataConnector';
|
|
13
|
+
import { VectorDBConnector } from '@sre/IO/VectorDB.service/VectorDBConnector';
|
|
14
|
+
import { CLIConnector } from '@sre/IO/CLI.service/CLIConnector';
|
|
15
|
+
import { NKVConnector } from '@sre/IO/NKV.service/NKVConnector';
|
|
16
|
+
import { RouterConnector } from '@sre/IO/Router.service/RouterConnector';
|
|
17
|
+
import { ManagedVaultConnector } from '@sre/Security/ManagedVault.service/ManagedVaultConnector';
|
|
18
|
+
import { LogConnector } from '@sre/IO/Log.service/LogConnector';
|
|
19
|
+
import { ComponentConnector } from '@sre/AgentManager/Component.service/ComponentConnector';
|
|
20
|
+
import { ModelsProviderConnector } from '@sre/LLMManager/ModelsProvider.service/ModelsProviderConnector';
|
|
21
|
+
const console = Logger('ConnectorService');
|
|
22
|
+
|
|
23
|
+
let ServiceRegistry: TServiceRegistry = {};
|
|
24
|
+
let _ready = false;
|
|
25
|
+
SystemEvents.on('SRE:Booted', (services) => {
|
|
26
|
+
ServiceRegistry = services;
|
|
27
|
+
_ready = true;
|
|
28
|
+
});
|
|
29
|
+
export class ConnectorService {
|
|
30
|
+
public static Connectors = {};
|
|
31
|
+
|
|
32
|
+
public static ConnectorInstances: any = {};
|
|
33
|
+
public static get ready() {
|
|
34
|
+
return _ready;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public static get service(): TServiceRegistry {
|
|
38
|
+
return ServiceRegistry;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Allows SRE services to register their connectors, a registered conector can then be initialized and used by SRE or its services
|
|
42
|
+
* @param connectorType
|
|
43
|
+
* @param connectorName
|
|
44
|
+
* @param connectorConstructor
|
|
45
|
+
* @returns
|
|
46
|
+
*/
|
|
47
|
+
static register(connectorType: TConnectorService, connectorName: string, connectorConstructor: any) {
|
|
48
|
+
if (typeof connectorConstructor !== 'function' || !isSubclassOf(connectorConstructor, Connector)) {
|
|
49
|
+
console.error(`Invalid Connector ${connectorType}:${connectorName}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (!ConnectorService.Connectors[connectorType]) {
|
|
53
|
+
ConnectorService.Connectors[connectorType] = {};
|
|
54
|
+
}
|
|
55
|
+
ConnectorService.Connectors[connectorType][connectorName] = connectorConstructor;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The init method instantiates a connector and starts it, a connector cannot be used before it is initialized
|
|
60
|
+
* Usually the initialization phase happens during the SRE startup, but some connectors can be initialized later if they are not mandatory for the SRE to start
|
|
61
|
+
*
|
|
62
|
+
*
|
|
63
|
+
* @param connectorType
|
|
64
|
+
* @param connectorName
|
|
65
|
+
* @param settings
|
|
66
|
+
* @param isDefault
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
static init(connectorType: TConnectorService, connectorName: string, connectorId?: string, settings: any = {}, isDefault = false) {
|
|
70
|
+
if (ConnectorService.ConnectorInstances[connectorType]?.[connectorName]) {
|
|
71
|
+
throw new Error(`Connector ${connectorType}:${connectorName} already initialized`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const entry = ConnectorService.Connectors[connectorType];
|
|
75
|
+
if (!entry) return;
|
|
76
|
+
const connectorConstructor = entry[connectorName];
|
|
77
|
+
|
|
78
|
+
if (connectorConstructor) {
|
|
79
|
+
const connector: Connector = new connectorConstructor(settings);
|
|
80
|
+
if (connector.interactionHandler) {
|
|
81
|
+
connector.interactionHandler();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
connector.start();
|
|
85
|
+
if (!ConnectorService.ConnectorInstances[connectorType]) ConnectorService.ConnectorInstances[connectorType] = {};
|
|
86
|
+
const id = connectorId || connectorName;
|
|
87
|
+
ConnectorService.ConnectorInstances[connectorType][id] = connector;
|
|
88
|
+
|
|
89
|
+
if (!ConnectorService.ConnectorInstances[connectorType].default && isDefault) {
|
|
90
|
+
ConnectorService.ConnectorInstances[connectorType].default = connector;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return connector;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
static async _stop() {
|
|
97
|
+
for (let connectorName in ConnectorService.ConnectorInstances) {
|
|
98
|
+
let allConnectors: Connector[] = Object.values(ConnectorService.ConnectorInstances[connectorName]);
|
|
99
|
+
//deduplicate
|
|
100
|
+
allConnectors = allConnectors.filter((value, index, self) => self.indexOf(value) === index);
|
|
101
|
+
for (let connector of allConnectors) {
|
|
102
|
+
connector.stop();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
static getInstance<T>(connectorType: TConnectorService, connectorName: string = 'default'): T {
|
|
107
|
+
const instance = ConnectorService.ConnectorInstances[connectorType]?.[connectorName || 'default'] as T;
|
|
108
|
+
if (!instance) {
|
|
109
|
+
//TODO only apply the fallback below if resilient mode is enabled
|
|
110
|
+
// if (ConnectorService.ConnectorInstances[connectorType] && Object.keys(ConnectorService.ConnectorInstances[connectorType]).length > 0) {
|
|
111
|
+
// //return the first instance
|
|
112
|
+
// return ConnectorService.ConnectorInstances[connectorType][Object.keys(ConnectorService.ConnectorInstances[connectorType])[0]] as T;
|
|
113
|
+
// }
|
|
114
|
+
console.warn(`Connector ${connectorType} not initialized returning DummyConnector`);
|
|
115
|
+
//print stack trace
|
|
116
|
+
|
|
117
|
+
printStackTrace(console, 5);
|
|
118
|
+
|
|
119
|
+
return DummyConnector(connectorType) as T;
|
|
120
|
+
}
|
|
121
|
+
return instance;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static getStorageConnector(name?: string): StorageConnector {
|
|
125
|
+
return ConnectorService.getInstance<StorageConnector>(TConnectorService.Storage, name);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static getCacheConnector(name?: string): CacheConnector {
|
|
129
|
+
return ConnectorService.getInstance<any>(TConnectorService.Cache, name);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static getVectorDBConnector(name?: string): VectorDBConnector {
|
|
133
|
+
return ConnectorService.getInstance<VectorDBConnector>(TConnectorService.VectorDB, name);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static getNKVConnector(name?: string): NKVConnector {
|
|
137
|
+
return ConnectorService.getInstance<NKVConnector>(TConnectorService.NKV, name);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static getLLMConnector(name?: string): LLMConnector {
|
|
141
|
+
return ConnectorService.getInstance<LLMConnector>(TConnectorService.LLM, name);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static getVaultConnector(name?: string): VaultConnector {
|
|
145
|
+
return ConnectorService.getInstance<VaultConnector>(TConnectorService.Vault, name);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static getManagedVaultConnector(name?: string): ManagedVaultConnector {
|
|
149
|
+
return ConnectorService.getInstance<ManagedVaultConnector>(TConnectorService.ManagedVault, name);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static getAccountConnector(name?: string): AccountConnector {
|
|
153
|
+
return ConnectorService.getInstance<AccountConnector>(TConnectorService.Account, name);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static getAgentDataConnector(name?: string): AgentDataConnector {
|
|
157
|
+
return ConnectorService.getInstance<AgentDataConnector>(TConnectorService.AgentData, name);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static getCLIConnector(name?: string): CLIConnector {
|
|
161
|
+
return ConnectorService.getInstance<CLIConnector>(TConnectorService.CLI, name);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static getLogConnector(name?: string): LogConnector {
|
|
165
|
+
return ConnectorService.getInstance<LogConnector>(TConnectorService.Log, name);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static getComponentConnector(name?: string): ComponentConnector {
|
|
169
|
+
return ConnectorService.getInstance<ComponentConnector>(TConnectorService.Component, name);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static getModelsProviderConnector(name?: string): ModelsProviderConnector {
|
|
173
|
+
return ConnectorService.getInstance<ModelsProviderConnector>(TConnectorService.ModelsProvider, name);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static hasInstance(connectorType: TConnectorService, connectorName: string = 'default') {
|
|
177
|
+
const instance = ConnectorService.ConnectorInstances[connectorType]?.[connectorName];
|
|
178
|
+
return instance && instance.valid;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static getRouterConnector(name?: string): RouterConnector {
|
|
182
|
+
return ConnectorService.getInstance<RouterConnector>(TConnectorService.Router, name);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export abstract class ConnectorServiceProvider {
|
|
187
|
+
public abstract register();
|
|
188
|
+
public init() {}
|
|
189
|
+
public constructor() {
|
|
190
|
+
this.register();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Logger } from '../helpers/Log.helper';
|
|
2
|
+
import { getFormattedStackTrace, printStackTrace } from '../utils';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* DummyConnector is a placeholder for unimplemented connectors, it logs a warning when a method is called in order to help developers identify missing connectors
|
|
6
|
+
*/
|
|
7
|
+
export const DummyConnector: any = (name: string) => {
|
|
8
|
+
const logger = Logger(`DummyConnector<${name}>`);
|
|
9
|
+
return new Proxy(
|
|
10
|
+
{},
|
|
11
|
+
{
|
|
12
|
+
get: function (target, prop, receiver) {
|
|
13
|
+
//check if we are accessing the valid property
|
|
14
|
+
if (prop === 'valid') {
|
|
15
|
+
return false; //when DummyConnector is used it means that the main connector failed to load
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check if the property being accessed is a function
|
|
19
|
+
if (typeof target[prop] === 'function') {
|
|
20
|
+
return target[prop];
|
|
21
|
+
} else {
|
|
22
|
+
// Return a function that logs "unavailable"
|
|
23
|
+
return function (...args: any[]) {
|
|
24
|
+
const argsString =
|
|
25
|
+
args.length > 0
|
|
26
|
+
? args
|
|
27
|
+
.map((arg) => {
|
|
28
|
+
if (typeof arg === 'object') return JSON.stringify(arg, null, 0).slice(0, 50) + '...';
|
|
29
|
+
if (typeof arg === 'string') return `"${arg.slice(0, 50)}..."`;
|
|
30
|
+
if (typeof arg === 'number') return arg.toString();
|
|
31
|
+
if (typeof arg === 'boolean') return arg.toString();
|
|
32
|
+
if (typeof arg === 'function') return arg.toString();
|
|
33
|
+
if (typeof arg === 'symbol') return arg.toString();
|
|
34
|
+
if (typeof arg === 'undefined') return 'undefined';
|
|
35
|
+
|
|
36
|
+
return String(arg);
|
|
37
|
+
})
|
|
38
|
+
.join(', ')
|
|
39
|
+
: '(no arguments)';
|
|
40
|
+
|
|
41
|
+
logger.warn(`[!!] Unimplemented Connector tried to call: ${name}.${prop.toString()}(${argsString})`);
|
|
42
|
+
|
|
43
|
+
printStackTrace(logger, 3, 1); //the argument 1 means that we skip one more strack element because we are calling printStackTrace from an anonymous function
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Type definition for hook callbacks
|
|
2
|
+
type HookCallback = (...args: any[]) => void;
|
|
3
|
+
|
|
4
|
+
// Store hooks in a map where each hook name can have multiple callbacks
|
|
5
|
+
const hooks: { [key: string]: HookCallback[] } = {};
|
|
6
|
+
|
|
7
|
+
export class HookService {
|
|
8
|
+
/**
|
|
9
|
+
* Register a new hook callback for a given hook name
|
|
10
|
+
* @param hookName The name of the hook to register
|
|
11
|
+
* @param callback The callback function to execute when the hook is triggered
|
|
12
|
+
*/
|
|
13
|
+
static register(hookName: string, callback: HookCallback): void {
|
|
14
|
+
if (typeof callback !== 'function') {
|
|
15
|
+
throw new Error('Hook callback must be a function');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!hooks[hookName]) {
|
|
19
|
+
hooks[hookName] = [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
hooks[hookName].push(callback);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static trigger(hookName: string, ...args: any[]) {
|
|
26
|
+
if (hooks[hookName]) {
|
|
27
|
+
hooks[hookName].forEach((callback) => callback(...args));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Decorator function that executes registered hooks before the decorated method
|
|
34
|
+
* @param hookName The name of the hook to trigger
|
|
35
|
+
*/
|
|
36
|
+
export function hook(hookName: string) {
|
|
37
|
+
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
38
|
+
const originalMethod = descriptor.value;
|
|
39
|
+
|
|
40
|
+
descriptor.value = function (...args: any[]) {
|
|
41
|
+
// Execute all registered hooks for this hook name
|
|
42
|
+
if (hooks[hookName]) {
|
|
43
|
+
hooks[hookName].forEach((callback) => {
|
|
44
|
+
callback.apply(this, args);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Call the original method
|
|
49
|
+
return originalMethod.apply(this, args);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return descriptor;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Decorator function that executes registered hooks asynchronously before the decorated method
|
|
58
|
+
* @param hookName The name of the hook to trigger
|
|
59
|
+
*/
|
|
60
|
+
export function hookAsync(hookName: string) {
|
|
61
|
+
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
62
|
+
const originalMethod = descriptor.value;
|
|
63
|
+
|
|
64
|
+
descriptor.value = async function (...args: any[]) {
|
|
65
|
+
// Execute all registered hooks for this hook name
|
|
66
|
+
if (hooks[hookName]) {
|
|
67
|
+
// Wait for all hooks to complete before proceeding
|
|
68
|
+
await Promise.all(hooks[hookName].map((callback) => callback.apply(this, args)));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Call the original method
|
|
72
|
+
return originalMethod.apply(this, args);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return descriptor;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Decorator function that executes registered hooks asynchronously before the decorated method
|
|
81
|
+
* @param hookName The name of the hook to trigger
|
|
82
|
+
* @param contextFn Optional function to extract additional context from the class instance
|
|
83
|
+
*/
|
|
84
|
+
export function hookAsyncWithContext(hookName: string, contextFn?: (instance: any) => Record<string, any>) {
|
|
85
|
+
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
86
|
+
const originalMethod = descriptor.value;
|
|
87
|
+
|
|
88
|
+
descriptor.value = async function (...args: any[]) {
|
|
89
|
+
// Execute all registered hooks for this hook name
|
|
90
|
+
if (hooks[hookName]) {
|
|
91
|
+
// Get additional context if contextFn is provided
|
|
92
|
+
const additionalContext = typeof contextFn === 'function' ? await contextFn(this) : {};
|
|
93
|
+
|
|
94
|
+
// Wait for all hooks to complete before proceeding
|
|
95
|
+
// We need to prepend the additional context before the args; otherwise, optional parameters may cause incorrect argument mapping.
|
|
96
|
+
await Promise.all(hooks[hookName].map((callback) => callback.apply(this, [additionalContext, ...args])));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Call the original method
|
|
100
|
+
return originalMethod.apply(this, args);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return descriptor;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { boot } from './boot';
|
|
2
|
+
|
|
3
|
+
import { SREConfig, TConnectorService } from '@sre/types/SRE.types';
|
|
4
|
+
import { ConnectorService } from './ConnectorsService';
|
|
5
|
+
import { SystemEvents } from './SystemEvents';
|
|
6
|
+
import { Logger } from '../helpers/Log.helper';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { dirname } from 'path';
|
|
12
|
+
|
|
13
|
+
const logger = Logger('SRE');
|
|
14
|
+
|
|
15
|
+
export class SmythRuntime {
|
|
16
|
+
public started = false;
|
|
17
|
+
|
|
18
|
+
private _smythDir: string;
|
|
19
|
+
public get smythDir() {
|
|
20
|
+
return this._smythDir;
|
|
21
|
+
}
|
|
22
|
+
private _readyPromise: Promise<boolean>;
|
|
23
|
+
private _readyResolve: (value: boolean) => void;
|
|
24
|
+
|
|
25
|
+
private defaultConfig: SREConfig = {
|
|
26
|
+
Vault: {
|
|
27
|
+
Connector: 'JSONFileVault',
|
|
28
|
+
},
|
|
29
|
+
Account: {
|
|
30
|
+
Connector: 'DummyAccount',
|
|
31
|
+
},
|
|
32
|
+
Cache: {
|
|
33
|
+
Connector: 'RAM',
|
|
34
|
+
},
|
|
35
|
+
Storage: {
|
|
36
|
+
Connector: 'LocalStorage',
|
|
37
|
+
},
|
|
38
|
+
Code: {
|
|
39
|
+
Connector: 'DummyConnector',
|
|
40
|
+
},
|
|
41
|
+
//NKV should be loaded before VectorDB
|
|
42
|
+
NKV: {
|
|
43
|
+
Connector: 'RAM',
|
|
44
|
+
},
|
|
45
|
+
VectorDB: {
|
|
46
|
+
Connector: 'RAMVec',
|
|
47
|
+
},
|
|
48
|
+
ModelsProvider: {
|
|
49
|
+
Connector: 'SmythModelsProvider',
|
|
50
|
+
},
|
|
51
|
+
AgentData: {
|
|
52
|
+
Connector: 'NullAgentData',
|
|
53
|
+
},
|
|
54
|
+
Component: {
|
|
55
|
+
Connector: 'LocalComponent',
|
|
56
|
+
},
|
|
57
|
+
ManagedVault: {
|
|
58
|
+
Connector: 'NullManagedVault',
|
|
59
|
+
},
|
|
60
|
+
Log: {
|
|
61
|
+
Connector: 'ConsoleLog',
|
|
62
|
+
},
|
|
63
|
+
Router: {
|
|
64
|
+
Connector: 'NullRouter',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
protected constructor() {
|
|
69
|
+
this.started = true;
|
|
70
|
+
this._readyPromise = new Promise((resolve) => {
|
|
71
|
+
this._readyResolve = resolve;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
protected static instance?: SmythRuntime;
|
|
76
|
+
public static get Instance(): SmythRuntime {
|
|
77
|
+
if (!SmythRuntime.instance) {
|
|
78
|
+
SmythRuntime.instance = new SmythRuntime();
|
|
79
|
+
}
|
|
80
|
+
return SmythRuntime.instance;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private _initializing = false;
|
|
84
|
+
|
|
85
|
+
public get initializing() {
|
|
86
|
+
return this._initializing;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private _initialized = false;
|
|
90
|
+
|
|
91
|
+
public init(_config?: SREConfig): SmythRuntime {
|
|
92
|
+
if (!_config || JSON.stringify(_config) === '{}') {
|
|
93
|
+
this._smythDir = findSmythDir();
|
|
94
|
+
logger.info('.smyth directory found in:', this._smythDir);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (this._initializing) {
|
|
98
|
+
console.warn('You tried to initialize SRE while it is already initializing ... skipping');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (this._initialized) {
|
|
102
|
+
throw new Error('SRE already initialized');
|
|
103
|
+
}
|
|
104
|
+
this._initializing = true;
|
|
105
|
+
SystemEvents.on('SRE:Booted', () => {
|
|
106
|
+
this._readyResolve(true);
|
|
107
|
+
});
|
|
108
|
+
boot();
|
|
109
|
+
|
|
110
|
+
const config = this.autoConf(_config);
|
|
111
|
+
|
|
112
|
+
for (let connectorType in config) {
|
|
113
|
+
for (let configEntry of config[connectorType]) {
|
|
114
|
+
ConnectorService.init(
|
|
115
|
+
connectorType as TConnectorService,
|
|
116
|
+
configEntry.Connector,
|
|
117
|
+
configEntry.Id,
|
|
118
|
+
configEntry.Settings,
|
|
119
|
+
configEntry.Default
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this._initialized = true;
|
|
125
|
+
SystemEvents.emit('SRE:Initialized');
|
|
126
|
+
|
|
127
|
+
return SmythRuntime.Instance as SmythRuntime;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* This function tries to auto configure, or fixes the provided configuration
|
|
132
|
+
*
|
|
133
|
+
* FIXME: The current version does not actually auto configure SRE, it just fixes the provided configuration for now
|
|
134
|
+
* TODO: Implement auto configuration based on present environment variables and auto-detected configs
|
|
135
|
+
* @param config
|
|
136
|
+
*/
|
|
137
|
+
private autoConf(config: SREConfig = {}) {
|
|
138
|
+
// default config for missing connectors
|
|
139
|
+
const defaultConfig = JSON.parse(JSON.stringify(this.defaultConfig));
|
|
140
|
+
|
|
141
|
+
// for (let connectorType in defaultConfig) {
|
|
142
|
+
// if (!config[connectorType]) {
|
|
143
|
+
// config[connectorType] = defaultConfig[connectorType];
|
|
144
|
+
// }
|
|
145
|
+
// }
|
|
146
|
+
|
|
147
|
+
const keys = Object.keys({ ...defaultConfig, ...config });
|
|
148
|
+
|
|
149
|
+
const newConfig: SREConfig = {};
|
|
150
|
+
for (let connectorType of keys) {
|
|
151
|
+
newConfig[connectorType] = [];
|
|
152
|
+
|
|
153
|
+
let entry = config[connectorType] || defaultConfig[connectorType];
|
|
154
|
+
if (!Array.isArray(entry)) {
|
|
155
|
+
entry = [entry];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let hasDefault = false;
|
|
159
|
+
for (let connector of entry) {
|
|
160
|
+
if (!connector.Connector) {
|
|
161
|
+
logger.warn(`Missing Connector Name in ${connectorType} entry ... it will be ignored`);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (connector.Default) {
|
|
165
|
+
if (hasDefault) {
|
|
166
|
+
logger.warn(`Entry ${connectorType} has more than one default Connector ... only the first one will be used`);
|
|
167
|
+
}
|
|
168
|
+
hasDefault = true;
|
|
169
|
+
}
|
|
170
|
+
newConfig[connectorType].push(connector);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!hasDefault && newConfig[connectorType].length > 0) {
|
|
174
|
+
newConfig[connectorType][0].Default = true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return newConfig;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public ready(): Promise<boolean> {
|
|
182
|
+
return this._readyPromise;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private _stopping = false;
|
|
186
|
+
public async _stop() {
|
|
187
|
+
if (this._stopping) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
this._stopping = true;
|
|
191
|
+
logger.info('Sending Shutdown Signals To All Subsystems...');
|
|
192
|
+
await ConnectorService._stop();
|
|
193
|
+
SmythRuntime.instance = undefined;
|
|
194
|
+
this.started = false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export const SRE = SmythRuntime.Instance;
|
|
199
|
+
let shuttingDown = false;
|
|
200
|
+
|
|
201
|
+
function findSmythDir() {
|
|
202
|
+
// 1. Try to find in local directory (the directory from which the program was run)
|
|
203
|
+
const localDir = path.resolve(process.cwd(), '.smyth');
|
|
204
|
+
if (fs.existsSync(localDir)) {
|
|
205
|
+
return localDir;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 2. Try to find from main script's directory (entry point)
|
|
209
|
+
const mainScriptPath = process.argv[1];
|
|
210
|
+
const mainScriptDir = path.dirname(path.resolve(mainScriptPath));
|
|
211
|
+
if (mainScriptPath) {
|
|
212
|
+
const mainScriptSmythDir = path.resolve(mainScriptDir, '.smyth');
|
|
213
|
+
if (fs.existsSync(mainScriptSmythDir)) {
|
|
214
|
+
return mainScriptSmythDir;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 3. Try to find it in current package root directory (where package.json is)
|
|
219
|
+
let packageRootDir = findPackageRoot();
|
|
220
|
+
if (packageRootDir) {
|
|
221
|
+
const packageSmythDir = path.resolve(packageRootDir, '.smyth');
|
|
222
|
+
if (fs.existsSync(packageSmythDir)) {
|
|
223
|
+
return packageSmythDir;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 4. Try to find it in current package root directory from main script's directory
|
|
228
|
+
packageRootDir = findPackageRoot(mainScriptDir);
|
|
229
|
+
if (packageRootDir) {
|
|
230
|
+
const packageSmythDir = path.resolve(packageRootDir, '.smyth');
|
|
231
|
+
if (fs.existsSync(packageSmythDir)) {
|
|
232
|
+
return packageSmythDir;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 5. Try to find it in user home directory
|
|
237
|
+
const homeDir = path.resolve(os.homedir(), '.smyth');
|
|
238
|
+
if (fs.existsSync(homeDir)) {
|
|
239
|
+
return homeDir;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Default: return path in current working directory (will be created if needed)
|
|
243
|
+
return localDir;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function findPackageRoot(startDir = process.cwd()) {
|
|
247
|
+
let currentDir = startDir;
|
|
248
|
+
|
|
249
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
250
|
+
const packageJsonPath = path.resolve(currentDir, 'package.json');
|
|
251
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
252
|
+
return currentDir;
|
|
253
|
+
}
|
|
254
|
+
currentDir = path.dirname(currentDir);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function shutdown(reason) {
|
|
261
|
+
if (!SmythRuntime.Instance.started) return;
|
|
262
|
+
if (shuttingDown) return;
|
|
263
|
+
shuttingDown = true;
|
|
264
|
+
|
|
265
|
+
logger.info(`Caught ${reason} ... Attempting graceful shutdown`);
|
|
266
|
+
if (SmythRuntime.Instance) {
|
|
267
|
+
try {
|
|
268
|
+
await SmythRuntime.Instance._stop();
|
|
269
|
+
} catch (err) {
|
|
270
|
+
logger.error('Shutdown error:', err);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
['SIGINT', 'SIGTERM'].forEach((signal) => {
|
|
276
|
+
process.on(signal, async () => {
|
|
277
|
+
await shutdown(signal);
|
|
278
|
+
process.exit(0); // Required after async
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
process.on('beforeExit', (code) => {
|
|
283
|
+
shutdown('beforeExit');
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
process.on('exit', (code) => {
|
|
287
|
+
logger.info(`Goodbye!`);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// process.on('uncaughtException', (err) => {
|
|
291
|
+
|
|
292
|
+
// });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SmythLLMUsage, SmythTaskUsage } from '@sre/types/LLM.types';
|
|
2
|
+
import { TServiceRegistry } from '@sre/types/SRE.types';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
|
|
5
|
+
export type SystemEventMap = {
|
|
6
|
+
'SRE:Booted': [TServiceRegistry];
|
|
7
|
+
'SRE:Initialized': [];
|
|
8
|
+
'USAGE:LLM': [SmythLLMUsage];
|
|
9
|
+
'USAGE:API': any;
|
|
10
|
+
'USAGE:TASK': [SmythTaskUsage];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const SystemEvents = new EventEmitter<SystemEventMap>();
|
|
14
|
+
|
|
15
|
+
export { SystemEvents };
|