@smythos/sre 1.7.20 → 1.7.41
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 +134 -89
- package/dist/index.js.map +1 -1
- package/dist/types/Components/AgentPlugin.class.d.ts +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 +4 -4
- package/dist/types/Components/RAG/DataSourceComponent.class.d.ts +5 -1
- package/dist/types/Components/index.d.ts +3 -3
- package/dist/types/config.d.ts +1 -0
- package/dist/types/helpers/Conversation.helper.d.ts +10 -13
- package/dist/types/helpers/TemplateString.helper.d.ts +1 -1
- package/dist/types/index.d.ts +4 -3
- package/dist/types/subsystems/IO/VectorDB.service/VectorDBConnector.d.ts +1 -0
- 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.helper.d.ts +19 -0
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +15 -10
- 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/Vault.service/connectors/SecretsManager.class.d.ts +2 -3
- package/dist/types/types/LLM.types.d.ts +23 -0
- package/dist/types/types/VectorDB.types.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/AgentPlugin.class.ts +20 -3
- package/src/Components/Classifier.class.ts +79 -16
- package/src/Components/Component.class.ts +14 -1
- package/src/Components/ForEach.class.ts +34 -6
- package/src/Components/GenAILLM.class.ts +75 -34
- package/src/Components/LLMAssistant.class.ts +56 -21
- package/src/Components/RAG/DataSourceCleaner.class.ts +180 -0
- package/src/Components/RAG/DataSourceComponent.class.ts +137 -0
- package/src/Components/RAG/DataSourceIndexer.class.ts +260 -0
- package/src/Components/{DataSourceLookup.class.ts → RAG/DataSourceLookup.class.ts} +96 -3
- package/src/Components/ScrapflyWebScrape.class.ts +7 -0
- package/src/Components/ServerlessCode.class.ts +1 -4
- package/src/Components/index.ts +3 -3
- package/src/config.ts +1 -0
- package/src/helpers/Conversation.helper.ts +112 -26
- package/src/helpers/S3Cache.helper.ts +2 -1
- package/src/helpers/TemplateString.helper.ts +6 -5
- package/src/index.ts +213 -212
- package/src/index.ts.bak +213 -212
- package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +3 -1
- package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +1 -0
- package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +145 -19
- package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +67 -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 +16 -0
- package/src/subsystems/LLMManager/LLM.helper.ts +25 -0
- package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +1 -1
- 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 +192 -139
- 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/openai/apiInterfaces/utils.ts +1 -1
- package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +9 -8
- package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +92 -1
- package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.ts +260 -17
- package/src/subsystems/Security/Account.service/AccountConnector.ts +3 -3
- package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +8 -63
- package/src/types/LLM.types.ts +24 -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/data.utils.ts +6 -4
- package/src/utils/string.utils.ts +3 -192
- package/src/Components/DataSourceCleaner.class.ts +0 -92
- package/src/Components/DataSourceIndexer.class.ts +0 -181
|
@@ -5,7 +5,9 @@ import { Component } from './Component.class';
|
|
|
5
5
|
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
6
6
|
import { TemplateString } from '@sre/helpers/TemplateString.helper';
|
|
7
7
|
import { LLMInference } from '@sre/LLMManager/LLM.inference';
|
|
8
|
+
import { LLMHelper } from '@sre/LLMManager/LLM.helper';
|
|
8
9
|
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
|
|
10
|
+
import { TLLMEvent } from '@sre/types/LLM.types';
|
|
9
11
|
|
|
10
12
|
export class Classifier extends Component {
|
|
11
13
|
protected schema = {
|
|
@@ -97,7 +99,7 @@ ${JSON.stringify(categories, null, 2)}`;
|
|
|
97
99
|
prompt = TemplateString(prompt).parse(input).result;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
logger.log(` Enhanced prompt \n${prompt}
|
|
102
|
+
logger.log(` Enhanced prompt \n${prompt}`);
|
|
101
103
|
|
|
102
104
|
if (!prompt) {
|
|
103
105
|
logger.error(` Missing information, Cannot run classifier`);
|
|
@@ -114,21 +116,82 @@ ${JSON.stringify(categories, null, 2)}`;
|
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
try {
|
|
117
|
-
let response
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
let response;
|
|
120
|
+
|
|
121
|
+
// Use streaming for Claude 4 family models
|
|
122
|
+
if (LLMHelper.isClaude4Family(modelId || model)) {
|
|
123
|
+
logger.debug(`\n ⚡ Using streaming for Claude 4 family model`);
|
|
124
|
+
|
|
125
|
+
const contentPromise = new Promise(async (resolve, reject) => {
|
|
126
|
+
let _content = '';
|
|
127
|
+
let eventEmitter;
|
|
128
|
+
|
|
129
|
+
eventEmitter = await llmInference
|
|
130
|
+
.promptStream({
|
|
131
|
+
contextWindow: [{ role: 'user', content: prompt }],
|
|
132
|
+
files: [],
|
|
133
|
+
params: {
|
|
134
|
+
...config.data,
|
|
135
|
+
agentId: agent.id,
|
|
136
|
+
responseFormat: 'json',
|
|
137
|
+
},
|
|
138
|
+
onFallback: (fallbackInfo) => {
|
|
139
|
+
logger.debug(`\n ↩️ Using fallback model: ${fallbackInfo.model}`);
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
.catch((error) => {
|
|
143
|
+
console.error('Error on promptStream: ', error);
|
|
144
|
+
reject(error);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
eventEmitter.on(TLLMEvent.Content, (content) => {
|
|
148
|
+
_content += content;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
eventEmitter.on(TLLMEvent.End, () => {
|
|
152
|
+
resolve(_content);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
eventEmitter.on(TLLMEvent.Error, (error) => {
|
|
156
|
+
reject(error);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
response = await contentPromise.catch((error) => {
|
|
161
|
+
return { error: error.message || error };
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Handle streaming errors
|
|
165
|
+
if (response?.error) {
|
|
166
|
+
const error = response?.error + ' ' + (response?.details || '');
|
|
167
|
+
logger.error(` LLM Error=`, error);
|
|
168
|
+
return { _error: error, _debug: logger.output };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Post-process the streaming response
|
|
172
|
+
const postProcessed = llmInference.connector.postProcess(response);
|
|
173
|
+
if (postProcessed.error) {
|
|
174
|
+
logger.error(` LLM Post-process Error=`, postProcessed.error);
|
|
175
|
+
return { _error: postProcessed.error, _debug: logger.output };
|
|
176
|
+
}
|
|
177
|
+
response = postProcessed;
|
|
178
|
+
} else {
|
|
179
|
+
// Use regular prompt for non-Claude 4 models
|
|
180
|
+
response = await llmInference
|
|
181
|
+
.prompt({
|
|
182
|
+
query: prompt,
|
|
183
|
+
params: { ...config, agentId: agent.id },
|
|
184
|
+
onFallback: (data) => {
|
|
185
|
+
logger.debug(`\n ↩️ Using Fallback Model: ${data.model}`);
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
.catch((error) => ({ error: error }));
|
|
189
|
+
|
|
190
|
+
if (response?.error) {
|
|
191
|
+
const error = response?.error + ' ' + (response?.details || '');
|
|
192
|
+
logger.error(` LLM Error=`, error);
|
|
193
|
+
return { _error: error, _debug: logger.output };
|
|
194
|
+
}
|
|
132
195
|
}
|
|
133
196
|
|
|
134
197
|
// let parsed = parseJson(response);
|
|
@@ -3,6 +3,7 @@ import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
|
3
3
|
import { Logger } from '@sre/helpers/Log.helper';
|
|
4
4
|
import { performTypeInference } from '@sre/helpers/TypeChecker.helper';
|
|
5
5
|
import { hookableClass, hookAsync } from '@sre/Core/HookService';
|
|
6
|
+
import { TemplateString } from '@sre/helpers/TemplateString.helper';
|
|
6
7
|
|
|
7
8
|
export type TComponentSchema = {
|
|
8
9
|
name: string;
|
|
@@ -123,7 +124,19 @@ export class Component {
|
|
|
123
124
|
if (agent.isKilled()) {
|
|
124
125
|
throw new Error('Agent killed');
|
|
125
126
|
}
|
|
126
|
-
|
|
127
|
+
|
|
128
|
+
let _input = {};
|
|
129
|
+
|
|
130
|
+
// #region Resolve agent variables so that:
|
|
131
|
+
// - type inference works correctly
|
|
132
|
+
// - we don’t need a separate resolution step when the variable name
|
|
133
|
+
// matches the component input name
|
|
134
|
+
for (let [key, value] of Object.entries(input)) {
|
|
135
|
+
_input[key] = TemplateString(value as string).parse(agent.agentVariables).result;
|
|
136
|
+
}
|
|
137
|
+
// #endregion
|
|
138
|
+
|
|
139
|
+
_input = await performTypeInference(_input, config?.inputs, agent);
|
|
127
140
|
|
|
128
141
|
// modify the input object for component's process method
|
|
129
142
|
for (const [key, value] of Object.entries(_input)) {
|
|
@@ -18,6 +18,8 @@ export class ForEach extends Component {
|
|
|
18
18
|
let _in_progress = true;
|
|
19
19
|
const logger = this.createComponentLogger(agent, config);
|
|
20
20
|
try {
|
|
21
|
+
logger.debug(`=== ForEach Log ===`);
|
|
22
|
+
|
|
21
23
|
const inputObject = input.Input;
|
|
22
24
|
let inputArray;
|
|
23
25
|
|
|
@@ -38,18 +40,30 @@ export class ForEach extends Component {
|
|
|
38
40
|
const runtimeData = agent.agentRuntime.getRuntimeData(config.id);
|
|
39
41
|
const _ForEachData = runtimeData._LoopData || { parentId: config.id, loopIndex: 0, loopLength: inputArray.length };
|
|
40
42
|
|
|
41
|
-
logger.debug(`Loop: ${_ForEachData.loopIndex} / ${_ForEachData.loopLength}`);
|
|
42
43
|
delete _ForEachData.branches; //reset branches (the number of branches is calculated in CallComponent@Agent.class.ts )
|
|
43
44
|
|
|
44
45
|
if (_ForEachData.result) {
|
|
45
46
|
_temp_result = _ForEachData.result;
|
|
46
|
-
logger.debug(` => Loop Result : ${JSON.stringify(Loop, null, 2)}`);
|
|
47
|
-
logger.debug(`---------------------------------------------------`);
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
Loop = inputArray[_ForEachData.loopIndex];
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
// Log each iteration: show iteration number, input, and previous iteration details (if available)
|
|
52
|
+
if (Loop !== undefined) {
|
|
53
|
+
logger.debug(` Iteration ${_ForEachData.loopIndex + 1}/${_ForEachData.loopLength}`);
|
|
54
|
+
logger.debug(` In Progress: ${_in_progress}`);
|
|
55
|
+
logger.debug(` Input: \n${JSON.stringify(Loop, null, 2)}`);
|
|
56
|
+
|
|
57
|
+
// Show previous iteration's input and result if available
|
|
58
|
+
if (_ForEachData.loopIndex > 0 && _temp_result && _temp_result[_ForEachData.loopIndex - 1]) {
|
|
59
|
+
const prevInput = inputArray[_ForEachData.loopIndex - 1];
|
|
60
|
+
const prevItem = _temp_result[_ForEachData.loopIndex - 1];
|
|
61
|
+
logger.debug(''); // empty line
|
|
62
|
+
logger.debug(` Previous Input: \n${JSON.stringify(prevInput, null, 2)}`);
|
|
63
|
+
logger.debug(''); // empty line
|
|
64
|
+
logger.debug(` Previous Result: \n${JSON.stringify(prevItem.result || prevItem, null, 2)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
53
67
|
|
|
54
68
|
_in_progress = Loop !== undefined;
|
|
55
69
|
if (_in_progress) {
|
|
@@ -67,12 +81,26 @@ export class ForEach extends Component {
|
|
|
67
81
|
|
|
68
82
|
switch (config?.data?.format) {
|
|
69
83
|
case 'minimal':
|
|
70
|
-
Result = Result.map((item) => cleanupResult(item.result));
|
|
84
|
+
Result = Result.map((item) => cleanupResult(item.result || item));
|
|
71
85
|
break;
|
|
72
86
|
case 'results-array':
|
|
73
|
-
Result = Result.map((item) => Object.values(cleanupResult(item.result))).flat(Infinity);
|
|
87
|
+
Result = Result.map((item) => Object.values(cleanupResult(item.result || item))).flat(Infinity);
|
|
74
88
|
break;
|
|
75
89
|
}
|
|
90
|
+
|
|
91
|
+
// Final summary: Input array, total iterations, and result
|
|
92
|
+
logger.debug(` Total Iterations: ${Result.length}`);
|
|
93
|
+
logger.debug(` In Progress: ${_in_progress}`);
|
|
94
|
+
logger.debug(''); // empty line
|
|
95
|
+
logger.debug(` Input: \n${JSON.stringify(input.Input, null, 2)}`);
|
|
96
|
+
logger.debug(''); // empty line
|
|
97
|
+
logger.debug(
|
|
98
|
+
` Result: \n${JSON.stringify(
|
|
99
|
+
Result.map((item) => item.result || item),
|
|
100
|
+
null,
|
|
101
|
+
2
|
|
102
|
+
)}`
|
|
103
|
+
);
|
|
76
104
|
}
|
|
77
105
|
|
|
78
106
|
return { Loop, Result, _temp_result, _error, _in_progress, _debug: logger.output };
|
|
@@ -107,25 +107,25 @@ export class GenAILLM extends Component {
|
|
|
107
107
|
},
|
|
108
108
|
webSearchCity: {
|
|
109
109
|
type: 'string',
|
|
110
|
-
max:
|
|
110
|
+
max: 255,
|
|
111
111
|
label: 'Web Search City',
|
|
112
112
|
allowEmpty: true,
|
|
113
113
|
},
|
|
114
114
|
webSearchCountry: {
|
|
115
115
|
type: 'string',
|
|
116
|
-
max:
|
|
116
|
+
max: 255,
|
|
117
117
|
label: 'Web Search Country',
|
|
118
118
|
allowEmpty: true,
|
|
119
119
|
},
|
|
120
120
|
webSearchRegion: {
|
|
121
121
|
type: 'string',
|
|
122
|
-
max:
|
|
122
|
+
max: 255,
|
|
123
123
|
label: 'Web Search Region',
|
|
124
124
|
allowEmpty: true,
|
|
125
125
|
},
|
|
126
126
|
webSearchTimezone: {
|
|
127
127
|
type: 'string',
|
|
128
|
-
max:
|
|
128
|
+
max: 255,
|
|
129
129
|
label: 'Web Search Timezone',
|
|
130
130
|
allowEmpty: true,
|
|
131
131
|
},
|
|
@@ -165,7 +165,7 @@ export class GenAILLM extends Component {
|
|
|
165
165
|
},
|
|
166
166
|
searchCountry: {
|
|
167
167
|
type: 'string',
|
|
168
|
-
max:
|
|
168
|
+
max: 255,
|
|
169
169
|
label: 'Search Country',
|
|
170
170
|
allowEmpty: true,
|
|
171
171
|
},
|
|
@@ -247,7 +247,7 @@ export class GenAILLM extends Component {
|
|
|
247
247
|
},
|
|
248
248
|
reasoningEffort: {
|
|
249
249
|
type: 'string',
|
|
250
|
-
valid: ['none', 'default', 'low', 'medium', 'high'],
|
|
250
|
+
valid: ['none', 'default', 'low', 'medium', 'high', 'xhigh'],
|
|
251
251
|
description: 'Controls the level of effort the model will put into reasoning',
|
|
252
252
|
label: 'Reasoning Effort',
|
|
253
253
|
},
|
|
@@ -295,10 +295,10 @@ export class GenAILLM extends Component {
|
|
|
295
295
|
// #region Web Search
|
|
296
296
|
useWebSearch: Joi.boolean().optional().label('Use Web Search'),
|
|
297
297
|
webSearchContextSize: Joi.string().valid('high', 'medium', 'low').optional().label('Web Search Context Size'),
|
|
298
|
-
webSearchCity: Joi.string().max(
|
|
299
|
-
webSearchCountry: Joi.string().max(
|
|
300
|
-
webSearchRegion: Joi.string().max(
|
|
301
|
-
webSearchTimezone: Joi.string().max(
|
|
298
|
+
webSearchCity: Joi.string().max(255).optional().allow('').label('Web Search City'),
|
|
299
|
+
webSearchCountry: Joi.string().max(255).optional().allow('').label('Web Search Country'),
|
|
300
|
+
webSearchRegion: Joi.string().max(255).optional().allow('').label('Web Search Region'),
|
|
301
|
+
webSearchTimezone: Joi.string().max(255).optional().allow('').label('Web Search Timezone'),
|
|
302
302
|
// #endregion
|
|
303
303
|
|
|
304
304
|
// #region xAI Search
|
|
@@ -307,7 +307,7 @@ export class GenAILLM extends Component {
|
|
|
307
307
|
returnCitations: Joi.boolean().optional().allow('').label('Return Citations'),
|
|
308
308
|
maxSearchResults: Joi.number().min(1).max(100).optional().allow('').label('Max Search Results'),
|
|
309
309
|
searchDataSources: Joi.array().items(Joi.string().valid('web', 'x', 'news', 'rss')).max(4).optional().allow('').label('Search Data Sources'),
|
|
310
|
-
searchCountry: Joi.string().
|
|
310
|
+
searchCountry: Joi.string().max(255).optional().allow('').label('Search Country'),
|
|
311
311
|
excludedWebsites: Joi.string().max(10000).optional().allow('').label('Excluded Websites'),
|
|
312
312
|
allowedWebsites: Joi.string().max(10000).optional().allow('').label('Allowed Websites'),
|
|
313
313
|
includedXHandles: Joi.string().max(1000).optional().allow('').label('Included X Handles'),
|
|
@@ -330,7 +330,11 @@ export class GenAILLM extends Component {
|
|
|
330
330
|
|
|
331
331
|
// #region Reasoning
|
|
332
332
|
useReasoning: Joi.boolean().optional().label('Use Reasoning'),
|
|
333
|
-
reasoningEffort: Joi.string()
|
|
333
|
+
reasoningEffort: Joi.string()
|
|
334
|
+
.valid('none', 'default', 'minimal', 'low', 'medium', 'high', 'xhigh')
|
|
335
|
+
.optional()
|
|
336
|
+
.allow('')
|
|
337
|
+
.label('Reasoning Effort'),
|
|
334
338
|
maxThinkingTokens: Joi.number().min(1).optional().label('Maximum Thinking Tokens'),
|
|
335
339
|
// #endregion
|
|
336
340
|
});
|
|
@@ -348,13 +352,24 @@ export class GenAILLM extends Component {
|
|
|
348
352
|
logger.debug(`=== GenAILLM Log ===`);
|
|
349
353
|
let teamId = agent?.teamId;
|
|
350
354
|
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
355
|
+
// Resolve template variables in config.data without mutating original config
|
|
356
|
+
const resolvedConfigData = {
|
|
357
|
+
...config.data,
|
|
358
|
+
prompt: config.data.prompt && TemplateString(config.data.prompt).parse(input).result,
|
|
359
|
+
webSearchCity: config.data.webSearchCity && TemplateString(config.data.webSearchCity).parse(input).result,
|
|
360
|
+
webSearchCountry: config.data.webSearchCountry && TemplateString(config.data.webSearchCountry).parse(input).result,
|
|
361
|
+
webSearchRegion: config.data.webSearchRegion && TemplateString(config.data.webSearchRegion).parse(input).result,
|
|
362
|
+
webSearchTimezone: config.data.webSearchTimezone && TemplateString(config.data.webSearchTimezone).parse(input).result,
|
|
363
|
+
|
|
364
|
+
searchCountry: config.data.searchCountry && TemplateString(config.data.searchCountry).parse(input).result,
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
const passThrough: boolean = resolvedConfigData.passthrough || false;
|
|
368
|
+
const useContextWindow: boolean = resolvedConfigData.useContextWindow || false;
|
|
369
|
+
const useSystemPrompt: boolean = resolvedConfigData.useSystemPrompt || false;
|
|
370
|
+
const maxTokens: number = parseInt(resolvedConfigData.maxTokens) || 1024;
|
|
371
|
+
const maxContextWindowLength: number = parseInt(resolvedConfigData.maxContextWindowLength) || 1024;
|
|
372
|
+
const model: string = resolvedConfigData.model || 'echo';
|
|
358
373
|
const llmInference: LLMInference = await LLMInference.getInstance(model, AccessCandidate.agent(agent.id));
|
|
359
374
|
|
|
360
375
|
// if the llm is undefined, then it means we removed the model from our system
|
|
@@ -371,7 +386,7 @@ export class GenAILLM extends Component {
|
|
|
371
386
|
|
|
372
387
|
logger.debug(` Model : ${modelId || model}`);
|
|
373
388
|
|
|
374
|
-
|
|
389
|
+
const prompt: any = resolvedConfigData.prompt;
|
|
375
390
|
|
|
376
391
|
let files: any[] = parseFiles(input, config);
|
|
377
392
|
let isMultimodalRequest = false;
|
|
@@ -403,8 +418,24 @@ export class GenAILLM extends Component {
|
|
|
403
418
|
files = validFiles.filter(Boolean);
|
|
404
419
|
|
|
405
420
|
if (files.length === 0) {
|
|
421
|
+
// No valid files after filtering - determine the cause
|
|
422
|
+
const hasDetectedMimeTypes = fileTypes.size > 0;
|
|
423
|
+
|
|
424
|
+
if (!hasDetectedMimeTypes) {
|
|
425
|
+
// Case 1: No mime types detected - files are corrupted/invalid
|
|
426
|
+
return {
|
|
427
|
+
_error: `Unable to process the provided file(s). Please ensure file(s) are not corrupted, have valid formats, and contain readable data.`,
|
|
428
|
+
_debug: logger.output,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Case 2: Files detected but model doesn't support those types
|
|
433
|
+
const detectedTypes = Array.from(fileTypes).join(', ');
|
|
434
|
+
const supportedTypes = new Set(Object.values(supportedFileTypes).flat());
|
|
435
|
+
const supportedTypesText = supportedTypes.size > 0 ? `\nSupported types: ${Array.from(supportedTypes).join(', ')}` : '';
|
|
436
|
+
|
|
406
437
|
return {
|
|
407
|
-
_error: `Model does not support
|
|
438
|
+
_error: `Model '${model}' does not support the provided file type(s): ${detectedTypes}.${supportedTypesText}`,
|
|
408
439
|
_debug: logger.output,
|
|
409
440
|
};
|
|
410
441
|
}
|
|
@@ -420,7 +451,7 @@ export class GenAILLM extends Component {
|
|
|
420
451
|
|
|
421
452
|
// default to json response format
|
|
422
453
|
const hasCustomOutputs = config?.outputs?.some((output) => !output.default);
|
|
423
|
-
|
|
454
|
+
resolvedConfigData.responseFormat = resolvedConfigData?.responseFormat || (hasCustomOutputs ? 'json' : '');
|
|
424
455
|
|
|
425
456
|
// request to LLM
|
|
426
457
|
let response: any;
|
|
@@ -478,7 +509,7 @@ export class GenAILLM extends Component {
|
|
|
478
509
|
contextWindow: messages,
|
|
479
510
|
files,
|
|
480
511
|
params: {
|
|
481
|
-
...
|
|
512
|
+
...resolvedConfigData,
|
|
482
513
|
agentId: agent.id,
|
|
483
514
|
},
|
|
484
515
|
onFallback: (fallbackInfo) => {
|
|
@@ -528,26 +559,36 @@ export class GenAILLM extends Component {
|
|
|
528
559
|
response = await contentPromise.catch((error) => {
|
|
529
560
|
return { error: error.message || error };
|
|
530
561
|
});
|
|
531
|
-
|
|
562
|
+
|
|
563
|
+
// #region Handle Response Errors
|
|
564
|
+
if (response?.error) {
|
|
565
|
+
const error = response?.error + ' ' + (response?.details || '');
|
|
566
|
+
logger.error(` LLM Error=`, error);
|
|
567
|
+
|
|
568
|
+
return { Output: response?.data, _error: error, _debug: logger.output };
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const emptyResponseErrorMsg =
|
|
572
|
+
"Empty response. This is usually due to output token limit reached. Please try again with a higher 'Maximum Output Tokens'.";
|
|
573
|
+
|
|
574
|
+
// If the finish reason is not "stop", it means the model stopped before completing the response.
|
|
532
575
|
if (finishReason !== 'stop') {
|
|
576
|
+
let errMsg = `The model stopped before completing the response.
|
|
577
|
+
\nReason: ${finishReason}.
|
|
578
|
+
\n${!response ? emptyResponseErrorMsg : ''}`;
|
|
579
|
+
|
|
533
580
|
return {
|
|
534
581
|
Reply: response,
|
|
535
|
-
_error:
|
|
582
|
+
_error: errMsg,
|
|
536
583
|
_debug: logger.output,
|
|
537
584
|
};
|
|
538
585
|
}
|
|
539
586
|
|
|
540
|
-
//
|
|
587
|
+
// If the finish reason is "stop" but there is still no response, it is usually caused by reaching the output token limit.
|
|
541
588
|
if (!response) {
|
|
542
|
-
return { _error:
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (response?.error) {
|
|
546
|
-
const error = response?.error + ' ' + (response?.details || '');
|
|
547
|
-
logger.error(` LLM Error=`, error);
|
|
548
|
-
|
|
549
|
-
return { Output: response?.data, _error: error, _debug: logger.output };
|
|
589
|
+
return { _error: emptyResponseErrorMsg, _debug: logger.output };
|
|
550
590
|
}
|
|
591
|
+
// #endregion
|
|
551
592
|
|
|
552
593
|
const Reply = llmInference.connector.postProcess(response);
|
|
553
594
|
if (Reply.error) {
|
|
@@ -10,7 +10,8 @@ import { encode } from 'gpt-tokenizer';
|
|
|
10
10
|
import { Component } from './Component.class';
|
|
11
11
|
import { JSONContent } from '@sre/helpers/JsonContent.helper';
|
|
12
12
|
import { LLMInference } from '@sre/LLMManager/LLM.inference';
|
|
13
|
-
import {
|
|
13
|
+
import { LLMHelper } from '@sre/LLMManager/LLM.helper';
|
|
14
|
+
import { TLLMMessageRole, TLLMEvent } from '@sre/types/LLM.types';
|
|
14
15
|
import { VaultHelper } from '@sre/Security/Vault.service/Vault.helper';
|
|
15
16
|
import path from 'path';
|
|
16
17
|
import config from '@sre/config';
|
|
@@ -113,7 +114,7 @@ export class LLMAssistant extends Component {
|
|
|
113
114
|
const conversationId = input.ConversationId;
|
|
114
115
|
|
|
115
116
|
let behavior = TemplateString(config.data.behavior).parse(input).result;
|
|
116
|
-
logger.debug(`[Parsed Behavior] \n${behavior}`);
|
|
117
|
+
logger.debug(` [Parsed Behavior] \n${behavior}`);
|
|
117
118
|
|
|
118
119
|
//#region get max tokens
|
|
119
120
|
let maxTokens = 2048;
|
|
@@ -147,7 +148,14 @@ export class LLMAssistant extends Component {
|
|
|
147
148
|
};
|
|
148
149
|
|
|
149
150
|
let response: any;
|
|
150
|
-
|
|
151
|
+
const isClaude4 = LLMHelper.isClaude4Family(modelId || model);
|
|
152
|
+
|
|
153
|
+
// Use streaming for passthrough OR Claude 4 family models
|
|
154
|
+
if (passThrough || isClaude4) {
|
|
155
|
+
if (isClaude4) {
|
|
156
|
+
logger.debug(`\n ⚡ Using streaming for Claude 4 family model`);
|
|
157
|
+
}
|
|
158
|
+
|
|
151
159
|
const contentPromise = new Promise(async (resolve, reject) => {
|
|
152
160
|
let _content = '';
|
|
153
161
|
const eventEmitter: any = await llmInference
|
|
@@ -162,25 +170,53 @@ export class LLMAssistant extends Component {
|
|
|
162
170
|
console.error('Error on promptStream: ', error);
|
|
163
171
|
reject(error);
|
|
164
172
|
});
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
173
|
+
|
|
174
|
+
eventEmitter.on(TLLMEvent.Content, (content) => {
|
|
175
|
+
if (passThrough) {
|
|
176
|
+
if (typeof agent.callback === 'function') {
|
|
177
|
+
agent.callback({ content });
|
|
178
|
+
}
|
|
179
|
+
agent.sse.send('llm/passthrough/content', content);
|
|
168
180
|
}
|
|
169
|
-
agent.sse.send('llm/passthrough/content', content);
|
|
170
181
|
_content += content;
|
|
171
182
|
});
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
183
|
+
|
|
184
|
+
eventEmitter.on(TLLMEvent.Thinking, (thinking) => {
|
|
185
|
+
if (passThrough) {
|
|
186
|
+
if (typeof agent.callback === 'function') {
|
|
187
|
+
agent.callback({ thinking });
|
|
188
|
+
}
|
|
189
|
+
agent.sse.send('llm/passthrough/thinking', thinking);
|
|
175
190
|
}
|
|
176
|
-
agent.sse.send('llm/passthrough/thinking', thinking);
|
|
177
191
|
});
|
|
178
|
-
|
|
179
|
-
|
|
192
|
+
|
|
193
|
+
eventEmitter.on(TLLMEvent.End, () => {
|
|
180
194
|
resolve(_content);
|
|
181
195
|
});
|
|
196
|
+
|
|
197
|
+
eventEmitter.on(TLLMEvent.Error, (error) => {
|
|
198
|
+
reject(error);
|
|
199
|
+
});
|
|
182
200
|
});
|
|
183
|
-
|
|
201
|
+
|
|
202
|
+
response = await contentPromise.catch((error) => {
|
|
203
|
+
return { error: error.message || error };
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Handle streaming errors
|
|
207
|
+
if (response?.error) {
|
|
208
|
+
const error = response?.error + ' ' + (response?.details || '');
|
|
209
|
+
logger.error(` LLM Error=`, error);
|
|
210
|
+
return { Response: response?.data, _error: error, _debug: logger.output };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Post-process the streaming response
|
|
214
|
+
const postProcessed = llmInference.connector.postProcess(response);
|
|
215
|
+
if (postProcessed.error) {
|
|
216
|
+
logger.error(` LLM Post-process Error=`, postProcessed.error);
|
|
217
|
+
return { _error: postProcessed.error, _debug: logger.output };
|
|
218
|
+
}
|
|
219
|
+
response = postProcessed;
|
|
184
220
|
} else {
|
|
185
221
|
response = await llmInference
|
|
186
222
|
.prompt({
|
|
@@ -191,6 +227,12 @@ export class LLMAssistant extends Component {
|
|
|
191
227
|
},
|
|
192
228
|
})
|
|
193
229
|
.catch((error) => ({ error: error }));
|
|
230
|
+
|
|
231
|
+
if (response?.error) {
|
|
232
|
+
const error = response?.error + ' ' + (response?.details || '');
|
|
233
|
+
logger.error(` LLM Error=`, error);
|
|
234
|
+
return { Response: response?.data, _error: error, _debug: logger.output };
|
|
235
|
+
}
|
|
194
236
|
}
|
|
195
237
|
|
|
196
238
|
// in case we have the response but it's empty string, undefined or null
|
|
@@ -198,13 +240,6 @@ export class LLMAssistant extends Component {
|
|
|
198
240
|
return { _error: ' LLM Error = Empty Response!', _debug: logger.output };
|
|
199
241
|
}
|
|
200
242
|
|
|
201
|
-
if (response?.error) {
|
|
202
|
-
const error = response?.error + ' ' + (response?.details || '');
|
|
203
|
-
logger.error(` LLM Error=`, error);
|
|
204
|
-
|
|
205
|
-
return { Response: response?.data, _error: error, _debug: logger.output };
|
|
206
|
-
}
|
|
207
|
-
|
|
208
243
|
messages.push({ role: 'assistant', content: response });
|
|
209
244
|
saveMessagesToSession(agent.id, userId, conversationId, messages, ttl);
|
|
210
245
|
|