@smythos/sre 1.5.37 → 1.5.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 (82) hide show
  1. package/dist/index.js +65 -45
  2. package/dist/index.js.map +1 -1
  3. package/dist/types/Components/ECMASandbox.class.d.ts +14 -0
  4. package/dist/types/Components/MemoryDeleteKeyVal.class.d.ts +19 -0
  5. package/dist/types/Components/MemoryReadKeyVal.class.d.ts +17 -0
  6. package/dist/types/Components/MemoryWriteKeyVal.class.d.ts +17 -0
  7. package/dist/types/Components/MemoryWriteObject.class.d.ts +19 -0
  8. package/dist/types/Components/index.d.ts +10 -0
  9. package/dist/types/Core/ConnectorsService.d.ts +2 -1
  10. package/dist/types/helpers/ECMASandbox.helper.d.ts +3 -0
  11. package/dist/types/helpers/Log.helper.d.ts +1 -1
  12. package/dist/types/index.d.ts +8 -1
  13. package/dist/types/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.d.ts +19 -0
  14. package/dist/types/subsystems/LLMManager/LLM.helper.d.ts +21 -10
  15. package/dist/types/subsystems/LLMManager/LLM.service/LLMConnector.d.ts +5 -5
  16. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.d.ts +2 -3
  17. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.d.ts +2 -3
  18. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Echo.class.d.ts +2 -3
  19. package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +2 -3
  20. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Groq.class.d.ts +2 -3
  21. package/dist/types/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.d.ts +3 -4
  22. package/dist/types/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.d.ts +19 -14
  23. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.d.ts +95 -0
  24. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.d.ts +87 -0
  25. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.d.ts +85 -0
  26. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.d.ts +49 -0
  27. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.d.ts +146 -0
  28. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.d.ts +10 -0
  29. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.d.ts +4 -0
  30. package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/types.d.ts +38 -0
  31. package/dist/types/subsystems/LLMManager/LLM.service/connectors/xAI.class.d.ts +1 -2
  32. package/dist/types/subsystems/Security/Vault.service/connectors/JSONFileVault.class.d.ts +5 -0
  33. package/dist/types/types/LLM.types.d.ts +82 -37
  34. package/dist/types/utils/data.utils.d.ts +2 -1
  35. package/package.json +4 -3
  36. package/src/Components/APICall/APICall.class.ts +2 -1
  37. package/src/Components/Component.class.ts +1 -1
  38. package/src/Components/ECMASandbox.class.ts +71 -0
  39. package/src/Components/GenAILLM.class.ts +1 -1
  40. package/src/Components/MemoryDeleteKeyVal.class.ts +70 -0
  41. package/src/Components/MemoryReadKeyVal.class.ts +66 -0
  42. package/src/Components/MemoryWriteKeyVal.class.ts +62 -0
  43. package/src/Components/MemoryWriteObject.class.ts +97 -0
  44. package/src/Components/index.ts +10 -0
  45. package/src/Core/ConnectorsService.ts +3 -3
  46. package/src/helpers/Conversation.helper.ts +11 -3
  47. package/src/helpers/ECMASandbox.helper.ts +54 -0
  48. package/src/helpers/Log.helper.ts +57 -17
  49. package/src/index.ts +192 -185
  50. package/src/index.ts.bak +192 -185
  51. package/src/subsystems/AgentManager/Agent.class.ts +11 -6
  52. package/src/subsystems/AgentManager/AgentRuntime.class.ts +13 -13
  53. package/src/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.ts +131 -0
  54. package/src/subsystems/ComputeManager/Code.service/index.ts +2 -0
  55. package/src/subsystems/LLMManager/LLM.helper.ts +57 -27
  56. package/src/subsystems/LLMManager/LLM.inference.ts +4 -0
  57. package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +125 -28
  58. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +18 -17
  59. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +2 -7
  60. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +2 -6
  61. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +26 -17
  62. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +2 -7
  63. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +2 -7
  64. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +314 -84
  65. package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +455 -0
  66. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +528 -0
  67. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.ts +100 -0
  68. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.ts +81 -0
  69. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +853 -0
  70. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.ts +37 -0
  71. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.ts +4 -0
  72. package/src/subsystems/LLMManager/LLM.service/connectors/openai/types.ts +37 -0
  73. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +0 -5
  74. package/src/subsystems/LLMManager/LLM.service/index.ts +1 -1
  75. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +2 -2
  76. package/src/subsystems/LLMManager/models.ts +1 -1
  77. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +18 -0
  78. package/src/subsystems/MemoryManager/RuntimeContext.ts +33 -16
  79. package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +68 -42
  80. package/src/types/LLM.types.ts +91 -43
  81. package/src/utils/data.utils.ts +3 -2
  82. package/src/subsystems/LLMManager/LLM.service/connectors/OpenAI.class.ts +0 -848
@@ -3,16 +3,23 @@ import EventEmitter from 'events';
3
3
 
4
4
  import { JSON_RESPONSE_INSTRUCTION, BUILT_IN_MODEL_PREFIX } from '@sre/constants';
5
5
  import {
6
- TLLMParams,
7
6
  TCustomLLMModel,
8
7
  APIKeySource,
9
8
  TVertexAISettings,
10
9
  ILLMRequestFuncParams,
11
10
  TGoogleAIRequestBody,
12
- TLLMConnectorParams,
13
11
  ILLMRequestContext,
12
+ TLLMPreparedParams,
13
+ TLLMMessageBlock,
14
+ ToolData,
15
+ TLLMToolResultMessageBlock,
16
+ TLLMMessageRole,
17
+ TLLMChatResponse,
18
+ TLLMEvent,
14
19
  } from '@sre/types/LLM.types';
15
20
  import { LLMHelper } from '@sre/LLMManager/LLM.helper';
21
+ import { BinaryInput } from '@sre/helpers/BinaryInput.helper';
22
+ import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
16
23
 
17
24
  import { LLMConnector } from '../LLMConnector';
18
25
  import { SystemEvents } from '@sre/Core/SystemEvents';
@@ -32,38 +39,66 @@ export class VertexAIConnector extends LLMConnector {
32
39
  return new VertexAI({
33
40
  project: projectId,
34
41
  location: region,
42
+ apiEndpoint: (modelInfo?.settings as TVertexAISettings)?.apiEndpoint,
35
43
  googleAuthOptions: {
36
44
  credentials: credentials as any,
37
45
  },
38
46
  });
39
47
  }
40
48
 
41
- protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<any> {
42
- const messages = body.messages;
43
- delete body.messages;
44
-
49
+ protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
45
50
  try {
46
51
  const vertexAI = await this.getClient(context);
47
- const generativeModel = vertexAI.getGenerativeModel(body);
48
52
 
49
- const result = await generativeModel.generateContent({ contents: messages });
50
- const content = result?.response?.candidates?.[0]?.content?.parts?.[0]?.text;
51
- const usage = result?.response?.usageMetadata;
53
+ // Separate contents from model configuration
54
+ const contents = body.contents;
55
+ delete body.contents;
52
56
 
53
- this.reportUsage(usage, {
54
- modelEntryName: context.modelEntryName,
55
- keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
56
- agentId: context.agentId,
57
- teamId: context.teamId,
58
- });
57
+ // VertexAI expects contents in a specific format: {contents: [...]}
58
+ const requestParam = { contents };
59
+
60
+ const model = vertexAI.getGenerativeModel(body);
61
+
62
+ const result = await model.generateContent(requestParam);
63
+ const response = await result.response;
64
+
65
+ const content = response.candidates?.[0]?.content?.parts?.[0]?.text || '';
66
+ const finishReason = response.candidates?.[0]?.finishReason || 'stop';
67
+ const usage = response.usageMetadata;
68
+
69
+ let toolsData: ToolData[] = [];
70
+ let useTool = false;
71
+
72
+ // Check for function calls in the response
73
+ const functionCalls = response.candidates?.[0]?.content?.parts?.filter((part) => part.functionCall);
74
+ if (functionCalls && functionCalls.length > 0) {
75
+ functionCalls.forEach((call, index) => {
76
+ toolsData.push({
77
+ index,
78
+ id: call.functionCall?.name + '_' + index, // VertexAI doesn't provide IDs like Anthropic
79
+ type: 'function',
80
+ name: call.functionCall?.name,
81
+ arguments: call.functionCall?.args,
82
+ role: TLLMMessageRole.Assistant,
83
+ });
84
+ });
85
+ useTool = true;
86
+ }
87
+
88
+ if (usage) {
89
+ this.reportUsage(usage, {
90
+ modelEntryName: context.modelEntryName,
91
+ keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
92
+ agentId: context.agentId,
93
+ teamId: context.teamId,
94
+ });
95
+ }
59
96
 
60
97
  return {
61
98
  content,
62
- finishReason: 'stop',
63
- useTool: false,
64
- toolsData: [],
65
- message: { content, role: 'assistant' },
66
- usage,
99
+ finishReason,
100
+ toolsData,
101
+ useTool,
67
102
  };
68
103
  } catch (error) {
69
104
  throw error;
@@ -71,85 +106,125 @@ export class VertexAIConnector extends LLMConnector {
71
106
  }
72
107
 
73
108
  protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
74
- // Simulate streaming similar to Perplexity's approach - fallback to regular request
75
109
  const emitter = new EventEmitter();
76
110
 
77
- setTimeout(() => {
111
+ setTimeout(async () => {
78
112
  try {
79
- this.request({ acRequest, body, context })
80
- .then((response) => {
81
- const finishReason = response.finishReason;
82
- const usage = response.usage;
83
-
84
- // Emit the content as a stream-like response
85
- emitter.emit('interrupted', finishReason);
86
- emitter.emit('content', response.content);
87
- emitter.emit('end', undefined, usage, finishReason);
88
- })
89
- .catch((error) => {
90
- emitter.emit('error', error.message || error.toString());
113
+ const vertexAI = await this.getClient(context);
114
+
115
+ // Separate contents from model configuration
116
+ const contents = body.contents;
117
+ delete body.contents;
118
+
119
+ const vertexModel = vertexAI.getGenerativeModel(body);
120
+
121
+ // VertexAI expects contents in a specific format: {contents: [...]}
122
+ const requestParam = { contents };
123
+
124
+ const streamResult = await vertexModel.generateContentStream(requestParam);
125
+
126
+ let toolsData: ToolData[] = [];
127
+ let usageData: any[] = [];
128
+
129
+ for await (const chunk of streamResult.stream) {
130
+ const chunkText = chunk.candidates?.[0]?.content?.parts?.[0]?.text || '';
131
+ if (chunkText) {
132
+ emitter.emit('content', chunkText);
133
+ }
134
+ }
135
+
136
+ const aggregatedResponse = await streamResult.response;
137
+
138
+ // Check for function calls in the final response (like Anthropic does)
139
+ const functionCalls = aggregatedResponse.candidates?.[0]?.content?.parts?.filter((part) => part.functionCall);
140
+ if (functionCalls && functionCalls.length > 0) {
141
+ functionCalls.forEach((call, index) => {
142
+ toolsData.push({
143
+ index,
144
+ id: call.functionCall?.name + '_' + index,
145
+ type: 'function',
146
+ name: call.functionCall?.name,
147
+ arguments: call.functionCall?.args,
148
+ role: TLLMMessageRole.Assistant,
149
+ });
150
+ });
151
+
152
+ emitter.emit(TLLMEvent.ToolInfo, toolsData);
153
+ }
154
+
155
+ const usage = aggregatedResponse.usageMetadata;
156
+
157
+ if (usage) {
158
+ const reportedUsage = this.reportUsage(usage, {
159
+ modelEntryName: context.modelEntryName,
160
+ keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
161
+ agentId: context.agentId,
162
+ teamId: context.teamId,
91
163
  });
164
+ usageData.push(reportedUsage);
165
+ }
166
+
167
+ const finishReason = (aggregatedResponse.candidates?.[0]?.finishReason || 'stop').toLowerCase();
168
+
169
+ if (finishReason !== 'stop') {
170
+ emitter.emit('interrupted', finishReason);
171
+ }
172
+
173
+ setTimeout(() => {
174
+ emitter.emit('end', toolsData, usageData, finishReason);
175
+ }, 100);
92
176
  } catch (error) {
93
- emitter.emit('error', error.message || error.toString());
177
+ emitter.emit('error', error);
94
178
  }
95
179
  }, 100);
96
180
 
97
181
  return emitter;
98
182
  }
99
183
 
100
- protected async webSearchRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
101
- throw new Error('Web search is not supported for Vertex AI');
102
- }
103
-
104
- protected async reqBodyAdapter(params: TLLMParams): Promise<TGoogleAIRequestBody> {
105
- let messages = params?.messages || [];
106
-
107
- //#region Separate system message and add JSON response instruction if needed
108
- let systemInstruction;
109
- const { systemMessage, otherMessages } = LLMHelper.separateSystemMessages(messages);
184
+ protected async reqBodyAdapter(params: TLLMPreparedParams): Promise<TGoogleAIRequestBody> {
185
+ const model = params?.model;
186
+ const { messages, systemMessage } = await this.prepareMessages(params);
110
187
 
111
- if ('content' in systemMessage) {
112
- systemInstruction = systemMessage.content;
113
- }
114
-
115
- messages = otherMessages;
188
+ let body: any = {
189
+ model: model as string,
190
+ contents: messages, // This will be separated in the request methods
191
+ };
116
192
 
117
193
  const responseFormat = params?.responseFormat || '';
194
+ let systemInstruction = systemMessage || '';
195
+
118
196
  if (responseFormat === 'json') {
119
- systemInstruction = JSON_RESPONSE_INSTRUCTION;
197
+ systemInstruction += (systemInstruction ? '\n\n' : '') + JSON_RESPONSE_INSTRUCTION;
120
198
  }
121
- //#endregion Separate system message and add JSON response instruction if needed
122
-
123
- const modelInfo = params.modelInfo as TCustomLLMModel;
124
-
125
- let body: TGoogleAIRequestBody = {
126
- model: modelInfo?.settings?.customModel || modelInfo?.settings?.foundationModel,
127
- messages,
128
- };
129
199
 
130
200
  const config: GenerationConfig = {};
131
201
 
132
- if (params?.maxTokens !== undefined) config.maxOutputTokens = params.maxTokens;
133
- if (params?.temperature !== undefined) config.temperature = params.temperature;
134
- if (params?.topP !== undefined) config.topP = params.topP;
135
- if (params?.topK !== undefined) config.topK = params.topK;
136
- if (params?.stopSequences?.length) config.stopSequences = params.stopSequences;
202
+ if (params.maxTokens !== undefined) config.maxOutputTokens = params.maxTokens;
203
+ if (params.temperature !== undefined) config.temperature = params.temperature;
204
+ if (params.topP !== undefined) config.topP = params.topP;
205
+ if (params.topK !== undefined) config.topK = params.topK;
206
+ if (params.stopSequences?.length) config.stopSequences = params.stopSequences;
137
207
 
138
208
  if (systemInstruction) {
139
- body.systemInstruction = systemInstruction;
209
+ body.systemInstruction = {
210
+ role: 'system',
211
+ parts: [{ text: systemInstruction }],
212
+ };
140
213
  }
141
214
 
142
215
  if (Object.keys(config).length > 0) {
143
- body.generationConfig = config as any;
216
+ body.generationConfig = config;
217
+ }
218
+
219
+ // Handle tools configuration
220
+ if (params?.toolsConfig?.tools && params?.toolsConfig?.tools.length > 0) {
221
+ body.tools = this.formatToolsForVertexAI(params.toolsConfig.tools);
144
222
  }
145
223
 
146
224
  return body;
147
225
  }
148
226
 
149
- protected reportUsage(
150
- usage: UsageMetadata & { cachedContentTokenCount?: number },
151
- metadata: { modelEntryName: string; keySource: APIKeySource; agentId: string; teamId: string }
152
- ) {
227
+ protected reportUsage(usage: UsageMetadata, metadata: { modelEntryName: string; keySource: APIKeySource; agentId: string; teamId: string }) {
153
228
  // SmythOS (built-in) models have a prefix, so we need to remove it to get the model name
154
229
  const modelName = metadata.modelEntryName.replace(BUILT_IN_MODEL_PREFIX, '');
155
230
 
@@ -168,26 +243,181 @@ export class VertexAIConnector extends LLMConnector {
168
243
  return usageData;
169
244
  }
170
245
 
171
- public formatToolsConfig({ type = 'function', toolDefinitions, toolChoice = 'auto' }) {
172
- throw new Error('Tool configuration is not currently implemented for Vertex AI');
173
- }
246
+ private async prepareMessages(params: TLLMPreparedParams) {
247
+ const messages = params?.messages || [];
248
+ const files: BinaryInput[] = params?.files || [];
174
249
 
175
- public getConsistentMessages(messages) {
176
- const _messages = LLMHelper.removeDuplicateUserMessages(messages);
250
+ let processedMessages = [...messages];
177
251
 
178
- return _messages.map((message) => {
179
- let textBlock = [];
252
+ // Handle system messages - VertexAI uses systemInstruction separately
253
+ const { systemMessage, otherMessages } = LLMHelper.separateSystemMessages(processedMessages);
254
+ processedMessages = otherMessages;
180
255
 
181
- if (message?.parts) {
182
- textBlock = message.parts;
183
- } else if (message?.content) {
184
- textBlock = Array.isArray(message.content) ? message.content : [{ text: message.content as string }];
256
+ // Handle files if present
257
+ if (files?.length > 0) {
258
+ const fileData = await this.processFiles(files, params.agentId);
259
+
260
+ // Add file data to the last user message
261
+ const userMessage = processedMessages.pop();
262
+ if (userMessage) {
263
+ const content = [{ text: userMessage.content as string }, ...fileData];
264
+ processedMessages.push({
265
+ role: userMessage.role,
266
+ parts: content,
267
+ });
185
268
  }
269
+ }
270
+
271
+ // Convert messages to VertexAI format
272
+ let vertexAIMessages = this.convertMessagesToVertexAIFormat(processedMessages);
273
+
274
+ // Ensure we have at least one message with content
275
+ if (!vertexAIMessages || vertexAIMessages.length === 0) {
276
+ vertexAIMessages = [
277
+ {
278
+ role: 'user',
279
+ parts: [{ text: 'Hello' }],
280
+ },
281
+ ];
282
+ }
283
+
284
+ return {
285
+ messages: vertexAIMessages,
286
+ systemMessage: (systemMessage as any)?.content || '',
287
+ };
288
+ }
289
+
290
+ private async processFiles(files: BinaryInput[], agentId: string) {
291
+ const fileData = [];
292
+
293
+ for (const file of files) {
294
+ const bufferData = await file.readData(AccessCandidate.agent(agentId));
295
+ const base64Data = bufferData.toString('base64');
296
+
297
+ fileData.push({
298
+ inlineData: {
299
+ data: base64Data,
300
+ mimeType: file.mimetype,
301
+ },
302
+ });
303
+ }
304
+
305
+ return fileData;
306
+ }
307
+
308
+ private convertMessagesToVertexAIFormat(messages: TLLMMessageBlock[]) {
309
+ return messages
310
+ .filter((message) => message && (message.content || message.parts))
311
+ .map((message) => {
312
+ let parts;
313
+
314
+ if (typeof message.content === 'string') {
315
+ parts = message.content.trim() ? [{ text: message.content.trim() }] : [{ text: 'Continue' }];
316
+ } else if (message.parts && Array.isArray(message.parts)) {
317
+ parts = message.parts;
318
+ } else if (message.content) {
319
+ parts = [{ text: String(message.content) || 'Continue' }];
320
+ } else {
321
+ parts = [{ text: 'Continue' }];
322
+ }
323
+
324
+ return {
325
+ role: message.role === TLLMMessageRole.Assistant ? 'model' : 'user',
326
+ parts,
327
+ };
328
+ });
329
+ }
330
+
331
+ private formatToolsForVertexAI(tools: any[]) {
332
+ return [
333
+ {
334
+ functionDeclarations: tools.map((tool) => ({
335
+ name: tool.name,
336
+ description: tool.description || '',
337
+ parameters: {
338
+ type: 'object',
339
+ properties: tool.properties || {},
340
+ required: tool.requiredFields || [],
341
+ },
342
+ })),
343
+ },
344
+ ];
345
+ }
346
+
347
+ public formatToolsConfig({ toolDefinitions, toolChoice = 'auto' }) {
348
+ const tools = toolDefinitions.map((tool) => {
349
+ const { name, description, properties, requiredFields } = tool;
186
350
 
187
351
  return {
188
- role: message.role,
189
- parts: textBlock,
352
+ name,
353
+ description,
354
+ properties,
355
+ requiredFields,
190
356
  };
191
357
  });
358
+
359
+ return {
360
+ tools,
361
+ toolChoice: {
362
+ type: toolChoice,
363
+ },
364
+ };
365
+ }
366
+
367
+ public transformToolMessageBlocks({
368
+ messageBlock,
369
+ toolsData,
370
+ }: {
371
+ messageBlock: TLLMMessageBlock;
372
+ toolsData: ToolData[];
373
+ }): TLLMToolResultMessageBlock[] {
374
+ const messageBlocks: TLLMToolResultMessageBlock[] = [];
375
+
376
+ if (messageBlock) {
377
+ const parts = [];
378
+
379
+ if (typeof messageBlock.content === 'string') {
380
+ parts.push({ text: messageBlock.content });
381
+ } else if (Array.isArray(messageBlock.content)) {
382
+ parts.push(...messageBlock.content);
383
+ }
384
+
385
+ if (messageBlock.tool_calls) {
386
+ const functionCalls = messageBlock.tool_calls.map((toolCall: any) => ({
387
+ functionCall: {
388
+ name: toolCall?.function?.name,
389
+ args:
390
+ typeof toolCall?.function?.arguments === 'string'
391
+ ? JSON.parse(toolCall.function.arguments)
392
+ : toolCall?.function?.arguments || {},
393
+ },
394
+ }));
395
+ parts.push(...functionCalls);
396
+ }
397
+
398
+ messageBlocks.push({
399
+ role: messageBlock.role,
400
+ parts,
401
+ });
402
+ }
403
+
404
+ // Transform tool results
405
+ const toolResults = toolsData.map((toolData) => ({
406
+ role: TLLMMessageRole.User,
407
+ parts: [
408
+ {
409
+ functionResponse: {
410
+ name: toolData.name,
411
+ response: {
412
+ name: toolData.name,
413
+ content: toolData.result,
414
+ },
415
+ },
416
+ },
417
+ ],
418
+ }));
419
+
420
+ messageBlocks.push(...toolResults);
421
+ return messageBlocks;
192
422
  }
193
423
  }