@smythos/sre 1.6.14 → 1.7.5

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 (115) hide show
  1. package/CHANGELOG +15 -0
  2. package/dist/index.js +66 -58
  3. package/dist/index.js.map +1 -1
  4. package/dist/types/Components/APIEndpoint.class.d.ts +2 -8
  5. package/dist/types/Components/Component.class.d.ts +9 -0
  6. package/dist/types/Components/Triggers/Gmail.trigger.d.ts +0 -17
  7. package/dist/types/Components/Triggers/JobScheduler.trigger.d.ts +10 -0
  8. package/dist/types/Components/Triggers/Trigger.class.d.ts +11 -0
  9. package/dist/types/Components/index.d.ts +6 -0
  10. package/dist/types/Core/Connector.class.d.ts +1 -0
  11. package/dist/types/Core/ConnectorsService.d.ts +2 -0
  12. package/dist/types/Core/HookService.d.ts +1 -1
  13. package/dist/types/helpers/BinaryInput.helper.d.ts +1 -1
  14. package/dist/types/helpers/Conversation.helper.d.ts +2 -0
  15. package/dist/types/helpers/Crypto.helper.d.ts +8 -0
  16. package/dist/types/helpers/LocalCache.helper.d.ts +18 -0
  17. package/dist/types/helpers/TemplateString.helper.d.ts +2 -1
  18. package/dist/types/index.d.ts +13 -0
  19. package/dist/types/subsystems/AgentManager/Agent.class.d.ts +4 -2
  20. package/dist/types/subsystems/AgentManager/AgentData.service/AgentDataConnector.d.ts +13 -0
  21. package/dist/types/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.d.ts +1 -4
  22. package/dist/types/subsystems/AgentManager/Scheduler.service/Job.class.d.ts +29 -6
  23. package/dist/types/subsystems/AgentManager/Scheduler.service/SchedulerConnector.d.ts +11 -3
  24. package/dist/types/subsystems/AgentManager/Scheduler.service/connectors/LocalScheduler.class.d.ts +31 -7
  25. package/dist/types/subsystems/IO/VectorDB.service/VectorDBConnector.d.ts +4 -4
  26. package/dist/types/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.d.ts +2 -2
  27. package/dist/types/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.d.ts +2 -2
  28. package/dist/types/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.d.ts +2 -2
  29. package/dist/types/subsystems/IO/VectorDB.service/embed/BaseEmbedding.d.ts +16 -9
  30. package/dist/types/subsystems/IO/VectorDB.service/embed/index.d.ts +4 -1
  31. package/dist/types/subsystems/LLMManager/LLM.inference.d.ts +36 -2
  32. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.d.ts +2 -5
  33. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.d.ts +3 -6
  34. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.d.ts +7 -0
  35. package/dist/types/subsystems/LLMManager/LLM.service/connectors/xAI.class.d.ts +2 -5
  36. package/dist/types/types/Agent.types.d.ts +1 -0
  37. package/dist/types/types/LLM.types.d.ts +56 -36
  38. package/dist/types/types/SRE.types.d.ts +4 -1
  39. package/dist/types/types/VectorDB.types.d.ts +6 -3
  40. package/dist/types/utils/string.utils.d.ts +0 -4
  41. package/package.json +6 -2
  42. package/src/Components/APICall/OAuth.helper.ts +30 -35
  43. package/src/Components/APIEndpoint.class.ts +25 -6
  44. package/src/Components/Classifier.class.ts +8 -2
  45. package/src/Components/Component.class.ts +11 -0
  46. package/src/Components/GenAILLM.class.ts +11 -7
  47. package/src/Components/LLMAssistant.class.ts +12 -3
  48. package/src/Components/ScrapflyWebScrape.class.ts +8 -1
  49. package/src/Components/TavilyWebSearch.class.ts +4 -1
  50. package/src/Components/Triggers/Gmail.trigger.ts +282 -0
  51. package/src/Components/Triggers/JobScheduler.trigger.ts +45 -0
  52. package/src/Components/Triggers/README.md +3 -0
  53. package/src/Components/Triggers/Trigger.class.ts +101 -0
  54. package/src/Components/Triggers/WhatsApp.trigger.ts +219 -0
  55. package/src/Components/index.ts +8 -0
  56. package/src/Core/AgentProcess.helper.ts +4 -6
  57. package/src/Core/Connector.class.ts +11 -3
  58. package/src/Core/ConnectorsService.ts +5 -0
  59. package/src/Core/ExternalEventsReceiver.ts +317 -0
  60. package/src/Core/HookService.ts +20 -6
  61. package/src/Core/SmythRuntime.class.ts +20 -2
  62. package/src/Core/SystemEvents.ts +17 -0
  63. package/src/Core/boot.ts +2 -0
  64. package/src/helpers/BinaryInput.helper.ts +8 -8
  65. package/src/helpers/Conversation.helper.ts +46 -12
  66. package/src/helpers/Crypto.helper.ts +28 -0
  67. package/src/helpers/LocalCache.helper.ts +18 -0
  68. package/src/helpers/TemplateString.helper.ts +20 -9
  69. package/src/index.ts +13 -0
  70. package/src/index.ts.bak +13 -0
  71. package/src/subsystems/AGENTS.md +594 -0
  72. package/src/subsystems/AgentManager/Agent.class.ts +73 -21
  73. package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +30 -6
  74. package/src/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.ts +2 -2
  75. package/src/subsystems/AgentManager/AgentLogger.class.ts +1 -1
  76. package/src/subsystems/AgentManager/AgentRuntime.class.ts +34 -5
  77. package/src/subsystems/AgentManager/Scheduler.service/Job.class.ts +414 -0
  78. package/src/subsystems/AgentManager/Scheduler.service/Schedule.class.ts +200 -0
  79. package/src/subsystems/AgentManager/Scheduler.service/SchedulerConnector.ts +200 -0
  80. package/src/subsystems/AgentManager/Scheduler.service/connectors/LocalScheduler.class.ts +767 -0
  81. package/src/subsystems/AgentManager/Scheduler.service/index.ts +11 -0
  82. package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +15 -4
  83. package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +32 -11
  84. package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +27 -10
  85. package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +25 -9
  86. package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +182 -12
  87. package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +1 -1
  88. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +1 -1
  89. package/src/subsystems/IO/VectorDB.service/embed/index.ts +12 -2
  90. package/src/subsystems/LLMManager/LLM.inference.ts +76 -17
  91. package/src/subsystems/LLMManager/LLM.service/LLMCredentials.helper.ts +61 -2
  92. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +3 -0
  93. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +3 -1
  94. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +5 -1
  95. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +247 -56
  96. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +3 -0
  97. package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +28 -21
  98. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +3 -0
  99. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +121 -33
  100. package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +38 -27
  101. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +3 -2
  102. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +117 -20
  103. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +3 -0
  104. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +3 -8
  105. package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +4 -1
  106. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +12 -0
  107. package/src/subsystems/MemoryManager/LLMContext.ts +3 -8
  108. package/src/subsystems/MemoryManager/RuntimeContext.ts +10 -9
  109. package/src/subsystems/Security/Credentials/Credentials.class.ts +1 -0
  110. package/src/subsystems/Security/Credentials/ManagedOAuth2Credentials.class.ts +106 -0
  111. package/src/types/Agent.types.ts +1 -0
  112. package/src/types/LLM.types.ts +68 -40
  113. package/src/types/SRE.types.ts +3 -0
  114. package/src/types/VectorDB.types.ts +7 -3
  115. package/src/utils/string.utils.ts +193 -191
@@ -3,12 +3,7 @@ import path from 'path';
3
3
  import EventEmitter from 'events';
4
4
  import fs from 'fs';
5
5
 
6
- import {
7
- GoogleGenAI,
8
- FunctionCallingConfigMode,
9
- FileState,
10
- type GenerateContentResponseUsageMetadata,
11
- } from '@google/genai/node';
6
+ import { GoogleGenAI, FunctionCallingConfigMode, FileState, type GenerateContentResponseUsageMetadata } from '@google/genai/node';
12
7
 
13
8
  import { JSON_RESPONSE_INSTRUCTION, BUILT_IN_MODEL_PREFIX } from '@sre/constants';
14
9
  import { BinaryInput } from '@sre/helpers/BinaryInput.helper';
@@ -40,6 +35,7 @@ import { SUPPORTED_MIME_TYPES_MAP } from '@sre/constants';
40
35
  import { Logger } from '@sre/helpers/Log.helper';
41
36
 
42
37
  import { LLMConnector } from '../LLMConnector';
38
+ import { hookAsync } from '@sre/Core/HookService';
43
39
 
44
40
  const logger = Logger('GoogleAIConnector');
45
41
 
@@ -90,6 +86,7 @@ export class GoogleAIConnector extends LLMConnector {
90
86
  return new GoogleGenAI({ apiKey });
91
87
  }
92
88
 
89
+ @hookAsync('LLMConnector.request')
93
90
  protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
94
91
  try {
95
92
  logger.debug(`request ${this.name}`, acRequest.candidate);
@@ -160,6 +157,7 @@ export class GoogleAIConnector extends LLMConnector {
160
157
  }
161
158
  }
162
159
 
160
+ @hookAsync('LLMConnector.streamRequest')
163
161
  protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
164
162
  logger.debug(`streamRequest ${this.name}`, acRequest.candidate);
165
163
  const emitter = new EventEmitter();
@@ -436,9 +434,10 @@ export class GoogleAIConnector extends LLMConnector {
436
434
  return body;
437
435
  }
438
436
 
439
- private normalizePrompt(
440
- prompt: TGoogleAIRequestBody['messages'] | TGoogleAIRequestBody['contents']
441
- ): { contents: any; config?: Record<string, any> } {
437
+ private normalizePrompt(prompt: TGoogleAIRequestBody['messages'] | TGoogleAIRequestBody['contents']): {
438
+ contents: any;
439
+ config?: Record<string, any>;
440
+ } {
442
441
  if (prompt == null) {
443
442
  return { contents: '' };
444
443
  }
@@ -627,87 +626,279 @@ export class GoogleAIConnector extends LLMConnector {
627
626
  }): TLLMToolResultMessageBlock[] {
628
627
  const messageBlocks: TLLMToolResultMessageBlock[] = [];
629
628
 
630
- if (messageBlock) {
631
- const content = [];
632
- if (typeof messageBlock.content === 'string') {
633
- content.push({ text: messageBlock.content });
634
- } else if (Array.isArray(messageBlock.content)) {
635
- content.push(...messageBlock.content);
629
+ const parseFunctionArgs = (args: unknown) => {
630
+ if (typeof args === 'string') {
631
+ try {
632
+ return JSON.parse(args);
633
+ } catch {
634
+ return args;
635
+ }
636
636
  }
637
+ return args ?? {};
638
+ };
639
+
640
+ const parseFunctionResponse = (response: unknown): any => {
641
+ if (typeof response === 'string') {
642
+ try {
643
+ const parsed = JSON.parse(response);
644
+ if (typeof parsed === 'string' && parsed !== response) {
645
+ return parseFunctionResponse(parsed);
646
+ }
647
+ return parsed;
648
+ } catch {
649
+ return response;
650
+ }
651
+ }
652
+ return response ?? {};
653
+ };
637
654
 
638
- if (messageBlock.parts) {
639
- const functionCalls = messageBlock.parts.filter((part) => part.functionCall);
640
- if (functionCalls.length > 0) {
641
- content.push(
642
- ...functionCalls.map((call) => ({
655
+ if (messageBlock) {
656
+ const content: any[] = [];
657
+
658
+ if (Array.isArray(messageBlock.parts) && messageBlock.parts.length > 0) {
659
+ for (const part of messageBlock.parts) {
660
+ if (!part) continue;
661
+
662
+ if (typeof part.text === 'string' && part.text.trim()) {
663
+ content.push({ text: part.text.trim() });
664
+ continue;
665
+ }
666
+
667
+ if (part.functionCall) {
668
+ content.push({
643
669
  functionCall: {
644
- name: call.functionCall.name,
645
- args: JSON.parse(call.functionCall.args),
670
+ name: part.functionCall.name,
671
+ args: parseFunctionArgs(part.functionCall.args),
646
672
  },
647
- }))
648
- );
673
+ });
674
+ continue;
675
+ }
676
+
677
+ if (part.functionResponse) {
678
+ content.push({
679
+ functionResponse: {
680
+ name: part.functionResponse.name,
681
+ response: parseFunctionResponse(part.functionResponse.response),
682
+ },
683
+ });
684
+ continue;
685
+ }
686
+
687
+ if ((part as any).inlineData) {
688
+ content.push({ inlineData: (part as any).inlineData });
689
+ }
690
+ }
691
+ } else {
692
+ if (typeof messageBlock.content === 'string' && messageBlock.content.trim()) {
693
+ content.push({ text: messageBlock.content.trim() });
694
+ } else if (Array.isArray(messageBlock.content) && messageBlock.content.length > 0) {
695
+ content.push(...messageBlock.content);
696
+ }
697
+ }
698
+
699
+ const hasFunctionCall = content.some((part) => part.functionCall);
700
+ if (!hasFunctionCall && toolsData.length > 0) {
701
+ toolsData.forEach((toolCall) => {
702
+ content.push({
703
+ functionCall: {
704
+ name: toolCall.name,
705
+ args: parseFunctionArgs(toolCall.arguments),
706
+ },
707
+ });
708
+ });
709
+ }
710
+
711
+ if (content.length > 0) {
712
+ let role = messageBlock.role;
713
+ if (role === TLLMMessageRole.Assistant) {
714
+ role = TLLMMessageRole.Model;
649
715
  }
716
+
717
+ messageBlocks.push({
718
+ role,
719
+ parts: content,
720
+ });
650
721
  }
722
+ }
723
+
724
+ const functionResponseParts = toolsData
725
+ .filter((toolData) => toolData.result !== undefined)
726
+ .map((toolData) => ({
727
+ functionResponse: {
728
+ name: toolData.name,
729
+ response: parseFunctionResponse(toolData.result),
730
+ },
731
+ }));
651
732
 
733
+ if (functionResponseParts.length > 0) {
652
734
  messageBlocks.push({
653
- role: messageBlock.role,
654
- parts: content,
735
+ role: TLLMMessageRole.Function,
736
+ parts: functionResponseParts,
655
737
  });
656
738
  }
657
739
 
658
- const transformedToolsData = toolsData.map(
659
- (toolData): TLLMToolResultMessageBlock => ({
660
- role: TLLMMessageRole.User,
661
- parts: [
662
- {
663
- functionResponse: {
664
- name: toolData.name,
665
- response: {
666
- name: toolData.name,
667
- content: typeof toolData.result === 'string' ? toolData.result : JSON.stringify(toolData.result),
668
- },
669
- },
670
- },
671
- ],
672
- })
673
- );
674
-
675
- return [...messageBlocks, ...transformedToolsData];
740
+ return messageBlocks;
676
741
  }
677
742
 
678
743
  public getConsistentMessages(messages: TLLMMessageBlock[]): TLLMMessageBlock[] {
679
744
  const _messages = LLMHelper.removeDuplicateUserMessages(messages);
680
745
 
681
746
  return _messages.map((message) => {
682
- const _message = { ...message };
683
- let textContent = '';
747
+ const _message: TLLMMessageBlock = { ...message };
748
+
749
+ const parseFunctionArgs = (args: unknown) => {
750
+ if (typeof args === 'string') {
751
+ try {
752
+ return JSON.parse(args);
753
+ } catch {
754
+ return args;
755
+ }
756
+ }
757
+
758
+ return args ?? {};
759
+ };
760
+
761
+ const parseFunctionResponse = (response: unknown) => {
762
+ if (typeof response === 'string') {
763
+ try {
764
+ return JSON.parse(response);
765
+ } catch {
766
+ return response;
767
+ }
768
+ }
769
+
770
+ return response;
771
+ };
772
+
773
+ const pushTextPart = (parts: any[], text?: string) => {
774
+ const value = typeof text === 'string' && text.trim() ? text : undefined;
775
+ if (value) {
776
+ parts.push({ text: value });
777
+ }
778
+ };
779
+
780
+ const normalizedParts: any[] = [];
684
781
 
685
782
  // Map roles to valid Google AI roles
686
783
  switch (_message.role) {
687
784
  case TLLMMessageRole.Assistant:
688
785
  case TLLMMessageRole.System:
786
+ case TLLMMessageRole.Model:
689
787
  _message.role = TLLMMessageRole.Model;
690
788
  break;
789
+ case TLLMMessageRole.Function:
790
+ case TLLMMessageRole.Tool:
791
+ _message.role = TLLMMessageRole.Function;
792
+ break;
691
793
  case TLLMMessageRole.User:
692
- // User role is already valid
693
794
  break;
694
795
  default:
695
- _message.role = TLLMMessageRole.User; // Default to user for unknown roles
796
+ _message.role = TLLMMessageRole.User;
696
797
  }
697
798
 
698
- // * empty text causes error that's why we added '...'
799
+ if (Array.isArray(message?.parts)) {
800
+ for (const part of message.parts) {
801
+ if (!part) continue;
802
+
803
+ const normalizedPart: any = { ...part };
804
+
805
+ if (typeof normalizedPart.text === 'string') {
806
+ normalizedPart.text = normalizedPart.text.trim() || '...';
807
+ }
808
+
809
+ if (part.functionCall) {
810
+ normalizedPart.functionCall = {
811
+ name: part.functionCall.name,
812
+ args: parseFunctionArgs(part.functionCall.args),
813
+ };
814
+ }
815
+
816
+ if (part.functionResponse) {
817
+ normalizedPart.functionResponse = {
818
+ name: part.functionResponse.name,
819
+ response: parseFunctionResponse(part.functionResponse.response),
820
+ };
821
+ }
822
+
823
+ const hasMeaningfulContent = Object.values(normalizedPart).some((value) => value !== undefined && value !== null && value !== '');
824
+
825
+ if (hasMeaningfulContent) {
826
+ normalizedParts.push(normalizedPart);
827
+ }
828
+ }
829
+ }
830
+
831
+ if (!normalizedParts.length && Array.isArray(message?.content)) {
832
+ for (const contentPart of message.content) {
833
+ if (!contentPart) continue;
834
+
835
+ if (typeof contentPart === 'string') {
836
+ pushTextPart(normalizedParts, contentPart);
837
+ } else if (typeof contentPart === 'object') {
838
+ if ('text' in contentPart && typeof contentPart.text === 'string') {
839
+ pushTextPart(normalizedParts, contentPart.text);
840
+ } else if ('functionCall' in contentPart && (contentPart as any).functionCall) {
841
+ const functionCallPart = (contentPart as any).functionCall;
842
+ normalizedParts.push({
843
+ functionCall: {
844
+ name: functionCallPart.name,
845
+ args: parseFunctionArgs(functionCallPart.args),
846
+ },
847
+ });
848
+ } else if ('functionResponse' in contentPart && (contentPart as any).functionResponse) {
849
+ const functionResponsePart = (contentPart as any).functionResponse;
850
+ normalizedParts.push({
851
+ functionResponse: {
852
+ name: functionResponsePart.name,
853
+ response: parseFunctionResponse(functionResponsePart.response),
854
+ },
855
+ });
856
+ } else {
857
+ const fallbackText = typeof (contentPart as any)?.toString === 'function' ? (contentPart as any).toString() : '';
858
+ if (fallbackText && fallbackText !== '[object Object]') {
859
+ pushTextPart(normalizedParts, fallbackText);
860
+ }
861
+ }
862
+ }
863
+ }
864
+ }
865
+
866
+ if (!normalizedParts.length) {
867
+ if (typeof message?.content === 'string') {
868
+ pushTextPart(normalizedParts, message.content);
869
+ } else if (message?.content && typeof message.content === 'object') {
870
+ if ('text' in (message.content as any)) {
871
+ pushTextPart(normalizedParts, (message.content as any).text);
872
+ } else {
873
+ const fallbackText = typeof (message.content as any)?.toString === 'function' ? (message.content as any).toString() : '';
874
+ if (fallbackText && fallbackText !== '[object Object]') {
875
+ pushTextPart(normalizedParts, fallbackText);
876
+ }
877
+ }
878
+ }
879
+ }
880
+
881
+ if (Array.isArray(message?.tool_calls) && message.tool_calls.length > 0) {
882
+ for (const toolCall of message.tool_calls) {
883
+ if (!toolCall?.function?.name) continue;
884
+
885
+ normalizedParts.push({
886
+ functionCall: {
887
+ name: toolCall.function.name,
888
+ args: parseFunctionArgs(toolCall.function.arguments),
889
+ },
890
+ });
891
+ }
892
+ }
699
893
 
700
- if (_message?.parts) {
701
- textContent = _message.parts.map((textBlock) => textBlock?.text || '...').join(' ');
702
- } else if (Array.isArray(_message?.content)) {
703
- textContent = _message.content.map((textBlock) => textBlock?.text || '...').join(' ');
704
- } else if (_message?.content) {
705
- textContent = (_message.content as string) || '...';
894
+ if (!normalizedParts.length) {
895
+ normalizedParts.push({ text: '...' });
706
896
  }
707
897
 
708
- _message.parts = [{ text: textContent || '...' }];
898
+ _message.parts = normalizedParts as any;
709
899
 
710
900
  delete _message.content; // Remove content to avoid error
901
+ delete (_message as any).tool_calls;
711
902
 
712
903
  return _message;
713
904
  });
@@ -20,6 +20,7 @@ import { LLMHelper } from '@sre/LLMManager/LLM.helper';
20
20
  import { LLMConnector } from '../LLMConnector';
21
21
  import { SystemEvents } from '@sre/Core/SystemEvents';
22
22
  import { Logger } from '@sre/helpers/Log.helper';
23
+ import { hookAsync } from '@sre/Core/HookService';
23
24
 
24
25
  const logger = Logger('GroqConnector');
25
26
 
@@ -50,6 +51,7 @@ export class GroqConnector extends LLMConnector {
50
51
  return new Groq({ apiKey });
51
52
  }
52
53
 
54
+ @hookAsync('LLMConnector.request')
53
55
  protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
54
56
  try {
55
57
  logger.debug(`request ${this.name}`, acRequest.candidate);
@@ -95,6 +97,7 @@ export class GroqConnector extends LLMConnector {
95
97
  }
96
98
  }
97
99
 
100
+ @hookAsync('LLMConnector.streamRequest')
98
101
  protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
99
102
  try {
100
103
  logger.debug(`streamRequest ${this.name}`, acRequest.candidate);
@@ -1,4 +1,4 @@
1
- import { Ollama, ChatResponse } from 'ollama';
1
+ import { Ollama, ChatResponse, type ChatRequest } from 'ollama';
2
2
  import EventEmitter from 'events';
3
3
 
4
4
  import { JSON_RESPONSE_INSTRUCTION, BUILT_IN_MODEL_PREFIX } from '@sre/constants';
@@ -14,12 +14,14 @@ import {
14
14
  TLLMPreparedParams,
15
15
  TLLMToolResultMessageBlock,
16
16
  TLLMRequestBody,
17
+ BasicCredentials,
17
18
  } from '@sre/types/LLM.types';
18
19
  import { LLMHelper } from '@sre/LLMManager/LLM.helper';
19
20
 
20
21
  import { LLMConnector } from '../LLMConnector';
21
22
  import { SystemEvents } from '@sre/Core/SystemEvents';
22
23
  import { Logger } from '@sre/helpers/Log.helper';
24
+ import { hookAsync } from '@sre/Core/HookService';
23
25
 
24
26
  const logger = Logger('OllamaConnector');
25
27
 
@@ -44,33 +46,37 @@ export class OllamaConnector extends LLMConnector {
44
46
  // Extract baseURL and sanitize it for Ollama SDK
45
47
  let host = 'http://localhost:11434';
46
48
 
47
- if (context.modelInfo.baseURL) {
48
- // Handle baseURL that might include /api/ suffix
49
- const baseURL = context.modelInfo.baseURL;
50
- if (baseURL.endsWith('/api/')) {
51
- // Remove /api/ suffix to get the root host
52
- host = baseURL.replace(/\/api\/$/, '');
53
- } else if (baseURL.endsWith('/api')) {
54
- // Remove /api suffix
55
- host = baseURL.replace(/\/api$/, '');
56
- } else {
57
- host = baseURL;
58
- }
49
+ const apiKey = (context.credentials as BasicCredentials)?.apiKey;
50
+ const baseURL = context?.modelInfo?.baseURL;
51
+
52
+ if (baseURL) {
53
+ // Extract base URL (origin) using URL class
54
+ const url = new URL(baseURL);
55
+ host = url.origin;
56
+ }
57
+
58
+ const config: { host: string; headers?: { Authorization?: string } } = { host };
59
+
60
+ if (apiKey) {
61
+ config.headers = {
62
+ Authorization: `Bearer ${apiKey}`,
63
+ };
59
64
  }
60
65
 
61
66
  // No API key validation required for Ollama (local by default)
62
- return new Ollama({ host });
67
+ return new Ollama(config);
63
68
  }
64
69
 
70
+ @hookAsync('LLMConnector.request')
65
71
  protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
66
72
  try {
67
73
  logger.debug(`request ${this.name}`, acRequest.candidate);
68
74
  const ollama = this.getClient(context);
69
75
 
70
- const result = await ollama.chat({
76
+ const result = (await ollama.chat({
71
77
  ...body,
72
78
  stream: false,
73
- }) as unknown as ChatResponse;
79
+ })) as unknown as ChatResponse;
74
80
 
75
81
  const message = result.message;
76
82
  const finishReason = result.done_reason || 'stop';
@@ -117,6 +123,7 @@ export class OllamaConnector extends LLMConnector {
117
123
  }
118
124
  }
119
125
 
126
+ @hookAsync('LLMConnector.streamRequest')
120
127
  protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
121
128
  try {
122
129
  logger.debug(`streamRequest ${this.name}`, acRequest.candidate);
@@ -124,10 +131,10 @@ export class OllamaConnector extends LLMConnector {
124
131
  const usage_data = [];
125
132
 
126
133
  const ollama = this.getClient(context);
127
- const stream = await ollama.chat({
134
+ const stream = (await ollama.chat({
128
135
  ...body,
129
136
  stream: true,
130
- }) as AsyncIterable<ChatResponse>;
137
+ })) as AsyncIterable<ChatResponse>;
131
138
 
132
139
  let toolsData: ToolData[] = [];
133
140
  let fullContent = '';
@@ -159,7 +166,7 @@ export class OllamaConnector extends LLMConnector {
159
166
  toolsData[index].arguments += toolCall.function.arguments;
160
167
  } else {
161
168
  // For object arguments, merge them properly
162
- toolsData[index].arguments = { ...toolsData[index].arguments as any, ...toolCall.function?.arguments };
169
+ toolsData[index].arguments = { ...(toolsData[index].arguments as any), ...toolCall.function?.arguments };
163
170
  }
164
171
  }
165
172
  });
@@ -237,7 +244,7 @@ export class OllamaConnector extends LLMConnector {
237
244
 
238
245
  // Handle tools
239
246
  if (params.toolsConfig?.tools) {
240
- body.tools = params.toolsConfig.tools.map(tool => ({
247
+ body.tools = params.toolsConfig.tools.map((tool) => ({
241
248
  type: 'function',
242
249
  function: {
243
250
  name: tool.function.name,
@@ -359,4 +366,4 @@ export class OllamaConnector extends LLMConnector {
359
366
  return _message;
360
367
  });
361
368
  }
362
- }
369
+ }
@@ -20,6 +20,7 @@ import { LLMHelper } from '@sre/LLMManager/LLM.helper';
20
20
  import { LLMConnector } from '../LLMConnector';
21
21
  import { SystemEvents } from '@sre/Core/SystemEvents';
22
22
  import { Logger } from '@sre/helpers/Log.helper';
23
+ import { hookAsync } from '@sre/Core/HookService';
23
24
 
24
25
  const logger = Logger('PerplexityConnector');
25
26
 
@@ -58,6 +59,7 @@ export class PerplexityConnector extends LLMConnector {
58
59
  });
59
60
  }
60
61
 
62
+ @hookAsync('LLMConnector.request')
61
63
  protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
62
64
  try {
63
65
  logger.debug(`request ${this.name}`, acRequest.candidate);
@@ -89,6 +91,7 @@ export class PerplexityConnector extends LLMConnector {
89
91
  }
90
92
  }
91
93
 
94
+ @hookAsync('LLMConnector.streamRequest')
92
95
  protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
93
96
  //throw new Error('Multimodal request is not supported for Perplexity.');
94
97
  //fallback to chatRequest