@smythos/sre 1.7.18 → 1.7.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +120 -82
- package/dist/index.js.map +1 -1
- package/dist/types/Components/DataSourceIndexer.class.d.ts +4 -12
- package/dist/types/Components/GenAILLM.class.d.ts +5 -5
- package/dist/types/Components/RAG/DataSourceCleaner.class.d.ts +37 -0
- package/dist/types/Components/RAG/DataSourceComponent.class.d.ts +30 -0
- package/dist/types/Components/RAG/DataSourceIndexer.class.d.ts +14 -0
- package/dist/types/Components/RAG/DataSourceLookup.class.d.ts +36 -0
- package/dist/types/Components/index.d.ts +3 -3
- package/dist/types/helpers/Conversation.helper.d.ts +3 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.d.ts +1 -0
- package/dist/types/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.d.ts +11 -4
- package/dist/types/subsystems/IO/VectorDB.service/embed/index.d.ts +5 -0
- package/dist/types/subsystems/LLMManager/LLM.inference.d.ts +10 -3
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +4 -2
- package/dist/types/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.d.ts +35 -0
- package/dist/types/subsystems/Security/Account.service/AccountConnector.d.ts +2 -2
- package/dist/types/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.d.ts +10 -0
- package/dist/types/subsystems/Security/Vault.service/connectors/SecretsManager.class.d.ts +6 -2
- package/dist/types/types/LLM.types.d.ts +2 -0
- package/dist/types/types/VectorDB.types.d.ts +4 -0
- package/dist/types/utils/array.utils.d.ts +4 -0
- package/dist/types/utils/string.utils.d.ts +1 -0
- package/package.json +3 -3
- package/src/Components/APIEndpoint.class.ts +1 -6
- package/src/Components/Component.class.ts +14 -1
- package/src/Components/DataSourceIndexer.class.ts +148 -34
- package/src/Components/GenAILLM.class.ts +21 -11
- package/src/Components/RAG/DataSourceCleaner.class.ts +178 -0
- package/src/Components/RAG/DataSourceComponent.class.ts +111 -0
- package/src/Components/RAG/DataSourceIndexer.class.ts +254 -0
- package/src/Components/{DataSourceLookup.class.ts → RAG/DataSourceLookup.class.ts} +92 -3
- package/src/Components/ServerlessCode.class.ts +1 -4
- package/src/Components/index.ts +3 -3
- package/src/helpers/AWSLambdaCode.helper.ts +40 -45
- package/src/helpers/Conversation.helper.ts +14 -10
- package/src/helpers/S3Cache.helper.ts +2 -1
- package/src/index.ts +212 -212
- package/src/index.ts.bak +212 -212
- package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +3 -1
- package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +145 -19
- package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +56 -22
- package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +1 -0
- package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +2 -1
- package/src/subsystems/IO/VectorDB.service/embed/index.ts +18 -0
- package/src/subsystems/LLMManager/LLM.inference.ts +63 -47
- package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +35 -10
- package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +12 -4
- package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +4 -4
- package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +105 -23
- package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +17 -5
- package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +18 -3
- package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +14 -5
- package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +6 -4
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +5 -5
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +8 -3
- package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +9 -8
- package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +126 -28
- package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.ts +38 -6
- package/src/subsystems/Security/Account.service/AccountConnector.ts +3 -3
- package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +111 -48
- package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +41 -66
- package/src/types/LLM.types.ts +5 -0
- package/src/types/VectorDB.types.ts +4 -0
- package/src/utils/array.utils.ts +11 -0
- package/src/utils/base64.utils.ts +1 -1
- package/src/utils/string.utils.ts +3 -192
- package/src/Components/DataSourceCleaner.class.ts +0 -92
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
2
|
+
import { DataSourceComponent } from './DataSourceComponent.class';
|
|
3
|
+
import Joi from 'joi';
|
|
4
|
+
import { validateCharacterSet } from '@sre/utils/validation.utils';
|
|
5
|
+
import { TemplateString } from '@sre/helpers/TemplateString.helper';
|
|
6
|
+
import { isUrl, detectURLSourceType } from '../../utils';
|
|
7
|
+
import { SmythFS } from '@sre/IO/Storage.service/SmythFS.class';
|
|
8
|
+
import { ConnectorService } from '@sre/Core/ConnectorsService';
|
|
9
|
+
|
|
10
|
+
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
|
|
11
|
+
import { TEmbeddings } from '@sre/IO/VectorDB.service/embed/BaseEmbedding';
|
|
12
|
+
import { VectorDBConnector } from '@sre/IO/VectorDB.service/VectorDBConnector';
|
|
13
|
+
import { JSONContentHelper } from '@sre/helpers/JsonContent.helper';
|
|
14
|
+
|
|
15
|
+
export class DataSourceIndexer extends DataSourceComponent {
|
|
16
|
+
private MAX_ALLOWED_URLS_PER_INPUT = 20;
|
|
17
|
+
protected configSchema = Joi.object({
|
|
18
|
+
namespace: Joi.string().max(50).allow(''),
|
|
19
|
+
id: Joi.string().custom(validateCharacterSet, 'id custom validation').allow('').label('source identifier'),
|
|
20
|
+
name: Joi.string().max(50).allow('').label('label'),
|
|
21
|
+
metadata: Joi.string().allow(null).allow('').max(10000).label('metadata'),
|
|
22
|
+
chunkSize: Joi.number().optional(),
|
|
23
|
+
chunkOverlap: Joi.number().optional(),
|
|
24
|
+
version: Joi.string().valid('v1', 'v2').default('v1'),
|
|
25
|
+
});
|
|
26
|
+
constructor() {
|
|
27
|
+
super();
|
|
28
|
+
}
|
|
29
|
+
init() {}
|
|
30
|
+
async process(input, config, agent: Agent) {
|
|
31
|
+
await super.process(input, config, agent);
|
|
32
|
+
|
|
33
|
+
let response: any = null;
|
|
34
|
+
if (!config.data.version || config.data.version === 'v1') {
|
|
35
|
+
response = await this.processV1(input, config, agent);
|
|
36
|
+
} else if (config.data.version === 'v2') {
|
|
37
|
+
response = await this.processV2(input, config, agent);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return response;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private async processV1(input, config, agent: Agent) {
|
|
44
|
+
const teamId = agent.teamId;
|
|
45
|
+
const agentId = agent.id;
|
|
46
|
+
let debugOutput = agent.agentRuntime?.debug ? '== Source Indexer Log ==\n' : null;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const _config = {
|
|
50
|
+
...config.data,
|
|
51
|
+
name: TemplateString(config.data.name).parse(input).result,
|
|
52
|
+
id: TemplateString(config.data.id).parse(input).result,
|
|
53
|
+
metadata: TemplateString(config.data.metadata).parse(input).result,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const outputs = {};
|
|
57
|
+
for (let con of config.outputs) {
|
|
58
|
+
if (con.default) continue;
|
|
59
|
+
outputs[con.name] = con?.description ? `<${con?.description}>` : '';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const namespaceId = _config.namespace.split('_').slice(1).join('_') || _config.namespace;
|
|
63
|
+
debugOutput += `[Selected namespace id] \n${namespaceId}\n\n`;
|
|
64
|
+
|
|
65
|
+
const vectorDbConnector =
|
|
66
|
+
// (await vectorDBHelper.getTeamConnector(teamId)) ||
|
|
67
|
+
ConnectorService.getVectorDBConnector();
|
|
68
|
+
const nsExists = await vectorDbConnector.requester(AccessCandidate.team(teamId)).namespaceExists(namespaceId);
|
|
69
|
+
|
|
70
|
+
if (!nsExists) {
|
|
71
|
+
const newNs = await vectorDbConnector.requester(AccessCandidate.team(teamId)).createNamespace(namespaceId);
|
|
72
|
+
debugOutput += `[Created namespace] \n${newNs}\n\n`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const inputSchema = this.validateInput(input);
|
|
76
|
+
if (inputSchema.error) {
|
|
77
|
+
throw new Error(`Input validation error: ${inputSchema.error}\n EXITING...`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const providedId = _config.id;
|
|
81
|
+
// const isAutoId = _config.isAutoId;
|
|
82
|
+
const idRegex = /^[a-zA-Z0-9\-\_\.]+$/;
|
|
83
|
+
|
|
84
|
+
if (!providedId) {
|
|
85
|
+
// Assign a new ID if it's set to auto-generate or not provided
|
|
86
|
+
// _config.id = crypto.randomBytes(16).toString('hex');
|
|
87
|
+
throw new Error(`Id is required`);
|
|
88
|
+
} else if (!idRegex.test(providedId)) {
|
|
89
|
+
// Validate the provided ID if it's not auto-generated
|
|
90
|
+
throw new Error(`Invalid id. Accepted characters: 'a-z', 'A-Z', '0-9', '-', '_', '.'`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let indexRes: any = null;
|
|
94
|
+
let parsedUrlArray: string[] | null = null;
|
|
95
|
+
const dsId = DataSourceIndexer.normalizeDsId(providedId, teamId, namespaceId);
|
|
96
|
+
|
|
97
|
+
if (isUrl(inputSchema.value.Source)) {
|
|
98
|
+
debugOutput += `STEP: Parsing input as url\n\n`;
|
|
99
|
+
throw new Error('URLs are not supported yet');
|
|
100
|
+
} else {
|
|
101
|
+
debugOutput += `STEP: Parsing input as text\n\n`;
|
|
102
|
+
indexRes = await this.addDSFromText({
|
|
103
|
+
teamId,
|
|
104
|
+
namespaceId: namespaceId,
|
|
105
|
+
text: inputSchema.value.Source,
|
|
106
|
+
name: _config.name || 'Untitled',
|
|
107
|
+
metadata: _config.metadata || null,
|
|
108
|
+
sourceId: dsId,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
debugOutput += `Created datasource successfully\n\n`;
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
_debug: debugOutput,
|
|
116
|
+
Success: {
|
|
117
|
+
result: indexRes?.data?.dataSource || true,
|
|
118
|
+
id: _config.id,
|
|
119
|
+
},
|
|
120
|
+
// _error,
|
|
121
|
+
};
|
|
122
|
+
} catch (err: any) {
|
|
123
|
+
debugOutput += `Error: ${err?.message || "Couldn't index data source"}\n\n`;
|
|
124
|
+
return {
|
|
125
|
+
_debug: debugOutput,
|
|
126
|
+
_error: err?.message || "Couldn't index data source",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private async processV2(input, config, agent: Agent) {
|
|
132
|
+
const teamId = agent.teamId;
|
|
133
|
+
const agentId = agent.id;
|
|
134
|
+
let debugOutput = agent.agentRuntime?.debug ? '== Source Indexer Log ==\n' : null;
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const _config = {
|
|
138
|
+
...config.data,
|
|
139
|
+
name: TemplateString(config.data.name).parse(input).result,
|
|
140
|
+
id: TemplateString(config.data.id).parse(input).result,
|
|
141
|
+
metadata: TemplateString(config.data.metadata).parse(input).result,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const outputs = {};
|
|
145
|
+
for (let con of config.outputs) {
|
|
146
|
+
if (con.default) continue;
|
|
147
|
+
outputs[con.name] = con?.description ? `<${con?.description}>` : '';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// we try to get the namespace without the prefix teamId, if not exist, we use the full namespace id
|
|
151
|
+
// const namespaceLabel = _config.namespace.split('_').slice(1).join('_') || _config.namespace;
|
|
152
|
+
const namespaceLabel = /^c[a-z0-9]{24}.+$/.test(_config.namespace) ? _config.namespace.split('_').slice(1).join('_') : _config.namespace;
|
|
153
|
+
const namespaceId = _config.namespace;
|
|
154
|
+
debugOutput += `[Selected namespace] \n${namespaceLabel}\n\n`;
|
|
155
|
+
|
|
156
|
+
let vecDbConnector: VectorDBConnector = null;
|
|
157
|
+
try {
|
|
158
|
+
vecDbConnector = await this.resolveVectorDbConnector(namespaceId, teamId);
|
|
159
|
+
} catch (err: any) {
|
|
160
|
+
debugOutput += `Error: ${err?.message || "Couldn't get vector database connector"}\n\n`;
|
|
161
|
+
return {
|
|
162
|
+
_debug: debugOutput,
|
|
163
|
+
_error: err?.message || "Couldn't get vector database connector",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const vecDbClient = vecDbConnector.requester(AccessCandidate.team(teamId));
|
|
167
|
+
|
|
168
|
+
const inputSchema = this.validateInput(input);
|
|
169
|
+
if (inputSchema.error) {
|
|
170
|
+
throw new Error(`Input validation error: ${inputSchema.error}\n EXITING...`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const providedId = _config.id;
|
|
174
|
+
// const isAutoId = _config.isAutoId;
|
|
175
|
+
const idRegex = /^[a-zA-Z0-9\-\_\.]+$/;
|
|
176
|
+
|
|
177
|
+
if (!providedId) {
|
|
178
|
+
// Assign a new ID if it's set to auto-generate or not provided
|
|
179
|
+
// _config.id = crypto.randomBytes(16).toString('hex');
|
|
180
|
+
throw new Error(`Id is required`);
|
|
181
|
+
} else if (!idRegex.test(providedId)) {
|
|
182
|
+
// Validate the provided ID if it's not auto-generated
|
|
183
|
+
throw new Error(`Invalid id. Accepted characters: 'a-z', 'A-Z', '0-9', '-', '_', '.'`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const dsId = DataSourceIndexer.normalizeDsId(providedId, teamId, namespaceLabel);
|
|
187
|
+
|
|
188
|
+
// check if the datasource already exists
|
|
189
|
+
const dsExists = await vecDbClient.getDatasource(namespaceLabel, dsId);
|
|
190
|
+
if (dsExists) {
|
|
191
|
+
debugOutput += `Datasource already exists\n\n`;
|
|
192
|
+
return {
|
|
193
|
+
_debug: debugOutput,
|
|
194
|
+
_error: `Datasource already exists`,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
debugOutput += `STEP: Parsing input as text\n\n`;
|
|
199
|
+
|
|
200
|
+
const response = await vecDbClient.createDatasource(namespaceLabel, {
|
|
201
|
+
text: inputSchema.value.Source,
|
|
202
|
+
metadata: JSONContentHelper.create(_config.metadata).tryParse() || null,
|
|
203
|
+
id: dsId,
|
|
204
|
+
label: _config.name || 'Untitled',
|
|
205
|
+
chunkSize: _config.chunkSize ? parseInt(_config.chunkSize) : undefined,
|
|
206
|
+
chunkOverlap: _config.chunkOverlap ? parseInt(_config.chunkOverlap) : undefined,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
debugOutput += `Created datasource successfully\n\n`;
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
_debug: debugOutput,
|
|
213
|
+
Success: {
|
|
214
|
+
result: response || true,
|
|
215
|
+
id: _config.id,
|
|
216
|
+
},
|
|
217
|
+
// _error,
|
|
218
|
+
};
|
|
219
|
+
} catch (err: any) {
|
|
220
|
+
debugOutput += `Error: ${err?.message || "Couldn't index data source"}\n\n`;
|
|
221
|
+
return {
|
|
222
|
+
_debug: debugOutput,
|
|
223
|
+
_error: err?.message || "Couldn't index data source",
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
validateInput(input: any) {
|
|
229
|
+
return Joi.object({
|
|
230
|
+
Source: Joi.any().required(),
|
|
231
|
+
})
|
|
232
|
+
.unknown(true)
|
|
233
|
+
.validate(input);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private async addDSFromText({ teamId, sourceId, namespaceId, text, name, metadata }) {
|
|
237
|
+
let vectorDbConnector = ConnectorService.getVectorDBConnector();
|
|
238
|
+
// const isOnCustomStorage = await vectorDBHelper.isNamespaceOnCustomStorage(teamId, namespaceId);
|
|
239
|
+
// if (isOnCustomStorage) {
|
|
240
|
+
// const customTeamConnector = await vectorDBHelper.getTeamConnector(teamId);
|
|
241
|
+
// if (customTeamConnector) {
|
|
242
|
+
// vectorDbConnector = customTeamConnector;
|
|
243
|
+
// }
|
|
244
|
+
// }
|
|
245
|
+
const id = await vectorDbConnector.requester(AccessCandidate.team(teamId)).createDatasource(namespaceId, {
|
|
246
|
+
text,
|
|
247
|
+
metadata,
|
|
248
|
+
id: sourceId,
|
|
249
|
+
label: name,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
return id;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import Joi from 'joi';
|
|
2
|
-
import { validateInteger } from '
|
|
2
|
+
import { validateInteger } from '../../utils';
|
|
3
3
|
import { jsonrepair } from 'jsonrepair';
|
|
4
4
|
import { TemplateString } from '@sre/helpers/TemplateString.helper';
|
|
5
5
|
import { JSONContent } from '@sre/helpers/JsonContent.helper';
|
|
6
6
|
import { ConnectorService } from '@sre/Core/ConnectorsService';
|
|
7
7
|
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
|
|
8
8
|
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
9
|
-
import {
|
|
9
|
+
import { DataSourceComponent } from './DataSourceComponent.class';
|
|
10
10
|
|
|
11
11
|
// Note: LLMHelper renamed to LLMInference
|
|
12
12
|
class LLMInference {
|
|
@@ -15,7 +15,7 @@ class LLMInference {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export class DataSourceLookup extends
|
|
18
|
+
export class DataSourceLookup extends DataSourceComponent {
|
|
19
19
|
protected configSchema = Joi.object({
|
|
20
20
|
topK: Joi.alternatives([Joi.string(), Joi.number()]) // Value is now a number; keep string fallback for backward compatibility.
|
|
21
21
|
|
|
@@ -31,13 +31,22 @@ export class DataSourceLookup extends Component {
|
|
|
31
31
|
}),
|
|
32
32
|
scoreThreshold: Joi.number().optional().label('Score Threshold'),
|
|
33
33
|
includeScore: Joi.boolean().optional().label('Include Score'),
|
|
34
|
+
version: Joi.string().valid('v1', 'v2').default('v1'),
|
|
34
35
|
});
|
|
35
36
|
constructor() {
|
|
36
37
|
super();
|
|
37
38
|
}
|
|
38
39
|
init() {}
|
|
40
|
+
|
|
39
41
|
async process(input, config, agent: Agent) {
|
|
40
42
|
await super.process(input, config, agent);
|
|
43
|
+
if (!config.data.version || config.data.version === 'v1') {
|
|
44
|
+
return await this.processV1(input, config, agent);
|
|
45
|
+
} else if (config.data.version === 'v2') {
|
|
46
|
+
return await this.processV2(input, config, agent);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async processV1(input, config, agent: Agent) {
|
|
41
50
|
const componentId = config.id;
|
|
42
51
|
const component = agent.components[componentId];
|
|
43
52
|
const teamId = agent.teamId;
|
|
@@ -139,6 +148,86 @@ export class DataSourceLookup extends Component {
|
|
|
139
148
|
};
|
|
140
149
|
}
|
|
141
150
|
|
|
151
|
+
async processV2(input, config, agent: Agent) {
|
|
152
|
+
const teamId = agent.teamId;
|
|
153
|
+
let debugOutput = agent.agentRuntime?.debug ? '== Data Source Lookup Log ==\n' : null;
|
|
154
|
+
|
|
155
|
+
const outputs = {};
|
|
156
|
+
for (let con of config.outputs) {
|
|
157
|
+
if (con.default) continue;
|
|
158
|
+
outputs[con.name] = '';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const namespaceLabel = /^c[a-z0-9]{24}.+$/.test(config.data.namespace)
|
|
162
|
+
? config.data.namespace.split('_').slice(1).join('_')
|
|
163
|
+
: config.data.namespace;
|
|
164
|
+
const namespaceId = config.data.namespace;
|
|
165
|
+
const model = config.data?.model || 'gpt-4o-mini';
|
|
166
|
+
const includeMetadata = config.data?.includeMetadata || false;
|
|
167
|
+
|
|
168
|
+
const scoreThreshold = config.data?.scoreThreshold || 0.001; // Use low score (0.001) to return most results for backward compatibility
|
|
169
|
+
const includeScore = config.data?.includeScore || false;
|
|
170
|
+
|
|
171
|
+
const _input = typeof input.Query === 'string' ? input.Query : JSON.stringify(input.Query);
|
|
172
|
+
|
|
173
|
+
const topK = Math.max(config.data?.topK || 50, 50);
|
|
174
|
+
|
|
175
|
+
// let vectorDbConnector = ConnectorService.getVectorDBConnector();
|
|
176
|
+
// let existingNs = await vectorDbConnector.requester(AccessCandidate.team(teamId)).namespaceExists(namespaceLabel);
|
|
177
|
+
|
|
178
|
+
const vecDbConnector = await this.resolveVectorDbConnector(namespaceId, teamId);
|
|
179
|
+
|
|
180
|
+
let results: string[] | { content: string; metadata: any; score?: number }[];
|
|
181
|
+
let _error;
|
|
182
|
+
try {
|
|
183
|
+
const response = await vecDbConnector
|
|
184
|
+
.requester(AccessCandidate.team(teamId))
|
|
185
|
+
.search(namespaceLabel, _input, { topK, includeMetadata: true });
|
|
186
|
+
|
|
187
|
+
results = response.slice(0, config.data.topK).map((result) => ({
|
|
188
|
+
content: result.text,
|
|
189
|
+
metadata: result.metadata,
|
|
190
|
+
score: result.score, // use a very low score to return
|
|
191
|
+
}));
|
|
192
|
+
|
|
193
|
+
results = results.filter((result) => result.score >= scoreThreshold);
|
|
194
|
+
|
|
195
|
+
// Transform results based on inclusion flags
|
|
196
|
+
results = results.map((result) => {
|
|
197
|
+
const transformedResult: any = {
|
|
198
|
+
content: result.content,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
if (includeMetadata) {
|
|
202
|
+
// legacy user-specific metadata key [result.metadata?.metadata]
|
|
203
|
+
transformedResult.metadata = this.parseMetadata(result.metadata || result.metadata?.metadata);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (includeScore) {
|
|
207
|
+
transformedResult.score = result.score;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// If neither metadata nor score is included, return just the content string
|
|
211
|
+
return includeMetadata || includeScore ? transformedResult : result.content;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
debugOutput += `[Results] \nLoaded ${results.length} results from namespace: ${namespaceLabel}\n\n`;
|
|
215
|
+
} catch (error) {
|
|
216
|
+
debugOutput += `Error: ${error instanceof Error ? error.message : error.toString()}\n\n`;
|
|
217
|
+
_error = error instanceof Error ? error.message : error.toString();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const totalLength = JSON.stringify(results).length;
|
|
221
|
+
debugOutput += `[Total Length] \n${totalLength}\n\n`;
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
Results: results,
|
|
225
|
+
_error,
|
|
226
|
+
_debug: debugOutput,
|
|
227
|
+
//_debug: `Query: ${_input}. \nTotal Length = ${totalLength} \nResults: ${JSON.stringify(results)}`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
142
231
|
// private async checkIfTeamOwnsNamespace(teamId: string, namespaceId: string, token: string) {
|
|
143
232
|
// try {
|
|
144
233
|
// const res = await SmythAPIHelper.fromAuth({ token }).mwSysAPI.get(`/vectors/namespaces/${namespaceId}`);
|
|
@@ -41,10 +41,7 @@ export class ServerlessCode extends Component {
|
|
|
41
41
|
let codeInputs = {};
|
|
42
42
|
|
|
43
43
|
for (let field of componentInputs) {
|
|
44
|
-
|
|
45
|
-
// This correctly resolves cases where input values reference agent variables with the same name.
|
|
46
|
-
// Example: agent variables { user_id: "123" }, input { user_id: "{{user_id}}" }.
|
|
47
|
-
const inputValue = TemplateString(input[field.name]).parse(input).parse(agent.agentVariables).result;
|
|
44
|
+
const inputValue = TemplateString(input[field.name]).parse(input).result;
|
|
48
45
|
|
|
49
46
|
const _type = typeof inputValue;
|
|
50
47
|
|
package/src/Components/index.ts
CHANGED
|
@@ -8,9 +8,9 @@ import { FSleep } from './FSleep.class';
|
|
|
8
8
|
import { FHash } from './FHash.class';
|
|
9
9
|
import { FEncDec } from './FEncDec.class';
|
|
10
10
|
import { FTimestamp } from './FTimestamp.class';
|
|
11
|
-
import { DataSourceLookup } from './DataSourceLookup.class';
|
|
12
|
-
import { DataSourceIndexer } from './DataSourceIndexer.class';
|
|
13
|
-
import { DataSourceCleaner } from './DataSourceCleaner.class';
|
|
11
|
+
import { DataSourceLookup } from './RAG/DataSourceLookup.class';
|
|
12
|
+
import { DataSourceIndexer } from './RAG/DataSourceIndexer.class';
|
|
13
|
+
import { DataSourceCleaner } from './RAG/DataSourceCleaner.class';
|
|
14
14
|
import { JSONFilter } from './JSONFilter.class';
|
|
15
15
|
import { LogicAND } from './LogicAND.class';
|
|
16
16
|
import { LogicOR } from './LogicOR.class';
|
|
@@ -134,13 +134,7 @@ export async function zipCode(directory: string) {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
export async function createOrUpdateLambdaFunction(functionName, zipFilePath, awsConfigs, envVariables: Record<string, string>) {
|
|
137
|
-
const client =
|
|
138
|
-
region: awsConfigs.region,
|
|
139
|
-
credentials: {
|
|
140
|
-
accessKeyId: awsConfigs.accessKeyId,
|
|
141
|
-
secretAccessKey: awsConfigs.secretAccessKey,
|
|
142
|
-
},
|
|
143
|
-
});
|
|
137
|
+
const client = getAWSLambdaClient(awsConfigs.region, awsConfigs.accessKeyId, awsConfigs.secretAccessKey)
|
|
144
138
|
const functionContent = fs.readFileSync(zipFilePath);
|
|
145
139
|
|
|
146
140
|
try {
|
|
@@ -168,26 +162,19 @@ export async function createOrUpdateLambdaFunction(functionName, zipFilePath, aw
|
|
|
168
162
|
let roleArn = '';
|
|
169
163
|
// check if the role exists
|
|
170
164
|
try {
|
|
171
|
-
const iamClient =
|
|
172
|
-
region: awsConfigs.region,
|
|
173
|
-
credentials: { accessKeyId: awsConfigs.accessKeyId, secretAccessKey: awsConfigs.secretAccessKey },
|
|
174
|
-
});
|
|
165
|
+
const iamClient = getAWSIAMClient(awsConfigs.region, awsConfigs.accessKeyId, awsConfigs.secretAccessKey);
|
|
175
166
|
const getRoleCommand = new GetRoleCommand({ RoleName: `smyth-${functionName}-role` });
|
|
176
167
|
const roleResponse: GetRoleCommandOutput = await iamClient.send(getRoleCommand);
|
|
177
168
|
roleArn = roleResponse.Role.Arn;
|
|
178
169
|
} catch (error) {
|
|
179
170
|
if (error.name === 'NoSuchEntityException') {
|
|
180
171
|
// create role
|
|
181
|
-
const iamClient =
|
|
182
|
-
region: awsConfigs.region,
|
|
183
|
-
credentials: { accessKeyId: awsConfigs.accessKeyId, secretAccessKey: awsConfigs.secretAccessKey },
|
|
184
|
-
});
|
|
172
|
+
const iamClient = getAWSIAMClient(awsConfigs.region, awsConfigs.accessKeyId, awsConfigs.secretAccessKey);
|
|
185
173
|
const createRoleCommand = new CreateRoleCommand({
|
|
186
174
|
RoleName: `smyth-${functionName}-role`,
|
|
187
175
|
AssumeRolePolicyDocument: getLambdaRolePolicy(),
|
|
188
176
|
});
|
|
189
177
|
const roleResponse: CreateRoleCommandOutput = await iamClient.send(createRoleCommand);
|
|
190
|
-
|
|
191
178
|
await waitForRoleDeploymentStatus(`smyth-${functionName}-role`, iamClient);
|
|
192
179
|
roleArn = roleResponse.Role.Arn;
|
|
193
180
|
} else {
|
|
@@ -231,7 +218,7 @@ function updateLambdaFunctionConfiguration(client: LambdaClient, functionName: s
|
|
|
231
218
|
|
|
232
219
|
async function createLambdaFunction(client: LambdaClient, functionParams: any, maxRetries: number = 5): Promise<void> {
|
|
233
220
|
let lastError: Error | null = null;
|
|
234
|
-
|
|
221
|
+
|
|
235
222
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
236
223
|
try {
|
|
237
224
|
const functionCreateCommand = new CreateFunctionCommand(functionParams);
|
|
@@ -241,7 +228,6 @@ async function createLambdaFunction(client: LambdaClient, functionParams: any, m
|
|
|
241
228
|
lastError = error;
|
|
242
229
|
// Check if this is a role trust policy error
|
|
243
230
|
if (error?.message?.includes('cannot be assumed by Lambda')) {
|
|
244
|
-
|
|
245
231
|
if (attempt < maxRetries) {
|
|
246
232
|
// Exponential backoff: 2^attempt seconds (2, 4, 8, 16, 32 seconds)
|
|
247
233
|
const waitTime = Math.pow(2, attempt) * 1000;
|
|
@@ -249,12 +235,11 @@ async function createLambdaFunction(client: LambdaClient, functionParams: any, m
|
|
|
249
235
|
continue;
|
|
250
236
|
}
|
|
251
237
|
}
|
|
252
|
-
|
|
253
238
|
// For other errors or if we've exhausted retries, throw immediately
|
|
254
239
|
throw error;
|
|
255
240
|
}
|
|
256
241
|
}
|
|
257
|
-
|
|
242
|
+
|
|
258
243
|
// If we get here, all retries failed
|
|
259
244
|
throw lastError || new Error('Lambda function creation failed after all retry attempts');
|
|
260
245
|
}
|
|
@@ -262,15 +247,15 @@ async function createLambdaFunction(client: LambdaClient, functionParams: any, m
|
|
|
262
247
|
export async function waitForRoleDeploymentStatus(roleName, client): Promise<boolean> {
|
|
263
248
|
return new Promise((resolve, reject) => {
|
|
264
249
|
const interval = setInterval(async () => {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
250
|
+
const getRoleCommand = new GetRoleCommand({ RoleName: roleName });
|
|
251
|
+
const roleResponse = await client.send(getRoleCommand);
|
|
252
|
+
|
|
253
|
+
// Check if role exists and has assume role policy document
|
|
254
|
+
if (roleResponse.Role && roleResponse.Role.AssumeRolePolicyDocument) {
|
|
255
|
+
clearInterval(interval);
|
|
256
|
+
setTimeout(() => resolve(true), 2000);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
274
259
|
}, 2000); // Check every 2 seconds
|
|
275
260
|
});
|
|
276
261
|
}
|
|
@@ -319,15 +304,7 @@ export async function invokeLambdaFunction(
|
|
|
319
304
|
awsCredentials: AWSCredentials & AWSRegionConfig
|
|
320
305
|
): Promise<any> {
|
|
321
306
|
try {
|
|
322
|
-
const client =
|
|
323
|
-
region: awsCredentials.region as string,
|
|
324
|
-
...(awsCredentials.accessKeyId && {
|
|
325
|
-
credentials: {
|
|
326
|
-
accessKeyId: awsCredentials.accessKeyId as string,
|
|
327
|
-
secretAccessKey: awsCredentials.secretAccessKey as string,
|
|
328
|
-
},
|
|
329
|
-
}),
|
|
330
|
-
});
|
|
307
|
+
const client = getAWSLambdaClient(awsCredentials.region, awsCredentials.accessKeyId, awsCredentials.secretAccessKey);
|
|
331
308
|
|
|
332
309
|
const invokeCommand = new InvokeCommand({
|
|
333
310
|
FunctionName: functionName,
|
|
@@ -347,13 +324,7 @@ export async function invokeLambdaFunction(
|
|
|
347
324
|
|
|
348
325
|
export async function getDeployedFunction(functionName: string, awsConfigs: AWSCredentials & AWSRegionConfig) {
|
|
349
326
|
try {
|
|
350
|
-
const client =
|
|
351
|
-
region: awsConfigs.region as string,
|
|
352
|
-
credentials: {
|
|
353
|
-
accessKeyId: awsConfigs.accessKeyId as string,
|
|
354
|
-
secretAccessKey: awsConfigs.secretAccessKey as string,
|
|
355
|
-
},
|
|
356
|
-
});
|
|
327
|
+
const client = getAWSLambdaClient(awsConfigs.region as string, awsConfigs.accessKeyId as string, awsConfigs.secretAccessKey as string);
|
|
357
328
|
const getFunctionCommand = new GetFunctionCommand({ FunctionName: functionName });
|
|
358
329
|
const lambdaResponse: GetFunctionCommandOutput = await client.send(getFunctionCommand);
|
|
359
330
|
return {
|
|
@@ -392,6 +363,30 @@ export async function getLambdaCredentials(agent: IAgent, config: any): Promise<
|
|
|
392
363
|
return awsCredentials;
|
|
393
364
|
}
|
|
394
365
|
|
|
366
|
+
function getAWSLambdaClient(region: string, accessKeyId?: string, secretAccessKey?: string) {
|
|
367
|
+
return new LambdaClient({
|
|
368
|
+
region,
|
|
369
|
+
...(accessKeyId && secretAccessKey && {
|
|
370
|
+
credentials: {
|
|
371
|
+
accessKeyId,
|
|
372
|
+
secretAccessKey,
|
|
373
|
+
},
|
|
374
|
+
}),
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function getAWSIAMClient(region: string, accessKeyId?: string, secretAccessKey?: string) {
|
|
379
|
+
return new IAMClient({
|
|
380
|
+
region,
|
|
381
|
+
...(accessKeyId && secretAccessKey && {
|
|
382
|
+
credentials: {
|
|
383
|
+
accessKeyId,
|
|
384
|
+
secretAccessKey,
|
|
385
|
+
},
|
|
386
|
+
}),
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
395
390
|
export function calculateExecutionCost(executionTime: number) {
|
|
396
391
|
// executionTime in milliseconds
|
|
397
392
|
const cost = (executionTime / 1000) * Number(PER_SECOND_COST);
|
|
@@ -117,6 +117,11 @@ export class Conversation extends EventEmitter {
|
|
|
117
117
|
return this._model;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
private _llmInference: LLMInference;
|
|
121
|
+
public get llmInference() {
|
|
122
|
+
return this._llmInference;
|
|
123
|
+
}
|
|
124
|
+
|
|
120
125
|
constructor(
|
|
121
126
|
private _model: string | TLLMModel,
|
|
122
127
|
private _specSource?: string | Record<string, any>,
|
|
@@ -308,7 +313,6 @@ export class Conversation extends EventEmitter {
|
|
|
308
313
|
// toolsConfig,
|
|
309
314
|
// });
|
|
310
315
|
/* ==================== STEP ENTRY ==================== */
|
|
311
|
-
const llmInference: LLMInference = await LLMInference.getInstance(this.model, AccessCandidate.team(this._teamId));
|
|
312
316
|
|
|
313
317
|
if (message) this._context.addUserMessage(message, message_id);
|
|
314
318
|
|
|
@@ -329,7 +333,7 @@ export class Conversation extends EventEmitter {
|
|
|
329
333
|
requestId: llmReqUid,
|
|
330
334
|
});
|
|
331
335
|
|
|
332
|
-
const eventEmitter: any = await llmInference
|
|
336
|
+
const eventEmitter: any = await this.llmInference
|
|
333
337
|
.promptStream({
|
|
334
338
|
contextWindow,
|
|
335
339
|
files,
|
|
@@ -818,6 +822,7 @@ export class Conversation extends EventEmitter {
|
|
|
818
822
|
handler: (args: Record<string, any>) => Promise<any>;
|
|
819
823
|
inputs?: any[];
|
|
820
824
|
}) {
|
|
825
|
+
await this.ready;
|
|
821
826
|
if (!tool.arguments) {
|
|
822
827
|
//if no arguments are provided, we need to extract them from the function
|
|
823
828
|
const toolFunction = tool.handler as Function;
|
|
@@ -879,11 +884,10 @@ export class Conversation extends EventEmitter {
|
|
|
879
884
|
|
|
880
885
|
//deduplicate tools
|
|
881
886
|
|
|
882
|
-
const llmInference: LLMInference = await LLMInference.getInstance(this.model, AccessCandidate.team(this._teamId));
|
|
883
887
|
this._customToolsDeclarations = this._customToolsDeclarations.filter(
|
|
884
888
|
(tool, index, self) => self.findIndex((t) => t.name === tool.name) === index
|
|
885
889
|
);
|
|
886
|
-
const toolsConfig: any = llmInference.connector.formatToolsConfig({
|
|
890
|
+
const toolsConfig: any = this.llmInference.connector.formatToolsConfig({
|
|
887
891
|
type: 'function',
|
|
888
892
|
toolDefinitions: this._customToolsDeclarations,
|
|
889
893
|
toolChoice: this.toolChoice,
|
|
@@ -896,11 +900,11 @@ export class Conversation extends EventEmitter {
|
|
|
896
900
|
}
|
|
897
901
|
|
|
898
902
|
async removeTool(toolName: string) {
|
|
903
|
+
await this.ready;
|
|
899
904
|
this._customToolsDeclarations = this._customToolsDeclarations.filter((tool) => tool.name !== toolName);
|
|
900
905
|
delete this._customToolsHandlers[toolName];
|
|
901
|
-
const llmInference: LLMInference = await LLMInference.getInstance(this.model, AccessCandidate.team(this._teamId));
|
|
902
906
|
|
|
903
|
-
const toolsConfig: any = llmInference.connector.formatToolsConfig({
|
|
907
|
+
const toolsConfig: any = this.llmInference.connector.formatToolsConfig({
|
|
904
908
|
type: 'function',
|
|
905
909
|
toolDefinitions: this._customToolsDeclarations,
|
|
906
910
|
toolChoice: this.toolChoice,
|
|
@@ -928,15 +932,15 @@ export class Conversation extends EventEmitter {
|
|
|
928
932
|
const functionDeclarations = this.getFunctionDeclarations(this._spec);
|
|
929
933
|
//functionDeclarations.push(...this._customToolsDeclarations);
|
|
930
934
|
this._customToolsDeclarations.push(...functionDeclarations);
|
|
931
|
-
|
|
932
|
-
if (!
|
|
935
|
+
this._llmInference = await LLMInference.getInstance(this._model, AccessCandidate.team(this._teamId));
|
|
936
|
+
if (!this._llmInference.connector) {
|
|
933
937
|
this.emit('error', 'No connector found for model: ' + this._model);
|
|
934
938
|
return;
|
|
935
939
|
}
|
|
936
940
|
this._customToolsDeclarations = this._customToolsDeclarations.filter(
|
|
937
941
|
(tool, index, self) => self.findIndex((t) => t.name === tool.name) === index
|
|
938
942
|
);
|
|
939
|
-
this._toolsConfig = llmInference.connector.formatToolsConfig({
|
|
943
|
+
this._toolsConfig = this.llmInference.connector.formatToolsConfig({
|
|
940
944
|
type: 'function',
|
|
941
945
|
toolDefinitions: this._customToolsDeclarations,
|
|
942
946
|
toolChoice: this.toolChoice,
|
|
@@ -945,7 +949,7 @@ export class Conversation extends EventEmitter {
|
|
|
945
949
|
let messages = [];
|
|
946
950
|
if (this._context) messages = this._context.messages; // preserve messages
|
|
947
951
|
|
|
948
|
-
this._context = new LLMContext(llmInference, this.systemPrompt, this._llmContextStore);
|
|
952
|
+
this._context = new LLMContext(this.llmInference, this.systemPrompt, this._llmContextStore);
|
|
949
953
|
} else {
|
|
950
954
|
this._toolsConfig = null;
|
|
951
955
|
this._reqMethods = null;
|