@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.
Files changed (69) hide show
  1. package/dist/index.js +120 -82
  2. package/dist/index.js.map +1 -1
  3. package/dist/types/Components/DataSourceIndexer.class.d.ts +4 -12
  4. package/dist/types/Components/GenAILLM.class.d.ts +5 -5
  5. package/dist/types/Components/RAG/DataSourceCleaner.class.d.ts +37 -0
  6. package/dist/types/Components/RAG/DataSourceComponent.class.d.ts +30 -0
  7. package/dist/types/Components/RAG/DataSourceIndexer.class.d.ts +14 -0
  8. package/dist/types/Components/RAG/DataSourceLookup.class.d.ts +36 -0
  9. package/dist/types/Components/index.d.ts +3 -3
  10. package/dist/types/helpers/Conversation.helper.d.ts +3 -0
  11. package/dist/types/index.d.ts +3 -3
  12. package/dist/types/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.d.ts +1 -0
  13. package/dist/types/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.d.ts +11 -4
  14. package/dist/types/subsystems/IO/VectorDB.service/embed/index.d.ts +5 -0
  15. package/dist/types/subsystems/LLMManager/LLM.inference.d.ts +10 -3
  16. package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +4 -2
  17. package/dist/types/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.d.ts +35 -0
  18. package/dist/types/subsystems/Security/Account.service/AccountConnector.d.ts +2 -2
  19. package/dist/types/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.d.ts +10 -0
  20. package/dist/types/subsystems/Security/Vault.service/connectors/SecretsManager.class.d.ts +6 -2
  21. package/dist/types/types/LLM.types.d.ts +2 -0
  22. package/dist/types/types/VectorDB.types.d.ts +4 -0
  23. package/dist/types/utils/array.utils.d.ts +4 -0
  24. package/dist/types/utils/string.utils.d.ts +1 -0
  25. package/package.json +3 -3
  26. package/src/Components/APIEndpoint.class.ts +1 -6
  27. package/src/Components/Component.class.ts +14 -1
  28. package/src/Components/DataSourceIndexer.class.ts +148 -34
  29. package/src/Components/GenAILLM.class.ts +21 -11
  30. package/src/Components/RAG/DataSourceCleaner.class.ts +178 -0
  31. package/src/Components/RAG/DataSourceComponent.class.ts +111 -0
  32. package/src/Components/RAG/DataSourceIndexer.class.ts +254 -0
  33. package/src/Components/{DataSourceLookup.class.ts → RAG/DataSourceLookup.class.ts} +92 -3
  34. package/src/Components/ServerlessCode.class.ts +1 -4
  35. package/src/Components/index.ts +3 -3
  36. package/src/helpers/AWSLambdaCode.helper.ts +40 -45
  37. package/src/helpers/Conversation.helper.ts +14 -10
  38. package/src/helpers/S3Cache.helper.ts +2 -1
  39. package/src/index.ts +212 -212
  40. package/src/index.ts.bak +212 -212
  41. package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +3 -1
  42. package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +145 -19
  43. package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +56 -22
  44. package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +1 -0
  45. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +2 -1
  46. package/src/subsystems/IO/VectorDB.service/embed/index.ts +18 -0
  47. package/src/subsystems/LLMManager/LLM.inference.ts +63 -47
  48. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +35 -10
  49. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +12 -4
  50. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +4 -4
  51. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +105 -23
  52. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +17 -5
  53. package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +18 -3
  54. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +14 -5
  55. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +6 -4
  56. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +5 -5
  57. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +8 -3
  58. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +9 -8
  59. package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +126 -28
  60. package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.ts +38 -6
  61. package/src/subsystems/Security/Account.service/AccountConnector.ts +3 -3
  62. package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +111 -48
  63. package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +41 -66
  64. package/src/types/LLM.types.ts +5 -0
  65. package/src/types/VectorDB.types.ts +4 -0
  66. package/src/utils/array.utils.ts +11 -0
  67. package/src/utils/base64.utils.ts +1 -1
  68. package/src/utils/string.utils.ts +3 -192
  69. package/src/Components/DataSourceCleaner.class.ts +0 -92
@@ -13,14 +13,30 @@ import { TLLMChatResponse, TLLMMessageRole, TLLMModel, TLLMParams } from '@sre/t
13
13
  import { LLMConnector } from './LLM.service/LLMConnector';
14
14
  import { IModelsProviderRequest, ModelsProviderConnector } from './ModelsProvider.service/ModelsProviderConnector';
15
15
 
16
- const console = Logger('LLMInference');
16
+ const logger = Logger('LLMInference');
17
17
 
18
18
  type TPromptParams = { query?: string; contextWindow?: any[]; files?: any[]; params: TLLMParams; onFallback?: (data: any) => void };
19
19
 
20
20
  export class LLMInference {
21
- private model: string | TLLMModel;
22
- private llmConnector: LLMConnector;
23
- private modelProviderReq: IModelsProviderRequest;
21
+ private _model: string | TLLMModel;
22
+ public get model() {
23
+ return this._model;
24
+ }
25
+ public get modelId() {
26
+ return typeof this._model === 'string' ? this._model : this._model?.modelId;
27
+ }
28
+ private _llmConnector: LLMConnector;
29
+ public get llmConnector() {
30
+ return this._llmConnector;
31
+ }
32
+ private _modelProviderReq: IModelsProviderRequest;
33
+ public get modelProviderReq() {
34
+ return this._modelProviderReq;
35
+ }
36
+ private _llmProviderName: string;
37
+ public get llmProviderName() {
38
+ return this._llmProviderName;
39
+ }
24
40
  public teamId?: string;
25
41
 
26
42
  public static async getInstance(model: string | TLLMModel, candidate: AccessCandidate) {
@@ -34,18 +50,18 @@ export class LLMInference {
34
50
  const llmInference = new LLMInference();
35
51
  llmInference.teamId = teamId;
36
52
 
37
- llmInference.modelProviderReq = modelsProvider.requester(candidate);
53
+ llmInference._modelProviderReq = modelsProvider.requester(candidate);
38
54
 
39
- const llmProvider = await llmInference.modelProviderReq.getProvider(model);
40
- if (llmProvider) {
41
- llmInference.llmConnector = ConnectorService.getLLMConnector(llmProvider);
55
+ llmInference._llmProviderName = await llmInference._modelProviderReq.getProvider(model);
56
+ if (llmInference._llmProviderName) {
57
+ llmInference._llmConnector = ConnectorService.getLLMConnector(llmInference._llmProviderName);
42
58
  }
43
59
 
44
- if (!llmInference.llmConnector) {
45
- console.error(`Model ${model} unavailable for team ${teamId}`);
60
+ if (!llmInference._llmConnector) {
61
+ logger.warn(`Model ${model} unavailable for team ${teamId}`);
46
62
  }
47
63
 
48
- llmInference.model = model;
64
+ llmInference._model = model;
49
65
 
50
66
  return llmInference;
51
67
  }
@@ -53,32 +69,32 @@ export class LLMInference {
53
69
  public static user(candidate: AccessCandidate): any {}
54
70
 
55
71
  public get connector(): LLMConnector {
56
- return this.llmConnector;
72
+ return this._llmConnector;
57
73
  }
58
74
 
59
75
  public async prompt({ query, contextWindow, files, params, onFallback = () => {} }: TPromptParams, isInFallback: boolean = false) {
60
76
  let messages = contextWindow || [];
61
77
 
62
78
  if (query) {
63
- const content = this.llmConnector.enhancePrompt(query, params);
79
+ const content = this._llmConnector.enhancePrompt(query, params);
64
80
  messages.push({ role: TLLMMessageRole.User, content });
65
81
  }
66
82
 
67
83
  // Reset the model, since the fallback model may change — especially when using user custom models.
68
- params.model = this.model;
84
+ params.model = this._model;
69
85
 
70
86
  params.messages = messages;
71
87
  params.files = files;
72
88
 
73
89
  // If a fallback model is used, trigger the onFallback callback to notify the caller.
74
90
  if (isInFallback && typeof onFallback === 'function') {
75
- onFallback({ model: this.model });
91
+ onFallback({ model: this._model });
76
92
  }
77
93
 
78
94
  try {
79
- let response: TLLMChatResponse = await this.llmConnector.requester(AccessCandidate.agent(params.agentId)).request(params);
95
+ let response: TLLMChatResponse = await this._llmConnector.requester(AccessCandidate.agent(params.agentId)).request(params);
80
96
 
81
- const result = this.llmConnector.postProcess(response?.content);
97
+ const result = this._llmConnector.postProcess(response?.content);
82
98
  if (result.error) {
83
99
  // If the model stopped before completing the response, this is usually due to output token limit reached.
84
100
  if (response.finishReason !== 'stop') {
@@ -102,12 +118,12 @@ export class LLMInference {
102
118
  }
103
119
  } catch (fallbackError) {
104
120
  // If fallback also failed, log it but continue to throw original error
105
- console.warn('Fallback also failed:', fallbackError);
121
+ logger.warn('Fallback also failed:', fallbackError);
106
122
  }
107
123
  }
108
124
 
109
125
  // If fallback was not attempted or failed, throw the original error
110
- console.error('Error in chatRequest: ', error);
126
+ logger.error('Error in chatRequest: ', error);
111
127
  throw error;
112
128
  }
113
129
  }
@@ -116,23 +132,23 @@ export class LLMInference {
116
132
  let messages = contextWindow || [];
117
133
 
118
134
  if (query) {
119
- const content = this.llmConnector.enhancePrompt(query, params);
135
+ const content = this._llmConnector.enhancePrompt(query, params);
120
136
  messages.push({ role: TLLMMessageRole.User, content });
121
137
  }
122
138
 
123
139
  // Reset the model, since the fallback model may change — especially when using user custom models.
124
- params.model = this.model;
140
+ params.model = this._model;
125
141
 
126
142
  params.messages = messages;
127
143
  params.files = files;
128
144
 
129
145
  // If a fallback model is used, trigger the onFallback callback to notify the caller.
130
146
  if (isInFallback && typeof onFallback === 'function') {
131
- onFallback({ model: this.model });
147
+ onFallback({ model: this._model });
132
148
  }
133
149
 
134
150
  try {
135
- return await this.llmConnector.user(AccessCandidate.agent(params.agentId)).streamRequest(params);
151
+ return await this._llmConnector.user(AccessCandidate.agent(params.agentId)).streamRequest(params);
136
152
  } catch (error) {
137
153
  // Attempt fallback for custom models (only if not already in fallback)
138
154
  if (!isInFallback) {
@@ -152,12 +168,12 @@ export class LLMInference {
152
168
  }
153
169
  } catch (fallbackError) {
154
170
  // If fallback also failed, log it but continue to return error emitter
155
- console.warn('Fallback also failed:', fallbackError);
171
+ logger.warn('Fallback also failed:', fallbackError);
156
172
  }
157
173
  }
158
174
 
159
175
  // If fallback was not attempted or failed, return error emitter
160
- console.error('Error in streamRequest:', error);
176
+ logger.error('Error in streamRequest:', error);
161
177
 
162
178
  const dummyEmitter = new EventEmitter();
163
179
  process.nextTick(() => {
@@ -224,22 +240,22 @@ export class LLMInference {
224
240
  * @returns The result from the fallback execution, or null if fallback should not be attempted
225
241
  */
226
242
  private async executeFallback(methodName: 'prompt' | 'promptStream', args: TPromptParams): Promise<any> {
227
- const isCustomModel = await this.modelProviderReq.isUserCustomLLM(this.model);
228
- const fallbackModel = await this.modelProviderReq.getFallbackLLM(this.model);
243
+ const isCustomModel = await this._modelProviderReq.isUserCustomLLM(this._model);
244
+ const fallbackModel = await this._modelProviderReq.getFallbackLLM(this._model);
229
245
 
230
246
  // Only execute fallback if it's a custom model with a configured fallback
231
247
  if (!isCustomModel || !fallbackModel) {
232
248
  return null;
233
249
  }
234
250
 
235
- console.info(`Attempting fallback from ${this.model} to ${fallbackModel}`);
251
+ logger.info(`Attempting fallback from ${this._model} to ${fallbackModel}`);
236
252
 
237
253
  // Mutate the model and connector to use fallback
238
- this.model = fallbackModel;
254
+ this._model = fallbackModel;
239
255
 
240
- const llmProvider = await this.modelProviderReq.getProvider(fallbackModel);
256
+ const llmProvider = await this._modelProviderReq.getProvider(fallbackModel);
241
257
  if (llmProvider) {
242
- this.llmConnector = ConnectorService.getLLMConnector(llmProvider);
258
+ this._llmConnector = ConnectorService.getLLMConnector(llmProvider);
243
259
  }
244
260
 
245
261
  // Call the appropriate method with isInFallback=true to prevent further fallbacks
@@ -252,13 +268,13 @@ export class LLMInference {
252
268
 
253
269
  public async imageGenRequest({ query, files, params }: TPromptParams) {
254
270
  params.prompt = query;
255
- return this.llmConnector.user(AccessCandidate.agent(params.agentId)).imageGenRequest(params);
271
+ return this._llmConnector.user(AccessCandidate.agent(params.agentId)).imageGenRequest(params);
256
272
  }
257
273
 
258
274
  public async imageEditRequest({ query, files, params }: TPromptParams) {
259
275
  params.prompt = query;
260
276
  params.files = files;
261
- return this.llmConnector.user(AccessCandidate.agent(params.agentId)).imageEditRequest(params);
277
+ return this._llmConnector.user(AccessCandidate.agent(params.agentId)).imageEditRequest(params);
262
278
  }
263
279
 
264
280
  //@deprecated
@@ -269,11 +285,11 @@ export class LLMInference {
269
285
  throw new Error('Input messages are required.');
270
286
  }
271
287
 
272
- const model = params.model || this.model;
288
+ const model = params.model || this._model;
273
289
 
274
- return await this.llmConnector.user(AccessCandidate.agent(agentId)).streamRequest({ ...params, model });
290
+ return await this._llmConnector.user(AccessCandidate.agent(agentId)).streamRequest({ ...params, model });
275
291
  } catch (error) {
276
- console.error('Error in streamRequest:', error);
292
+ logger.error('Error in streamRequest:', error);
277
293
 
278
294
  const dummyEmitter = new EventEmitter();
279
295
  process.nextTick(() => {
@@ -306,11 +322,11 @@ export class LLMInference {
306
322
  //FIXME we need to update the connector multimediaStreamRequest in order to ignore prompt param if not provided
307
323
  const userMessage = Array.isArray(params.messages) ? params.messages.pop() : {};
308
324
  const prompt = userMessage?.content || '';
309
- const model = params.model || this.model;
325
+ const model = params.model || this._model;
310
326
 
311
- return await this.llmConnector.user(AccessCandidate.agent(agentId)).multimodalStreamRequest(prompt, { ...params, model });
327
+ return await this._llmConnector.user(AccessCandidate.agent(agentId)).multimodalStreamRequest(prompt, { ...params, model });
312
328
  } catch (error: any) {
313
- console.error('Error in multimodalRequest: ', error);
329
+ logger.error('Error in multimodalRequest: ', error);
314
330
 
315
331
  throw error;
316
332
  }
@@ -337,12 +353,12 @@ export class LLMInference {
337
353
  params.files = _files;
338
354
 
339
355
  try {
340
- prompt = this.llmConnector.enhancePrompt(prompt, config);
341
- const model = params.model || this.model;
356
+ prompt = this._llmConnector.enhancePrompt(prompt, config);
357
+ const model = params.model || this._model;
342
358
 
343
- return await this.llmConnector.user(AccessCandidate.agent(agentId)).multimodalStreamRequest(prompt, { ...params, model });
359
+ return await this._llmConnector.user(AccessCandidate.agent(agentId)).multimodalStreamRequest(prompt, { ...params, model });
344
360
  } catch (error: any) {
345
- console.error('Error in multimodalRequest: ', error);
361
+ logger.error('Error in multimodalRequest: ', error);
346
362
 
347
363
  throw error;
348
364
  }
@@ -376,7 +392,7 @@ export class LLMInference {
376
392
 
377
393
  //#region get max model context
378
394
 
379
- const modelInfo = await this.modelProviderReq.getModelInfo(this.model, true);
395
+ const modelInfo = await this._modelProviderReq.getModelInfo(this._model, true);
380
396
  let maxModelContext = modelInfo?.tokens;
381
397
  let maxModelOutputTokens = modelInfo?.completionTokens || modelInfo?.tokens;
382
398
  // const isStandardLLM = LLMRegistry.isStandardLLM(this.model);
@@ -399,10 +415,10 @@ export class LLMInference {
399
415
  }
400
416
 
401
417
  if (maxInputContext <= 0) {
402
- console.warn('Max input context is 0, returning empty context window, This usually indicates a wrong model configuration');
418
+ logger.warn('Max input context is 0, returning empty context window, This usually indicates a wrong model configuration');
403
419
  }
404
420
 
405
- console.debug(
421
+ logger.debug(
406
422
  `Context Window Configuration: Max Input Tokens: ${maxInputContext}, Max Output Tokens: ${maxOutputContext}, Max Model Tokens: ${maxModelContext}`
407
423
  );
408
424
  const systemMessage = { role: 'system', content: systemPrompt };
@@ -473,7 +489,7 @@ function countTokens(content: any, model: 'gpt-4o' | 'gpt-4o-mini' = 'gpt-4o') {
473
489
  const tokens = encodeChat([{ role: 'user', content: _stringifiedContent } as ChatMessage], model);
474
490
  return tokens.length;
475
491
  } catch (error) {
476
- console.warn('Error in countTokens: ', error);
492
+ logger.warn('Error in countTokens: ', error);
477
493
  return 0;
478
494
  }
479
495
  }
@@ -1,5 +1,6 @@
1
1
  import EventEmitter from 'events';
2
2
  import Anthropic from '@anthropic-ai/sdk';
3
+ import type { MessageStreamEvents } from '@anthropic-ai/sdk/lib/MessageStream';
3
4
 
4
5
  import { JSON_RESPONSE_INSTRUCTION, BUILT_IN_MODEL_PREFIX } from '@sre/constants';
5
6
  import { BinaryInput } from '@sre/helpers/BinaryInput.helper';
@@ -35,6 +36,26 @@ const LEGACY_THINKING_MODELS = ['smythos/claude-3.7-sonnet-thinking', 'claude-3.
35
36
 
36
37
  // Type aliases
37
38
  type AnthropicMessageParams = Anthropic.MessageCreateParamsNonStreaming | Anthropic.Messages.MessageStreamParams;
39
+ type AnthropicStreamEventType = keyof MessageStreamEvents;
40
+
41
+ // Event names automatically validated against MessageStreamEvents type
42
+ // TypeScript will error if any events are missing or incorrect
43
+ // This ensures we always use the correct event names as defined by Anthropic SDK
44
+ const AnthropicStreamEvent = {
45
+ connect: 'connect',
46
+ streamEvent: 'streamEvent',
47
+ text: 'text',
48
+ citation: 'citation',
49
+ inputJson: 'inputJson',
50
+ thinking: 'thinking',
51
+ signature: 'signature',
52
+ message: 'message',
53
+ contentBlock: 'contentBlock',
54
+ finalMessage: 'finalMessage',
55
+ error: 'error',
56
+ abort: 'abort',
57
+ end: 'end',
58
+ } satisfies Record<keyof MessageStreamEvents, AnthropicStreamEventType>;
38
59
 
39
60
  // TODO [Forhad]: implement proper typing
40
61
 
@@ -132,34 +153,38 @@ export class AnthropicConnector extends LLMConnector {
132
153
  const needsPrefillInjection = this.hasPrefillText(body.messages);
133
154
  let prefillInjected = false;
134
155
 
135
- stream.on('streamEvent', (event: any) => {
156
+ stream.on(AnthropicStreamEvent.streamEvent, (event: any) => {
136
157
  if (event.message?.usage) {
137
158
  //console.log('usage', event.message?.usage);
138
159
  }
139
160
  });
140
161
 
141
- stream.on('error', (error) => {
162
+ stream.on(AnthropicStreamEvent.error, (error) => {
142
163
  //console.log('error', error);
143
164
 
144
- emitter.emit('error', error);
165
+ emitter.emit(TLLMEvent.Error, error);
145
166
  });
146
167
 
147
- stream.on('text', (text: string) => {
168
+ stream.on(AnthropicStreamEvent.message, (message) => {
169
+ emitter.emit(TLLMEvent.Data, message);
170
+ });
171
+
172
+ stream.on(AnthropicStreamEvent.text, (text: string) => {
148
173
  // Inject prefill text only once at the very beginning if needed
149
174
  if (needsPrefillInjection && !prefillInjected) {
150
175
  text = `${PREFILL_TEXT_FOR_JSON_RESPONSE}${text}`;
151
176
  prefillInjected = true;
152
177
  }
153
178
 
154
- emitter.emit('content', text);
179
+ emitter.emit(TLLMEvent.Content, text);
155
180
  });
156
181
 
157
- stream.on('thinking', (thinking) => {
182
+ stream.on(AnthropicStreamEvent.thinking, (thinking) => {
158
183
  // Handle thinking blocks during streaming
159
- emitter.emit('thinking', thinking);
184
+ emitter.emit(TLLMEvent.Thinking, thinking);
160
185
  });
161
186
 
162
- stream.on('finalMessage', (finalMessage) => {
187
+ stream.on(AnthropicStreamEvent.finalMessage, (finalMessage) => {
163
188
  let finishReason = 'stop';
164
189
  // Preserve thinking blocks for subsequent tool interactions
165
190
  thinkingBlocks = finalMessage.content.filter((block) => block.type === 'thinking' || block.type === 'redacted_thinking');
@@ -197,12 +222,12 @@ export class AnthropicConnector extends LLMConnector {
197
222
  usage_data.push(reportedUsage);
198
223
  }
199
224
  if (finishReason !== 'stop' && finishReason !== 'end_turn') {
200
- emitter.emit('interrupted', finishReason);
225
+ emitter.emit(TLLMEvent.Interrupted, finishReason);
201
226
  }
202
227
 
203
228
  //only emit end event after processing the final message
204
229
  setTimeout(() => {
205
- emitter.emit('end', toolsData, usage_data, finishReason);
230
+ emitter.emit(TLLMEvent.End, toolsData, usage_data, finishReason);
206
231
  }, 100);
207
232
  });
208
233
 
@@ -126,14 +126,14 @@ export class BedrockConnector extends LLMConnector {
126
126
  // Handle message start
127
127
  if (chunk.messageStart) {
128
128
  currentMessage.role = chunk.messageStart.role || '';
129
- emitter.emit('data', { role: currentMessage.role });
129
+ emitter.emit(TLLMEvent.Data, { role: currentMessage.role });
130
130
  }
131
131
 
132
132
  // Handle content deltas
133
133
  if (chunk.contentBlockDelta?.delta?.text) {
134
134
  currentMessage.content += chunk.contentBlockDelta.delta.text;
135
- emitter.emit('data', chunk.contentBlockDelta.delta.text);
136
- emitter.emit('content', chunk.contentBlockDelta.delta.text, currentMessage.role);
135
+ emitter.emit(TLLMEvent.Data, chunk.contentBlockDelta.delta.text);
136
+ emitter.emit(TLLMEvent.Content, chunk.contentBlockDelta.delta.text, currentMessage.role);
137
137
  }
138
138
 
139
139
  // Handle tool use start
@@ -175,10 +175,18 @@ export class BedrockConnector extends LLMConnector {
175
175
 
176
176
  // Handle message completion
177
177
  if (chunk.messageStop) {
178
+ const finishReason = chunk.messageStop.stopReason || 'stop';
179
+
178
180
  if (currentMessage.toolCalls.length > 0) {
179
181
  emitter.emit(TLLMEvent.ToolInfo, currentMessage.toolCalls);
180
182
  }
181
- emitter.emit(TLLMEvent.End, currentMessage.toolCalls);
183
+
184
+ // Emit interrupted event if finishReason is not 'stop'
185
+ if (finishReason !== 'stop' && finishReason !== 'end_turn') {
186
+ emitter.emit(TLLMEvent.Interrupted, finishReason);
187
+ }
188
+
189
+ emitter.emit(TLLMEvent.End, currentMessage.toolCalls, [], finishReason);
182
190
  }
183
191
 
184
192
  if (chunk?.metadata?.usage) {
@@ -1,7 +1,7 @@
1
1
  import { JSONContent } from '@sre/helpers/JsonContent.helper';
2
2
  import { LLMConnector } from '../LLMConnector';
3
3
  import EventEmitter from 'events';
4
- import { APIKeySource, ILLMRequestFuncParams, TLLMChatResponse, TLLMPreparedParams } from '@sre/types/LLM.types';
4
+ import { APIKeySource, ILLMRequestFuncParams, TLLMChatResponse, TLLMEvent, TLLMPreparedParams } from '@sre/types/LLM.types';
5
5
  import { Logger } from '@sre/helpers/Log.helper';
6
6
  import { delay } from '@sre/utils/index';
7
7
  import { hookAsync } from '@sre/Core/HookService';
@@ -54,13 +54,13 @@ export class EchoConnector extends LLMConnector {
54
54
  const isLastChunk = i === chunks.length - 1;
55
55
  // Add space between chunks except for the last one to avoid trailing space in file URLs
56
56
  const delta = { content: chunks[i] + (isLastChunk ? '' : ' ') };
57
- emitter.emit('data', delta);
58
- emitter.emit('content', delta.content);
57
+ emitter.emit(TLLMEvent.Data, delta);
58
+ emitter.emit(TLLMEvent.Content, delta.content);
59
59
  }
60
60
 
61
61
  // Emit end event after all chunks are processed
62
62
  setTimeout(() => {
63
- emitter.emit('end', [], []); // Empty arrays for toolsData and usage_data
63
+ emitter.emit(TLLMEvent.End, [], [], 'stop'); // Empty arrays for toolsData and usage_data, with finishReason
64
64
  }, 100);
65
65
  })();
66
66