@smythos/sre 1.6.1 → 1.6.8
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/CHANGELOG +111 -111
- package/LICENSE +18 -18
- package/README.md +135 -135
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/types/subsystems/LLMManager/ModelsProvider.service/connectors/SmythModelsProvider.class.d.ts +39 -0
- package/package.json +1 -1
- package/src/Components/APICall/APICall.class.ts +161 -161
- package/src/Components/APICall/AccessTokenManager.ts +166 -166
- package/src/Components/APICall/ArrayBufferResponse.helper.ts +58 -58
- package/src/Components/APICall/OAuth.helper.ts +447 -447
- package/src/Components/APICall/mimeTypeCategories.ts +46 -46
- package/src/Components/APICall/parseData.ts +167 -167
- package/src/Components/APICall/parseHeaders.ts +41 -41
- package/src/Components/APICall/parseProxy.ts +68 -68
- package/src/Components/APICall/parseUrl.ts +91 -91
- package/src/Components/APIEndpoint.class.ts +234 -234
- package/src/Components/APIOutput.class.ts +58 -58
- package/src/Components/AgentPlugin.class.ts +102 -102
- package/src/Components/Async.class.ts +155 -155
- package/src/Components/Await.class.ts +90 -90
- package/src/Components/Classifier.class.ts +158 -158
- package/src/Components/Component.class.ts +147 -147
- package/src/Components/ComponentHost.class.ts +38 -38
- package/src/Components/DataSourceCleaner.class.ts +92 -92
- package/src/Components/DataSourceIndexer.class.ts +181 -181
- package/src/Components/DataSourceLookup.class.ts +161 -161
- package/src/Components/ECMASandbox.class.ts +72 -72
- package/src/Components/FEncDec.class.ts +29 -29
- package/src/Components/FHash.class.ts +33 -33
- package/src/Components/FSign.class.ts +80 -80
- package/src/Components/FSleep.class.ts +25 -25
- package/src/Components/FTimestamp.class.ts +66 -66
- package/src/Components/FileStore.class.ts +78 -78
- package/src/Components/ForEach.class.ts +97 -97
- package/src/Components/GPTPlugin.class.ts +70 -70
- package/src/Components/GenAILLM.class.ts +586 -586
- package/src/Components/HuggingFace.class.ts +313 -313
- package/src/Components/Image/imageSettings.config.ts +70 -70
- package/src/Components/ImageGenerator.class.ts +483 -483
- package/src/Components/JSONFilter.class.ts +54 -54
- package/src/Components/LLMAssistant.class.ts +213 -213
- package/src/Components/LogicAND.class.ts +28 -28
- package/src/Components/LogicAtLeast.class.ts +85 -85
- package/src/Components/LogicAtMost.class.ts +86 -86
- package/src/Components/LogicOR.class.ts +29 -29
- package/src/Components/LogicXOR.class.ts +34 -34
- package/src/Components/MCPClient.class.ts +137 -137
- package/src/Components/MemoryDeleteKeyVal.class.ts +70 -70
- package/src/Components/MemoryReadKeyVal.class.ts +67 -67
- package/src/Components/MemoryWriteKeyVal.class.ts +62 -62
- package/src/Components/MemoryWriteObject.class.ts +97 -97
- package/src/Components/MultimodalLLM.class.ts +128 -128
- package/src/Components/OpenAPI.class.ts +72 -72
- package/src/Components/PromptGenerator.class.ts +122 -122
- package/src/Components/ScrapflyWebScrape.class.ts +183 -183
- package/src/Components/ServerlessCode.class.ts +123 -123
- package/src/Components/TavilyWebSearch.class.ts +103 -103
- package/src/Components/VisionLLM.class.ts +104 -104
- package/src/Components/ZapierAction.class.ts +127 -127
- package/src/Components/index.ts +97 -97
- package/src/Core/AgentProcess.helper.ts +240 -240
- package/src/Core/Connector.class.ts +123 -123
- package/src/Core/ConnectorsService.ts +197 -197
- package/src/Core/DummyConnector.ts +49 -49
- package/src/Core/HookService.ts +105 -105
- package/src/Core/SmythRuntime.class.ts +241 -241
- package/src/Core/SystemEvents.ts +16 -16
- package/src/Core/boot.ts +56 -56
- package/src/config.ts +15 -15
- package/src/constants.ts +126 -126
- package/src/data/hugging-face.params.json +579 -579
- package/src/helpers/AWSLambdaCode.helper.ts +624 -599
- package/src/helpers/BinaryInput.helper.ts +331 -331
- package/src/helpers/Conversation.helper.ts +1157 -1157
- package/src/helpers/ECMASandbox.helper.ts +64 -64
- package/src/helpers/JsonContent.helper.ts +97 -97
- package/src/helpers/LocalCache.helper.ts +97 -97
- package/src/helpers/Log.helper.ts +274 -274
- package/src/helpers/OpenApiParser.helper.ts +150 -150
- package/src/helpers/S3Cache.helper.ts +147 -147
- package/src/helpers/SmythURI.helper.ts +5 -5
- package/src/helpers/Sysconfig.helper.ts +95 -95
- package/src/helpers/TemplateString.helper.ts +243 -243
- package/src/helpers/TypeChecker.helper.ts +329 -329
- package/src/index.ts +198 -198
- package/src/index.ts.bak +198 -198
- package/src/subsystems/AgentManager/Agent.class.ts +1114 -1114
- package/src/subsystems/AgentManager/Agent.helper.ts +3 -3
- package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +230 -230
- package/src/subsystems/AgentManager/AgentData.service/connectors/CLIAgentDataConnector.class.ts +66 -66
- package/src/subsystems/AgentManager/AgentData.service/connectors/LocalAgentDataConnector.class.ts +145 -145
- package/src/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.ts +39 -39
- package/src/subsystems/AgentManager/AgentData.service/index.ts +18 -18
- package/src/subsystems/AgentManager/AgentLogger.class.ts +301 -301
- package/src/subsystems/AgentManager/AgentRequest.class.ts +51 -51
- package/src/subsystems/AgentManager/AgentRuntime.class.ts +557 -557
- package/src/subsystems/AgentManager/AgentSSE.class.ts +101 -101
- package/src/subsystems/AgentManager/AgentSettings.class.ts +52 -52
- package/src/subsystems/AgentManager/Component.service/ComponentConnector.ts +32 -32
- package/src/subsystems/AgentManager/Component.service/connectors/LocalComponentConnector.class.ts +60 -60
- package/src/subsystems/AgentManager/Component.service/index.ts +11 -11
- package/src/subsystems/AgentManager/EmbodimentSettings.class.ts +47 -47
- package/src/subsystems/AgentManager/ForkedAgent.class.ts +154 -154
- package/src/subsystems/AgentManager/OSResourceMonitor.ts +77 -77
- package/src/subsystems/ComputeManager/Code.service/CodeConnector.ts +98 -98
- package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +171 -172
- package/src/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.ts +131 -131
- package/src/subsystems/ComputeManager/Code.service/index.ts +13 -13
- package/src/subsystems/IO/CLI.service/CLIConnector.ts +47 -47
- package/src/subsystems/IO/CLI.service/index.ts +9 -9
- package/src/subsystems/IO/Log.service/LogConnector.ts +32 -32
- package/src/subsystems/IO/Log.service/connectors/ConsoleLog.class.ts +28 -28
- package/src/subsystems/IO/Log.service/index.ts +13 -13
- package/src/subsystems/IO/NKV.service/NKVConnector.ts +43 -43
- package/src/subsystems/IO/NKV.service/connectors/NKVLocalStorage.class.ts +234 -234
- package/src/subsystems/IO/NKV.service/connectors/NKVRAM.class.ts +204 -204
- package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +182 -182
- package/src/subsystems/IO/NKV.service/index.ts +14 -14
- package/src/subsystems/IO/Router.service/RouterConnector.ts +21 -21
- package/src/subsystems/IO/Router.service/connectors/ExpressRouter.class.ts +48 -48
- package/src/subsystems/IO/Router.service/connectors/NullRouter.class.ts +40 -40
- package/src/subsystems/IO/Router.service/index.ts +11 -11
- package/src/subsystems/IO/Storage.service/SmythFS.class.ts +488 -488
- package/src/subsystems/IO/Storage.service/StorageConnector.ts +66 -66
- package/src/subsystems/IO/Storage.service/connectors/LocalStorage.class.ts +327 -327
- package/src/subsystems/IO/Storage.service/connectors/S3Storage.class.ts +482 -482
- package/src/subsystems/IO/Storage.service/index.ts +13 -13
- package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +108 -108
- package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +465 -465
- package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +387 -387
- package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +408 -408
- package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +107 -107
- package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +118 -118
- package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +109 -109
- package/src/subsystems/IO/VectorDB.service/embed/index.ts +26 -26
- package/src/subsystems/IO/VectorDB.service/index.ts +14 -14
- package/src/subsystems/LLMManager/LLM.helper.ts +251 -251
- package/src/subsystems/LLMManager/LLM.inference.ts +345 -345
- package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +492 -492
- package/src/subsystems/LLMManager/LLM.service/LLMCredentials.helper.ts +171 -171
- package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +666 -666
- package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +407 -407
- package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +92 -92
- package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +983 -983
- package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +319 -319
- package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +361 -361
- package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +257 -257
- package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +430 -430
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +503 -503
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +524 -524
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.ts +100 -100
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.ts +81 -81
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +1145 -1145
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.ts +13 -13
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.ts +4 -4
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.ts +11 -11
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/types.ts +32 -32
- package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +478 -478
- package/src/subsystems/LLMManager/LLM.service/index.ts +47 -47
- package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +303 -303
- package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +271 -271
- package/src/subsystems/LLMManager/ModelsProvider.service/index.ts +11 -11
- package/src/subsystems/LLMManager/custom-models.ts +854 -854
- package/src/subsystems/LLMManager/models.ts +2540 -2540
- package/src/subsystems/LLMManager/paramMappings.ts +69 -69
- package/src/subsystems/MemoryManager/Cache.service/CacheConnector.ts +86 -86
- package/src/subsystems/MemoryManager/Cache.service/connectors/LocalStorageCache.class.ts +297 -297
- package/src/subsystems/MemoryManager/Cache.service/connectors/RAMCache.class.ts +214 -214
- package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +252 -252
- package/src/subsystems/MemoryManager/Cache.service/connectors/S3Cache.class.ts +373 -373
- package/src/subsystems/MemoryManager/Cache.service/index.ts +15 -15
- package/src/subsystems/MemoryManager/LLMCache.ts +72 -72
- package/src/subsystems/MemoryManager/LLMContext.ts +124 -124
- package/src/subsystems/MemoryManager/LLMMemory.service/LLMMemoryConnector.ts +26 -26
- package/src/subsystems/MemoryManager/RuntimeContext.ts +277 -277
- package/src/subsystems/Security/AccessControl/ACL.class.ts +208 -208
- package/src/subsystems/Security/AccessControl/AccessCandidate.class.ts +82 -82
- package/src/subsystems/Security/AccessControl/AccessRequest.class.ts +52 -52
- package/src/subsystems/Security/Account.service/AccountConnector.ts +44 -44
- package/src/subsystems/Security/Account.service/connectors/DummyAccount.class.ts +130 -130
- package/src/subsystems/Security/Account.service/connectors/JSONFileAccount.class.ts +170 -170
- package/src/subsystems/Security/Account.service/connectors/MySQLAccount.class.ts +76 -76
- package/src/subsystems/Security/Account.service/index.ts +14 -14
- package/src/subsystems/Security/Credentials.helper.ts +62 -62
- package/src/subsystems/Security/ManagedVault.service/ManagedVaultConnector.ts +38 -38
- package/src/subsystems/Security/ManagedVault.service/connectors/NullManagedVault.class.ts +53 -53
- package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +154 -154
- package/src/subsystems/Security/ManagedVault.service/index.ts +12 -12
- package/src/subsystems/Security/SecureConnector.class.ts +110 -110
- package/src/subsystems/Security/Vault.service/Vault.helper.ts +30 -30
- package/src/subsystems/Security/Vault.service/VaultConnector.ts +29 -29
- package/src/subsystems/Security/Vault.service/connectors/HashicorpVault.class.ts +46 -46
- package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +221 -221
- package/src/subsystems/Security/Vault.service/connectors/NullVault.class.ts +54 -54
- package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +140 -140
- package/src/subsystems/Security/Vault.service/index.ts +12 -12
- package/src/types/ACL.types.ts +104 -104
- package/src/types/AWS.types.ts +10 -10
- package/src/types/Agent.types.ts +61 -61
- package/src/types/AgentLogger.types.ts +17 -17
- package/src/types/Cache.types.ts +1 -1
- package/src/types/Common.types.ts +2 -2
- package/src/types/LLM.types.ts +520 -520
- package/src/types/Redis.types.ts +8 -8
- package/src/types/SRE.types.ts +64 -64
- package/src/types/Security.types.ts +14 -14
- package/src/types/Storage.types.ts +5 -5
- package/src/types/VectorDB.types.ts +86 -86
- package/src/utils/base64.utils.ts +275 -275
- package/src/utils/cli.utils.ts +68 -68
- package/src/utils/data.utils.ts +322 -322
- package/src/utils/date-time.utils.ts +22 -22
- package/src/utils/general.utils.ts +238 -238
- package/src/utils/index.ts +12 -12
- package/src/utils/lazy-client.ts +261 -261
- package/src/utils/numbers.utils.ts +13 -13
- package/src/utils/oauth.utils.ts +35 -35
- package/src/utils/string.utils.ts +414 -414
- package/src/utils/url.utils.ts +19 -19
- package/src/utils/validation.utils.ts +74 -74
- package/dist/bundle-analysis-lazy.html +0 -4949
- package/dist/bundle-analysis.html +0 -4949
- package/dist/types/Components/Triggers/GmailTrigger.class.d.ts +0 -13
- package/dist/types/Components/Triggers/Trigger.class.d.ts +0 -3
- package/dist/types/helpers/AIPerformanceAnalyzer.helper.d.ts +0 -45
- package/dist/types/helpers/AIPerformanceCollector.helper.d.ts +0 -111
- package/dist/types/subsystems/IO/Storage.service/connectors/AzureBlobStorage.class.d.ts +0 -211
- package/dist/types/subsystems/IO/VectorDB.service/connectors/WeaviateVectorDB.class.d.ts +0 -187
- package/dist/types/subsystems/PerformanceManager/Performance.service/PerformanceConnector.d.ts +0 -102
- package/dist/types/subsystems/PerformanceManager/Performance.service/connectors/LocalPerformanceConnector.class.d.ts +0 -100
- package/dist/types/subsystems/PerformanceManager/Performance.service/index.d.ts +0 -22
- package/dist/types/types/Performance.types.d.ts +0 -468
- package/dist/types/utils/package-manager.utils.d.ts +0 -26
|
@@ -1,362 +1,362 @@
|
|
|
1
|
-
import { Ollama, ChatResponse } from 'ollama';
|
|
2
|
-
import EventEmitter from 'events';
|
|
3
|
-
|
|
4
|
-
import { JSON_RESPONSE_INSTRUCTION, BUILT_IN_MODEL_PREFIX } from '@sre/constants';
|
|
5
|
-
import {
|
|
6
|
-
TLLMMessageBlock,
|
|
7
|
-
ToolData,
|
|
8
|
-
TLLMMessageRole,
|
|
9
|
-
APIKeySource,
|
|
10
|
-
TLLMEvent,
|
|
11
|
-
ILLMRequestFuncParams,
|
|
12
|
-
TLLMChatResponse,
|
|
13
|
-
ILLMRequestContext,
|
|
14
|
-
TLLMPreparedParams,
|
|
15
|
-
TLLMToolResultMessageBlock,
|
|
16
|
-
TLLMRequestBody,
|
|
17
|
-
} from '@sre/types/LLM.types';
|
|
18
|
-
import { LLMHelper } from '@sre/LLMManager/LLM.helper';
|
|
19
|
-
|
|
20
|
-
import { LLMConnector } from '../LLMConnector';
|
|
21
|
-
import { SystemEvents } from '@sre/Core/SystemEvents';
|
|
22
|
-
import { Logger } from '@sre/helpers/Log.helper';
|
|
23
|
-
|
|
24
|
-
const logger = Logger('OllamaConnector');
|
|
25
|
-
|
|
26
|
-
type OllamaChatRequest = {
|
|
27
|
-
model: string;
|
|
28
|
-
messages: any[];
|
|
29
|
-
stream?: boolean;
|
|
30
|
-
options?: {
|
|
31
|
-
num_predict?: number;
|
|
32
|
-
temperature?: number;
|
|
33
|
-
top_p?: number;
|
|
34
|
-
top_k?: number;
|
|
35
|
-
stop?: string[];
|
|
36
|
-
};
|
|
37
|
-
tools?: any[];
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export class OllamaConnector extends LLMConnector {
|
|
41
|
-
public name = 'LLM:Ollama';
|
|
42
|
-
|
|
43
|
-
private getClient(context: ILLMRequestContext): Ollama {
|
|
44
|
-
// Extract baseURL and sanitize it for Ollama SDK
|
|
45
|
-
let host = 'http://localhost:11434';
|
|
46
|
-
|
|
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
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// No API key validation required for Ollama (local by default)
|
|
62
|
-
return new Ollama({ host });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
|
|
66
|
-
try {
|
|
67
|
-
logger.debug(`request ${this.name}`, acRequest.candidate);
|
|
68
|
-
const ollama = this.getClient(context);
|
|
69
|
-
|
|
70
|
-
const result = await ollama.chat({
|
|
71
|
-
...body,
|
|
72
|
-
stream: false,
|
|
73
|
-
}) as unknown as ChatResponse;
|
|
74
|
-
|
|
75
|
-
const message = result.message;
|
|
76
|
-
const finishReason = result.done_reason || 'stop';
|
|
77
|
-
const usage = {
|
|
78
|
-
prompt_tokens: result.prompt_eval_count || 0,
|
|
79
|
-
completion_tokens: result.eval_count || 0,
|
|
80
|
-
total_tokens: (result.prompt_eval_count || 0) + (result.eval_count || 0),
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
this.reportUsage(usage, {
|
|
84
|
-
modelEntryName: context.modelEntryName,
|
|
85
|
-
keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
|
|
86
|
-
agentId: context.agentId,
|
|
87
|
-
teamId: context.teamId,
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
let toolsData: ToolData[] = [];
|
|
91
|
-
let useTool = false;
|
|
92
|
-
|
|
93
|
-
// Handle tool calls if present
|
|
94
|
-
if (message?.tool_calls) {
|
|
95
|
-
toolsData = message.tool_calls.map((tool, index) => ({
|
|
96
|
-
index,
|
|
97
|
-
id: tool.function?.name || `tool_${index}`,
|
|
98
|
-
type: 'function',
|
|
99
|
-
name: tool.function.name,
|
|
100
|
-
arguments: tool.function.arguments,
|
|
101
|
-
role: TLLMMessageRole.Assistant,
|
|
102
|
-
}));
|
|
103
|
-
useTool = true;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
content: message?.content ?? '',
|
|
108
|
-
finishReason,
|
|
109
|
-
useTool,
|
|
110
|
-
toolsData,
|
|
111
|
-
message: message as any,
|
|
112
|
-
usage,
|
|
113
|
-
};
|
|
114
|
-
} catch (error) {
|
|
115
|
-
logger.error(`request ${this.name}`, error, acRequest.candidate);
|
|
116
|
-
throw error;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
|
|
121
|
-
try {
|
|
122
|
-
logger.debug(`streamRequest ${this.name}`, acRequest.candidate);
|
|
123
|
-
const emitter = new EventEmitter();
|
|
124
|
-
const usage_data = [];
|
|
125
|
-
|
|
126
|
-
const ollama = this.getClient(context);
|
|
127
|
-
const stream = await ollama.chat({
|
|
128
|
-
...body,
|
|
129
|
-
stream: true,
|
|
130
|
-
}) as AsyncIterable<ChatResponse>;
|
|
131
|
-
|
|
132
|
-
let toolsData: ToolData[] = [];
|
|
133
|
-
let fullContent = '';
|
|
134
|
-
|
|
135
|
-
(async () => {
|
|
136
|
-
for await (const chunk of stream) {
|
|
137
|
-
// Emit content deltas
|
|
138
|
-
if (chunk.message?.content) {
|
|
139
|
-
const content = chunk.message.content;
|
|
140
|
-
fullContent += content;
|
|
141
|
-
emitter.emit('content', content);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Handle tool calls accumulation
|
|
145
|
-
if (chunk.message?.tool_calls) {
|
|
146
|
-
chunk.message.tool_calls.forEach((toolCall, index) => {
|
|
147
|
-
if (!toolsData[index]) {
|
|
148
|
-
toolsData[index] = {
|
|
149
|
-
index,
|
|
150
|
-
id: toolCall.function?.name || `tool_${index}`,
|
|
151
|
-
type: 'function',
|
|
152
|
-
name: toolCall.function?.name,
|
|
153
|
-
arguments: toolCall.function?.arguments || '',
|
|
154
|
-
role: 'assistant',
|
|
155
|
-
};
|
|
156
|
-
} else {
|
|
157
|
-
// Merge arguments across chunks for string arguments
|
|
158
|
-
if (typeof toolsData[index].arguments === 'string' && typeof toolCall.function?.arguments === 'string') {
|
|
159
|
-
toolsData[index].arguments += toolCall.function.arguments;
|
|
160
|
-
} else {
|
|
161
|
-
// For object arguments, merge them properly
|
|
162
|
-
toolsData[index].arguments = { ...toolsData[index].arguments as any, ...toolCall.function?.arguments };
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Capture usage data when available
|
|
169
|
-
if (chunk.prompt_eval_count !== undefined || chunk.eval_count !== undefined) {
|
|
170
|
-
const usage = {
|
|
171
|
-
prompt_tokens: chunk.prompt_eval_count || 0,
|
|
172
|
-
completion_tokens: chunk.eval_count || 0,
|
|
173
|
-
total_tokens: (chunk.prompt_eval_count || 0) + (chunk.eval_count || 0),
|
|
174
|
-
};
|
|
175
|
-
usage_data.push(usage);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Emit tool info if tools were requested
|
|
180
|
-
if (toolsData.length > 0) {
|
|
181
|
-
emitter.emit(TLLMEvent.ToolInfo, toolsData);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Report usage
|
|
185
|
-
usage_data.forEach((usage) => {
|
|
186
|
-
this.reportUsage(usage, {
|
|
187
|
-
modelEntryName: context.modelEntryName,
|
|
188
|
-
keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
|
|
189
|
-
agentId: context.agentId,
|
|
190
|
-
teamId: context.teamId,
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// Final end event
|
|
195
|
-
setTimeout(() => {
|
|
196
|
-
emitter.emit('end', toolsData);
|
|
197
|
-
}, 100);
|
|
198
|
-
})();
|
|
199
|
-
|
|
200
|
-
return emitter;
|
|
201
|
-
} catch (error: any) {
|
|
202
|
-
logger.error(`streamRequest ${this.name}`, error, acRequest.candidate);
|
|
203
|
-
throw error;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
protected async reqBodyAdapter(params: TLLMPreparedParams): Promise<TLLMRequestBody> {
|
|
208
|
-
const messages = params?.messages || [];
|
|
209
|
-
|
|
210
|
-
const body: OllamaChatRequest = {
|
|
211
|
-
model: params.model as string,
|
|
212
|
-
messages,
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
// Handle JSON response format
|
|
216
|
-
const responseFormat = params?.responseFormat || '';
|
|
217
|
-
if (responseFormat === 'json') {
|
|
218
|
-
if (messages?.[0]?.role === 'system') {
|
|
219
|
-
messages[0].content += JSON_RESPONSE_INSTRUCTION;
|
|
220
|
-
} else {
|
|
221
|
-
messages.unshift({ role: 'system', content: JSON_RESPONSE_INSTRUCTION });
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Map SRE options to Ollama options
|
|
226
|
-
const options: any = {};
|
|
227
|
-
|
|
228
|
-
if (params.maxTokens !== undefined) options.num_predict = params.maxTokens;
|
|
229
|
-
if (params.temperature !== undefined) options.temperature = params.temperature;
|
|
230
|
-
if (params.topP !== undefined) options.top_p = params.topP;
|
|
231
|
-
if (params.topK !== undefined) options.top_k = params.topK;
|
|
232
|
-
if (params.stopSequences?.length) options.stop = params.stopSequences;
|
|
233
|
-
|
|
234
|
-
if (Object.keys(options).length > 0) {
|
|
235
|
-
body.options = options;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Handle tools
|
|
239
|
-
if (params.toolsConfig?.tools) {
|
|
240
|
-
body.tools = params.toolsConfig.tools.map(tool => ({
|
|
241
|
-
type: 'function',
|
|
242
|
-
function: {
|
|
243
|
-
name: tool.function.name,
|
|
244
|
-
description: tool.function.description,
|
|
245
|
-
parameters: tool.function.parameters,
|
|
246
|
-
},
|
|
247
|
-
}));
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return body as unknown as TLLMRequestBody;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
protected reportUsage(
|
|
254
|
-
usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number },
|
|
255
|
-
metadata: { modelEntryName: string; keySource: APIKeySource; agentId: string; teamId: string }
|
|
256
|
-
) {
|
|
257
|
-
// SmythOS (built-in) models have a prefix, so we need to remove it to get the model name
|
|
258
|
-
const modelName = metadata.modelEntryName.replace(BUILT_IN_MODEL_PREFIX, '');
|
|
259
|
-
|
|
260
|
-
const usageData = {
|
|
261
|
-
sourceId: `llm:${modelName}`,
|
|
262
|
-
input_tokens: usage.prompt_tokens,
|
|
263
|
-
output_tokens: usage.completion_tokens,
|
|
264
|
-
input_tokens_cache_write: 0,
|
|
265
|
-
input_tokens_cache_read: 0,
|
|
266
|
-
keySource: metadata.keySource,
|
|
267
|
-
agentId: metadata.agentId,
|
|
268
|
-
teamId: metadata.teamId,
|
|
269
|
-
};
|
|
270
|
-
SystemEvents.emit('USAGE:LLM', usageData);
|
|
271
|
-
|
|
272
|
-
return usageData;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
public transformToolMessageBlocks({
|
|
276
|
-
messageBlock,
|
|
277
|
-
toolsData,
|
|
278
|
-
}: {
|
|
279
|
-
messageBlock: TLLMMessageBlock;
|
|
280
|
-
toolsData: ToolData[];
|
|
281
|
-
}): TLLMToolResultMessageBlock[] {
|
|
282
|
-
const messageBlocks: TLLMToolResultMessageBlock[] = [];
|
|
283
|
-
|
|
284
|
-
// Transform the assistant message block if present
|
|
285
|
-
if (messageBlock) {
|
|
286
|
-
const transformedMessageBlock = {
|
|
287
|
-
...messageBlock,
|
|
288
|
-
content: typeof messageBlock.content === 'object' ? JSON.stringify(messageBlock.content) : messageBlock.content,
|
|
289
|
-
};
|
|
290
|
-
if (transformedMessageBlock.tool_calls) {
|
|
291
|
-
for (let toolCall of transformedMessageBlock.tool_calls) {
|
|
292
|
-
const args = toolCall?.function?.arguments;
|
|
293
|
-
if (typeof args === 'string') {
|
|
294
|
-
try {
|
|
295
|
-
toolCall.function.arguments = JSON.parse(args);
|
|
296
|
-
} catch {
|
|
297
|
-
toolCall.function.arguments = {};
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
// If it's already an object, keep as-is for Ollama
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
messageBlocks.push(transformedMessageBlock);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Transform tool results into tool role messages
|
|
307
|
-
const transformedToolsData = toolsData.map((toolData) => ({
|
|
308
|
-
tool_call_id: toolData.id,
|
|
309
|
-
role: TLLMMessageRole.Tool,
|
|
310
|
-
name: toolData.name,
|
|
311
|
-
content: typeof toolData.result === 'string' ? toolData.result : JSON.stringify(toolData.result),
|
|
312
|
-
}));
|
|
313
|
-
|
|
314
|
-
return [...messageBlocks, ...transformedToolsData];
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
public formatToolsConfig({ type = 'function', toolDefinitions, toolChoice = 'auto' }) {
|
|
318
|
-
let tools = [];
|
|
319
|
-
|
|
320
|
-
if (type === 'function') {
|
|
321
|
-
tools = toolDefinitions.map((tool) => {
|
|
322
|
-
const { name, description, properties, requiredFields } = tool;
|
|
323
|
-
|
|
324
|
-
return {
|
|
325
|
-
type: 'function',
|
|
326
|
-
function: {
|
|
327
|
-
name,
|
|
328
|
-
description,
|
|
329
|
-
parameters: {
|
|
330
|
-
type: 'object',
|
|
331
|
-
properties,
|
|
332
|
-
required: requiredFields,
|
|
333
|
-
},
|
|
334
|
-
},
|
|
335
|
-
};
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return tools?.length > 0 ? { tools, tool_choice: toolChoice } : {};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
public getConsistentMessages(messages: TLLMMessageBlock[]): TLLMMessageBlock[] {
|
|
343
|
-
const _messages = LLMHelper.removeDuplicateUserMessages(messages);
|
|
344
|
-
|
|
345
|
-
return _messages.map((message) => {
|
|
346
|
-
const _message = { ...message };
|
|
347
|
-
let textContent = '';
|
|
348
|
-
|
|
349
|
-
if (message?.parts) {
|
|
350
|
-
textContent = message.parts.map((textBlock) => textBlock?.text || '').join(' ');
|
|
351
|
-
} else if (Array.isArray(message?.content)) {
|
|
352
|
-
textContent = message.content.map((textBlock) => textBlock?.text || '').join(' ');
|
|
353
|
-
} else if (message?.content) {
|
|
354
|
-
textContent = message.content as string;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
_message.content = textContent;
|
|
358
|
-
|
|
359
|
-
return _message;
|
|
360
|
-
});
|
|
361
|
-
}
|
|
1
|
+
import { Ollama, ChatResponse } from 'ollama';
|
|
2
|
+
import EventEmitter from 'events';
|
|
3
|
+
|
|
4
|
+
import { JSON_RESPONSE_INSTRUCTION, BUILT_IN_MODEL_PREFIX } from '@sre/constants';
|
|
5
|
+
import {
|
|
6
|
+
TLLMMessageBlock,
|
|
7
|
+
ToolData,
|
|
8
|
+
TLLMMessageRole,
|
|
9
|
+
APIKeySource,
|
|
10
|
+
TLLMEvent,
|
|
11
|
+
ILLMRequestFuncParams,
|
|
12
|
+
TLLMChatResponse,
|
|
13
|
+
ILLMRequestContext,
|
|
14
|
+
TLLMPreparedParams,
|
|
15
|
+
TLLMToolResultMessageBlock,
|
|
16
|
+
TLLMRequestBody,
|
|
17
|
+
} from '@sre/types/LLM.types';
|
|
18
|
+
import { LLMHelper } from '@sre/LLMManager/LLM.helper';
|
|
19
|
+
|
|
20
|
+
import { LLMConnector } from '../LLMConnector';
|
|
21
|
+
import { SystemEvents } from '@sre/Core/SystemEvents';
|
|
22
|
+
import { Logger } from '@sre/helpers/Log.helper';
|
|
23
|
+
|
|
24
|
+
const logger = Logger('OllamaConnector');
|
|
25
|
+
|
|
26
|
+
type OllamaChatRequest = {
|
|
27
|
+
model: string;
|
|
28
|
+
messages: any[];
|
|
29
|
+
stream?: boolean;
|
|
30
|
+
options?: {
|
|
31
|
+
num_predict?: number;
|
|
32
|
+
temperature?: number;
|
|
33
|
+
top_p?: number;
|
|
34
|
+
top_k?: number;
|
|
35
|
+
stop?: string[];
|
|
36
|
+
};
|
|
37
|
+
tools?: any[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export class OllamaConnector extends LLMConnector {
|
|
41
|
+
public name = 'LLM:Ollama';
|
|
42
|
+
|
|
43
|
+
private getClient(context: ILLMRequestContext): Ollama {
|
|
44
|
+
// Extract baseURL and sanitize it for Ollama SDK
|
|
45
|
+
let host = 'http://localhost:11434';
|
|
46
|
+
|
|
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
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// No API key validation required for Ollama (local by default)
|
|
62
|
+
return new Ollama({ host });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
|
|
66
|
+
try {
|
|
67
|
+
logger.debug(`request ${this.name}`, acRequest.candidate);
|
|
68
|
+
const ollama = this.getClient(context);
|
|
69
|
+
|
|
70
|
+
const result = await ollama.chat({
|
|
71
|
+
...body,
|
|
72
|
+
stream: false,
|
|
73
|
+
}) as unknown as ChatResponse;
|
|
74
|
+
|
|
75
|
+
const message = result.message;
|
|
76
|
+
const finishReason = result.done_reason || 'stop';
|
|
77
|
+
const usage = {
|
|
78
|
+
prompt_tokens: result.prompt_eval_count || 0,
|
|
79
|
+
completion_tokens: result.eval_count || 0,
|
|
80
|
+
total_tokens: (result.prompt_eval_count || 0) + (result.eval_count || 0),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
this.reportUsage(usage, {
|
|
84
|
+
modelEntryName: context.modelEntryName,
|
|
85
|
+
keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
|
|
86
|
+
agentId: context.agentId,
|
|
87
|
+
teamId: context.teamId,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
let toolsData: ToolData[] = [];
|
|
91
|
+
let useTool = false;
|
|
92
|
+
|
|
93
|
+
// Handle tool calls if present
|
|
94
|
+
if (message?.tool_calls) {
|
|
95
|
+
toolsData = message.tool_calls.map((tool, index) => ({
|
|
96
|
+
index,
|
|
97
|
+
id: tool.function?.name || `tool_${index}`,
|
|
98
|
+
type: 'function',
|
|
99
|
+
name: tool.function.name,
|
|
100
|
+
arguments: tool.function.arguments,
|
|
101
|
+
role: TLLMMessageRole.Assistant,
|
|
102
|
+
}));
|
|
103
|
+
useTool = true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
content: message?.content ?? '',
|
|
108
|
+
finishReason,
|
|
109
|
+
useTool,
|
|
110
|
+
toolsData,
|
|
111
|
+
message: message as any,
|
|
112
|
+
usage,
|
|
113
|
+
};
|
|
114
|
+
} catch (error) {
|
|
115
|
+
logger.error(`request ${this.name}`, error, acRequest.candidate);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
|
|
121
|
+
try {
|
|
122
|
+
logger.debug(`streamRequest ${this.name}`, acRequest.candidate);
|
|
123
|
+
const emitter = new EventEmitter();
|
|
124
|
+
const usage_data = [];
|
|
125
|
+
|
|
126
|
+
const ollama = this.getClient(context);
|
|
127
|
+
const stream = await ollama.chat({
|
|
128
|
+
...body,
|
|
129
|
+
stream: true,
|
|
130
|
+
}) as AsyncIterable<ChatResponse>;
|
|
131
|
+
|
|
132
|
+
let toolsData: ToolData[] = [];
|
|
133
|
+
let fullContent = '';
|
|
134
|
+
|
|
135
|
+
(async () => {
|
|
136
|
+
for await (const chunk of stream) {
|
|
137
|
+
// Emit content deltas
|
|
138
|
+
if (chunk.message?.content) {
|
|
139
|
+
const content = chunk.message.content;
|
|
140
|
+
fullContent += content;
|
|
141
|
+
emitter.emit('content', content);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Handle tool calls accumulation
|
|
145
|
+
if (chunk.message?.tool_calls) {
|
|
146
|
+
chunk.message.tool_calls.forEach((toolCall, index) => {
|
|
147
|
+
if (!toolsData[index]) {
|
|
148
|
+
toolsData[index] = {
|
|
149
|
+
index,
|
|
150
|
+
id: toolCall.function?.name || `tool_${index}`,
|
|
151
|
+
type: 'function',
|
|
152
|
+
name: toolCall.function?.name,
|
|
153
|
+
arguments: toolCall.function?.arguments || '',
|
|
154
|
+
role: 'assistant',
|
|
155
|
+
};
|
|
156
|
+
} else {
|
|
157
|
+
// Merge arguments across chunks for string arguments
|
|
158
|
+
if (typeof toolsData[index].arguments === 'string' && typeof toolCall.function?.arguments === 'string') {
|
|
159
|
+
toolsData[index].arguments += toolCall.function.arguments;
|
|
160
|
+
} else {
|
|
161
|
+
// For object arguments, merge them properly
|
|
162
|
+
toolsData[index].arguments = { ...toolsData[index].arguments as any, ...toolCall.function?.arguments };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Capture usage data when available
|
|
169
|
+
if (chunk.prompt_eval_count !== undefined || chunk.eval_count !== undefined) {
|
|
170
|
+
const usage = {
|
|
171
|
+
prompt_tokens: chunk.prompt_eval_count || 0,
|
|
172
|
+
completion_tokens: chunk.eval_count || 0,
|
|
173
|
+
total_tokens: (chunk.prompt_eval_count || 0) + (chunk.eval_count || 0),
|
|
174
|
+
};
|
|
175
|
+
usage_data.push(usage);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Emit tool info if tools were requested
|
|
180
|
+
if (toolsData.length > 0) {
|
|
181
|
+
emitter.emit(TLLMEvent.ToolInfo, toolsData);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Report usage
|
|
185
|
+
usage_data.forEach((usage) => {
|
|
186
|
+
this.reportUsage(usage, {
|
|
187
|
+
modelEntryName: context.modelEntryName,
|
|
188
|
+
keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
|
|
189
|
+
agentId: context.agentId,
|
|
190
|
+
teamId: context.teamId,
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Final end event
|
|
195
|
+
setTimeout(() => {
|
|
196
|
+
emitter.emit('end', toolsData);
|
|
197
|
+
}, 100);
|
|
198
|
+
})();
|
|
199
|
+
|
|
200
|
+
return emitter;
|
|
201
|
+
} catch (error: any) {
|
|
202
|
+
logger.error(`streamRequest ${this.name}`, error, acRequest.candidate);
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
protected async reqBodyAdapter(params: TLLMPreparedParams): Promise<TLLMRequestBody> {
|
|
208
|
+
const messages = params?.messages || [];
|
|
209
|
+
|
|
210
|
+
const body: OllamaChatRequest = {
|
|
211
|
+
model: params.model as string,
|
|
212
|
+
messages,
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// Handle JSON response format
|
|
216
|
+
const responseFormat = params?.responseFormat || '';
|
|
217
|
+
if (responseFormat === 'json') {
|
|
218
|
+
if (messages?.[0]?.role === 'system') {
|
|
219
|
+
messages[0].content += JSON_RESPONSE_INSTRUCTION;
|
|
220
|
+
} else {
|
|
221
|
+
messages.unshift({ role: 'system', content: JSON_RESPONSE_INSTRUCTION });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Map SRE options to Ollama options
|
|
226
|
+
const options: any = {};
|
|
227
|
+
|
|
228
|
+
if (params.maxTokens !== undefined) options.num_predict = params.maxTokens;
|
|
229
|
+
if (params.temperature !== undefined) options.temperature = params.temperature;
|
|
230
|
+
if (params.topP !== undefined) options.top_p = params.topP;
|
|
231
|
+
if (params.topK !== undefined) options.top_k = params.topK;
|
|
232
|
+
if (params.stopSequences?.length) options.stop = params.stopSequences;
|
|
233
|
+
|
|
234
|
+
if (Object.keys(options).length > 0) {
|
|
235
|
+
body.options = options;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Handle tools
|
|
239
|
+
if (params.toolsConfig?.tools) {
|
|
240
|
+
body.tools = params.toolsConfig.tools.map(tool => ({
|
|
241
|
+
type: 'function',
|
|
242
|
+
function: {
|
|
243
|
+
name: tool.function.name,
|
|
244
|
+
description: tool.function.description,
|
|
245
|
+
parameters: tool.function.parameters,
|
|
246
|
+
},
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return body as unknown as TLLMRequestBody;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
protected reportUsage(
|
|
254
|
+
usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number },
|
|
255
|
+
metadata: { modelEntryName: string; keySource: APIKeySource; agentId: string; teamId: string }
|
|
256
|
+
) {
|
|
257
|
+
// SmythOS (built-in) models have a prefix, so we need to remove it to get the model name
|
|
258
|
+
const modelName = metadata.modelEntryName.replace(BUILT_IN_MODEL_PREFIX, '');
|
|
259
|
+
|
|
260
|
+
const usageData = {
|
|
261
|
+
sourceId: `llm:${modelName}`,
|
|
262
|
+
input_tokens: usage.prompt_tokens,
|
|
263
|
+
output_tokens: usage.completion_tokens,
|
|
264
|
+
input_tokens_cache_write: 0,
|
|
265
|
+
input_tokens_cache_read: 0,
|
|
266
|
+
keySource: metadata.keySource,
|
|
267
|
+
agentId: metadata.agentId,
|
|
268
|
+
teamId: metadata.teamId,
|
|
269
|
+
};
|
|
270
|
+
SystemEvents.emit('USAGE:LLM', usageData);
|
|
271
|
+
|
|
272
|
+
return usageData;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
public transformToolMessageBlocks({
|
|
276
|
+
messageBlock,
|
|
277
|
+
toolsData,
|
|
278
|
+
}: {
|
|
279
|
+
messageBlock: TLLMMessageBlock;
|
|
280
|
+
toolsData: ToolData[];
|
|
281
|
+
}): TLLMToolResultMessageBlock[] {
|
|
282
|
+
const messageBlocks: TLLMToolResultMessageBlock[] = [];
|
|
283
|
+
|
|
284
|
+
// Transform the assistant message block if present
|
|
285
|
+
if (messageBlock) {
|
|
286
|
+
const transformedMessageBlock = {
|
|
287
|
+
...messageBlock,
|
|
288
|
+
content: typeof messageBlock.content === 'object' ? JSON.stringify(messageBlock.content) : messageBlock.content,
|
|
289
|
+
};
|
|
290
|
+
if (transformedMessageBlock.tool_calls) {
|
|
291
|
+
for (let toolCall of transformedMessageBlock.tool_calls) {
|
|
292
|
+
const args = toolCall?.function?.arguments;
|
|
293
|
+
if (typeof args === 'string') {
|
|
294
|
+
try {
|
|
295
|
+
toolCall.function.arguments = JSON.parse(args);
|
|
296
|
+
} catch {
|
|
297
|
+
toolCall.function.arguments = {};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// If it's already an object, keep as-is for Ollama
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
messageBlocks.push(transformedMessageBlock);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Transform tool results into tool role messages
|
|
307
|
+
const transformedToolsData = toolsData.map((toolData) => ({
|
|
308
|
+
tool_call_id: toolData.id,
|
|
309
|
+
role: TLLMMessageRole.Tool,
|
|
310
|
+
name: toolData.name,
|
|
311
|
+
content: typeof toolData.result === 'string' ? toolData.result : JSON.stringify(toolData.result),
|
|
312
|
+
}));
|
|
313
|
+
|
|
314
|
+
return [...messageBlocks, ...transformedToolsData];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
public formatToolsConfig({ type = 'function', toolDefinitions, toolChoice = 'auto' }) {
|
|
318
|
+
let tools = [];
|
|
319
|
+
|
|
320
|
+
if (type === 'function') {
|
|
321
|
+
tools = toolDefinitions.map((tool) => {
|
|
322
|
+
const { name, description, properties, requiredFields } = tool;
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
type: 'function',
|
|
326
|
+
function: {
|
|
327
|
+
name,
|
|
328
|
+
description,
|
|
329
|
+
parameters: {
|
|
330
|
+
type: 'object',
|
|
331
|
+
properties,
|
|
332
|
+
required: requiredFields,
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
};
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return tools?.length > 0 ? { tools, tool_choice: toolChoice } : {};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
public getConsistentMessages(messages: TLLMMessageBlock[]): TLLMMessageBlock[] {
|
|
343
|
+
const _messages = LLMHelper.removeDuplicateUserMessages(messages);
|
|
344
|
+
|
|
345
|
+
return _messages.map((message) => {
|
|
346
|
+
const _message = { ...message };
|
|
347
|
+
let textContent = '';
|
|
348
|
+
|
|
349
|
+
if (message?.parts) {
|
|
350
|
+
textContent = message.parts.map((textBlock) => textBlock?.text || '').join(' ');
|
|
351
|
+
} else if (Array.isArray(message?.content)) {
|
|
352
|
+
textContent = message.content.map((textBlock) => textBlock?.text || '').join(' ');
|
|
353
|
+
} else if (message?.content) {
|
|
354
|
+
textContent = message.content as string;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
_message.content = textContent;
|
|
358
|
+
|
|
359
|
+
return _message;
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
362
|
}
|