@smythos/sre 1.5.26 → 1.5.31
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 +28 -0
- package/dist/index.js +61 -46
- package/dist/index.js.map +1 -1
- package/dist/types/Components/GenAILLM.class.d.ts +126 -0
- package/dist/types/helpers/AWSLambdaCode.helper.d.ts +9 -3
- package/dist/types/index.d.ts +1 -0
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/xAI.d.ts +121 -0
- package/dist/types/subsystems/LLMManager/models.d.ts +1 -0
- package/dist/types/types/LLM.types.d.ts +16 -0
- package/package.json +1 -1
- package/src/Components/GenAILLM.class.ts +166 -7
- package/src/Components/ServerlessCode.class.ts +7 -3
- package/src/helpers/AWSLambdaCode.helper.ts +184 -44
- package/src/helpers/Conversation.helper.ts +2 -2
- package/src/index.ts +185 -184
- package/src/index.ts.bak +185 -184
- package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +15 -11
- package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +21 -5
- package/src/subsystems/LLMManager/LLM.service/connectors/xAI.ts +476 -0
- package/src/subsystems/LLMManager/LLM.service/index.ts +2 -1
- package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +17 -11
- package/src/subsystems/LLMManager/models.ts +1 -0
- package/src/types/LLM.types.ts +18 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
import axios, { AxiosInstance } from 'axios';
|
|
3
|
+
|
|
4
|
+
import { JSON_RESPONSE_INSTRUCTION, BUILT_IN_MODEL_PREFIX } from '@sre/constants';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
TLLMParams,
|
|
8
|
+
ToolData,
|
|
9
|
+
TLLMMessageBlock,
|
|
10
|
+
TLLMToolResultMessageBlock,
|
|
11
|
+
TLLMMessageRole,
|
|
12
|
+
APIKeySource,
|
|
13
|
+
BasicCredentials,
|
|
14
|
+
ILLMRequestFuncParams,
|
|
15
|
+
TLLMChatResponse,
|
|
16
|
+
ILLMRequestContext,
|
|
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
|
+
|
|
23
|
+
type ChatCompletionParams = {
|
|
24
|
+
model: string;
|
|
25
|
+
messages: any[];
|
|
26
|
+
max_tokens?: number;
|
|
27
|
+
temperature?: number;
|
|
28
|
+
top_p?: number;
|
|
29
|
+
frequency_penalty?: number;
|
|
30
|
+
presence_penalty?: number;
|
|
31
|
+
stop?: string | string[];
|
|
32
|
+
response_format?: { type: string };
|
|
33
|
+
stream?: boolean;
|
|
34
|
+
stream_options?: { include_usage: boolean };
|
|
35
|
+
tools?: any[];
|
|
36
|
+
tool_choice?: any;
|
|
37
|
+
// xAI search parameters - nested structure
|
|
38
|
+
search_parameters?: {
|
|
39
|
+
mode?: 'auto' | 'on' | 'off';
|
|
40
|
+
return_citations?: boolean;
|
|
41
|
+
max_search_results?: number;
|
|
42
|
+
sources?: Array<{
|
|
43
|
+
type: 'web' | 'x' | 'news' | 'rss';
|
|
44
|
+
country?: string;
|
|
45
|
+
excluded_websites?: string[];
|
|
46
|
+
allowed_websites?: string[];
|
|
47
|
+
safe_search?: boolean;
|
|
48
|
+
included_x_handles?: string[];
|
|
49
|
+
excluded_x_handles?: string[];
|
|
50
|
+
post_favorite_count?: number;
|
|
51
|
+
post_view_count?: number;
|
|
52
|
+
links?: string[];
|
|
53
|
+
}>;
|
|
54
|
+
from_date?: string;
|
|
55
|
+
to_date?: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type TUsage = {
|
|
60
|
+
prompt_tokens: number;
|
|
61
|
+
completion_tokens: number;
|
|
62
|
+
total_tokens: number;
|
|
63
|
+
prompt_tokens_details?: {
|
|
64
|
+
text_tokens?: number;
|
|
65
|
+
audio_tokens?: number;
|
|
66
|
+
image_tokens?: number;
|
|
67
|
+
cached_tokens?: number;
|
|
68
|
+
};
|
|
69
|
+
completion_tokens_details?: {
|
|
70
|
+
reasoning_tokens?: number;
|
|
71
|
+
audio_tokens?: number;
|
|
72
|
+
accepted_prediction_tokens?: number;
|
|
73
|
+
rejected_prediction_tokens?: number;
|
|
74
|
+
};
|
|
75
|
+
reasoning_tokens?: number; // for backward compatibility
|
|
76
|
+
num_sources_used?: number;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export class xAIConnector extends LLMConnector {
|
|
80
|
+
public name = 'LLM:Grok';
|
|
81
|
+
|
|
82
|
+
private async getClient(params: ILLMRequestContext): Promise<AxiosInstance> {
|
|
83
|
+
const apiKey = (params.credentials as BasicCredentials)?.apiKey;
|
|
84
|
+
const baseURL = params?.modelInfo?.baseURL || 'https://api.x.ai/v1';
|
|
85
|
+
|
|
86
|
+
if (!apiKey) throw new Error('Please provide an API key for Grok');
|
|
87
|
+
|
|
88
|
+
return axios.create({
|
|
89
|
+
baseURL,
|
|
90
|
+
headers: {
|
|
91
|
+
Authorization: `Bearer ${apiKey}`,
|
|
92
|
+
'Content-Type': 'application/json',
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected async request({ acRequest, body, context }: ILLMRequestFuncParams): Promise<TLLMChatResponse> {
|
|
98
|
+
try {
|
|
99
|
+
const grok = await this.getClient(context);
|
|
100
|
+
const response = await grok.post('/chat/completions', body);
|
|
101
|
+
|
|
102
|
+
const message = response?.data?.choices?.[0]?.message;
|
|
103
|
+
const finishReason = response?.data?.choices?.[0]?.finish_reason;
|
|
104
|
+
const usage = response?.data?.usage as TUsage;
|
|
105
|
+
const citations = response?.data?.citations;
|
|
106
|
+
|
|
107
|
+
let toolsData: ToolData[] = [];
|
|
108
|
+
let useTool = false;
|
|
109
|
+
|
|
110
|
+
if (finishReason === 'tool_calls') {
|
|
111
|
+
toolsData =
|
|
112
|
+
message?.tool_calls?.map((tool, index) => ({
|
|
113
|
+
index,
|
|
114
|
+
id: tool?.id,
|
|
115
|
+
type: tool?.type,
|
|
116
|
+
name: tool?.function?.name,
|
|
117
|
+
arguments: tool?.function?.arguments,
|
|
118
|
+
role: 'tool',
|
|
119
|
+
})) || [];
|
|
120
|
+
|
|
121
|
+
useTool = true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Handle citations from live search
|
|
125
|
+
let content = message?.content ?? '';
|
|
126
|
+
if (citations && citations.length > 0) {
|
|
127
|
+
const citationsText = '\n\n**Sources:**\n' + citations.map((url, index) => `${index + 1}. ${url}`).join('\n');
|
|
128
|
+
content += citationsText;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this.reportUsage(usage, {
|
|
132
|
+
modelEntryName: context.modelEntryName,
|
|
133
|
+
keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
|
|
134
|
+
agentId: context.agentId,
|
|
135
|
+
teamId: context.teamId,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
content,
|
|
140
|
+
finishReason,
|
|
141
|
+
useTool,
|
|
142
|
+
toolsData,
|
|
143
|
+
message,
|
|
144
|
+
usage,
|
|
145
|
+
};
|
|
146
|
+
} catch (error) {
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
protected async streamRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
|
|
152
|
+
const emitter = new EventEmitter();
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const grok = await this.getClient(context);
|
|
156
|
+
const response = await grok.post(
|
|
157
|
+
'/chat/completions',
|
|
158
|
+
{ ...body, stream: true, stream_options: { include_usage: true } },
|
|
159
|
+
{
|
|
160
|
+
responseType: 'stream',
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const reportedUsage: any[] = [];
|
|
165
|
+
let finishReason = 'stop';
|
|
166
|
+
let toolsData: any[] = [];
|
|
167
|
+
let usage: any = {};
|
|
168
|
+
let citations: any[] = [];
|
|
169
|
+
|
|
170
|
+
response.data.on('data', (chunk) => {
|
|
171
|
+
const lines = chunk.toString().split('\n');
|
|
172
|
+
|
|
173
|
+
for (const line of lines) {
|
|
174
|
+
if (line.startsWith('data: ')) {
|
|
175
|
+
const data = line.slice(6);
|
|
176
|
+
if (data === '[DONE]') {
|
|
177
|
+
// Handle stream completion
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const parsed = JSON.parse(data);
|
|
183
|
+
const delta = parsed.choices?.[0]?.delta;
|
|
184
|
+
|
|
185
|
+
// Usage data comes in final chunk when stream_options.include_usage is true
|
|
186
|
+
if (parsed?.usage) {
|
|
187
|
+
usage = parsed.usage;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Handle citations from xAI - they come at the top level as an array of URLs
|
|
191
|
+
if (parsed.citations) {
|
|
192
|
+
citations = parsed.citations;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (delta) {
|
|
196
|
+
emitter.emit('data', delta);
|
|
197
|
+
|
|
198
|
+
if (delta.content) {
|
|
199
|
+
emitter.emit('content', delta.content, delta.role);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (delta.tool_calls) {
|
|
203
|
+
const toolCall = delta.tool_calls[0];
|
|
204
|
+
const index = toolCall?.index;
|
|
205
|
+
|
|
206
|
+
toolsData[index] = {
|
|
207
|
+
index,
|
|
208
|
+
role: 'tool',
|
|
209
|
+
id: (toolsData?.[index]?.id || '') + (toolCall?.id || ''),
|
|
210
|
+
type: (toolsData?.[index]?.type || '') + (toolCall?.type || ''),
|
|
211
|
+
name: (toolsData?.[index]?.name || '') + (toolCall?.function?.name || ''),
|
|
212
|
+
arguments: (toolsData?.[index]?.arguments || '') + (toolCall?.function?.arguments || ''),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (parsed.choices?.[0]?.finish_reason) {
|
|
218
|
+
finishReason = parsed.choices[0].finish_reason;
|
|
219
|
+
}
|
|
220
|
+
} catch (e) {
|
|
221
|
+
// Ignore parsing errors for incomplete chunks
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
response.data.on('end', () => {
|
|
228
|
+
// Include citations in content if available
|
|
229
|
+
if (citations && citations.length > 0) {
|
|
230
|
+
const citationsText = '\n\n**Sources:**\n' + citations.map((url, index) => `${index + 1}. ${url}`).join('\n');
|
|
231
|
+
|
|
232
|
+
emitter.emit('content', citationsText, 'assistant');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (toolsData.length > 0) {
|
|
236
|
+
emitter.emit('toolInfo', toolsData);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Report usage if available
|
|
240
|
+
if (Object.keys(usage).length > 0) {
|
|
241
|
+
const _reported = this.reportUsage(usage, {
|
|
242
|
+
modelEntryName: context.modelEntryName,
|
|
243
|
+
keySource: context.isUserKey ? APIKeySource.User : APIKeySource.Smyth,
|
|
244
|
+
agentId: context.agentId,
|
|
245
|
+
teamId: context.teamId,
|
|
246
|
+
});
|
|
247
|
+
reportedUsage.push(_reported);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (finishReason !== 'stop') {
|
|
251
|
+
emitter.emit('interrupted', finishReason);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
setTimeout(() => {
|
|
255
|
+
emitter.emit('end', toolsData, reportedUsage, finishReason);
|
|
256
|
+
}, 100);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
response.data.on('error', (error) => {
|
|
260
|
+
emitter.emit('error', error);
|
|
261
|
+
});
|
|
262
|
+
} catch (error) {
|
|
263
|
+
emitter.emit('error', error);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return emitter;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// TODO: will be removed when we merge with interface support of OpenAI
|
|
270
|
+
protected async webSearchRequest({ acRequest, body, context }: ILLMRequestFuncParams): Promise<EventEmitter> {
|
|
271
|
+
throw new Error('Not implemented');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
protected async reqBodyAdapter(params: TLLMParams): Promise<ChatCompletionParams> {
|
|
275
|
+
const messages = params?.messages || [];
|
|
276
|
+
const modelName = params.model as string;
|
|
277
|
+
|
|
278
|
+
// Handle JSON response format
|
|
279
|
+
const responseFormat = params?.responseFormat || '';
|
|
280
|
+
if (responseFormat === 'json') {
|
|
281
|
+
if (messages?.[0]?.role === TLLMMessageRole.System) {
|
|
282
|
+
messages[0].content += JSON_RESPONSE_INSTRUCTION;
|
|
283
|
+
} else {
|
|
284
|
+
messages.unshift({ role: TLLMMessageRole.System, content: JSON_RESPONSE_INSTRUCTION });
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
params.responseFormat = { type: 'json_object' };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const body: ChatCompletionParams = {
|
|
291
|
+
model: modelName,
|
|
292
|
+
messages,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// Add parameters if they're not undefined and not 0 (for reasoning models)
|
|
296
|
+
if (params?.maxTokens !== undefined) body.max_tokens = params.maxTokens;
|
|
297
|
+
if (params?.temperature !== undefined) body.temperature = params.temperature;
|
|
298
|
+
if (params?.topP !== undefined) body.top_p = params.topP;
|
|
299
|
+
|
|
300
|
+
if (params?.responseFormat) {
|
|
301
|
+
body.response_format = params.responseFormat;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Add tools configuration if available
|
|
305
|
+
if (params?.toolsConfig?.tools && params?.toolsConfig?.tools?.length > 0) {
|
|
306
|
+
body.tools = params.toolsConfig.tools;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (params?.toolsConfig?.tool_choice) {
|
|
310
|
+
body.tool_choice = params.toolsConfig.tool_choice;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Add xAI search configuration if useSearch is enabled
|
|
314
|
+
if (params?.useSearch) {
|
|
315
|
+
body.search_parameters = {};
|
|
316
|
+
|
|
317
|
+
// Basic search parameters
|
|
318
|
+
if (params.searchMode) body.search_parameters.mode = params.searchMode;
|
|
319
|
+
if (params.returnCitations !== undefined) body.search_parameters.return_citations = params.returnCitations;
|
|
320
|
+
if (params.maxSearchResults !== undefined) body.search_parameters.max_search_results = params.maxSearchResults;
|
|
321
|
+
|
|
322
|
+
// Date filtering
|
|
323
|
+
if (params.fromDate) body.search_parameters.from_date = params.fromDate;
|
|
324
|
+
if (params.toDate) body.search_parameters.to_date = params.toDate;
|
|
325
|
+
|
|
326
|
+
// Create sources array
|
|
327
|
+
const sources: any[] = [];
|
|
328
|
+
|
|
329
|
+
// If searchDataSources is provided, use it as source types
|
|
330
|
+
if (params.searchDataSources && params.searchDataSources.length > 0) {
|
|
331
|
+
params.searchDataSources.forEach((sourceType) => {
|
|
332
|
+
const source: any = { type: sourceType };
|
|
333
|
+
|
|
334
|
+
// Add parameters based on source type
|
|
335
|
+
if (sourceType === 'web' || sourceType === 'news') {
|
|
336
|
+
if (params.searchCountry) source.country = params.searchCountry;
|
|
337
|
+
|
|
338
|
+
// Website filtering (mutually exclusive)
|
|
339
|
+
if (params.excludedWebsites && params.excludedWebsites.length > 0) {
|
|
340
|
+
source.excluded_websites = params.excludedWebsites;
|
|
341
|
+
} else if (params.allowedWebsites && params.allowedWebsites.length > 0) {
|
|
342
|
+
source.allowed_websites = params.allowedWebsites;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (params.safeSearch !== undefined) source.safe_search = params.safeSearch;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (sourceType === 'x') {
|
|
349
|
+
if (params.includedXHandles && params.includedXHandles.length > 0) {
|
|
350
|
+
source.included_x_handles = params.includedXHandles;
|
|
351
|
+
} else if (params.excludedXHandles && params.excludedXHandles.length > 0) {
|
|
352
|
+
source.excluded_x_handles = params.excludedXHandles;
|
|
353
|
+
}
|
|
354
|
+
if (params.postFavoriteCount !== undefined && params.postFavoriteCount > 0) {
|
|
355
|
+
source.post_favorite_count = params.postFavoriteCount;
|
|
356
|
+
}
|
|
357
|
+
if (params.postViewCount !== undefined && params.postViewCount > 0) {
|
|
358
|
+
source.post_view_count = params.postViewCount;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (sourceType === 'rss') {
|
|
363
|
+
if (params.rssLinks) source.links = params.rssLinks;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
sources.push(source);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (sources.length > 0) {
|
|
371
|
+
body.search_parameters.sources = sources;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return body;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
protected reportUsage(usage: TUsage, metadata: { modelEntryName: string; keySource: APIKeySource; agentId: string; teamId: string }) {
|
|
379
|
+
// SmythOS (built-in) models have a prefix, so we need to remove it to get the model name
|
|
380
|
+
const modelName = metadata.modelEntryName.replace(BUILT_IN_MODEL_PREFIX, '');
|
|
381
|
+
|
|
382
|
+
const usageData = {
|
|
383
|
+
sourceId: `llm:${modelName}`,
|
|
384
|
+
input_tokens: usage?.prompt_tokens - (usage?.prompt_tokens_details?.cached_tokens || 0),
|
|
385
|
+
output_tokens: usage?.completion_tokens,
|
|
386
|
+
input_tokens_cache_write: 0,
|
|
387
|
+
input_tokens_cache_read: usage?.prompt_tokens_details?.cached_tokens || 0,
|
|
388
|
+
reasoning_tokens: usage?.completion_tokens_details?.reasoning_tokens || usage?.reasoning_tokens || 0,
|
|
389
|
+
keySource: metadata.keySource,
|
|
390
|
+
agentId: metadata.agentId,
|
|
391
|
+
teamId: metadata.teamId,
|
|
392
|
+
};
|
|
393
|
+
SystemEvents.emit('USAGE:LLM', usageData);
|
|
394
|
+
|
|
395
|
+
return usageData;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
public formatToolsConfig({ type = 'function', toolDefinitions, toolChoice = 'auto' }) {
|
|
399
|
+
let tools: any[] = [];
|
|
400
|
+
|
|
401
|
+
if (type === 'function') {
|
|
402
|
+
tools = toolDefinitions.map((tool) => {
|
|
403
|
+
const { name, description, properties, requiredFields } = tool;
|
|
404
|
+
|
|
405
|
+
return {
|
|
406
|
+
type: 'function',
|
|
407
|
+
function: {
|
|
408
|
+
name,
|
|
409
|
+
description,
|
|
410
|
+
parameters: {
|
|
411
|
+
type: 'object',
|
|
412
|
+
properties,
|
|
413
|
+
required: requiredFields,
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
};
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return tools?.length > 0 ? { tools, tool_choice: toolChoice || 'auto' } : {};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
public transformToolMessageBlocks({
|
|
424
|
+
messageBlock,
|
|
425
|
+
toolsData,
|
|
426
|
+
}: {
|
|
427
|
+
messageBlock: TLLMMessageBlock;
|
|
428
|
+
toolsData: ToolData[];
|
|
429
|
+
}): TLLMToolResultMessageBlock[] {
|
|
430
|
+
const messageBlocks: TLLMToolResultMessageBlock[] = [];
|
|
431
|
+
|
|
432
|
+
if (messageBlock) {
|
|
433
|
+
const transformedMessageBlock = {
|
|
434
|
+
...messageBlock,
|
|
435
|
+
content: typeof messageBlock.content === 'object' ? JSON.stringify(messageBlock.content) : messageBlock.content,
|
|
436
|
+
};
|
|
437
|
+
if (transformedMessageBlock.tool_calls) {
|
|
438
|
+
for (let toolCall of transformedMessageBlock.tool_calls) {
|
|
439
|
+
toolCall.function.arguments =
|
|
440
|
+
typeof toolCall.function.arguments === 'object' ? JSON.stringify(toolCall.function.arguments) : toolCall.function.arguments;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
messageBlocks.push(transformedMessageBlock);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const transformedToolsData = toolsData.map((toolData) => ({
|
|
447
|
+
tool_call_id: toolData.id,
|
|
448
|
+
role: TLLMMessageRole.Tool,
|
|
449
|
+
name: toolData.name,
|
|
450
|
+
content: typeof toolData.result === 'string' ? toolData.result : JSON.stringify(toolData.result),
|
|
451
|
+
}));
|
|
452
|
+
|
|
453
|
+
return [...messageBlocks, ...transformedToolsData];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
public getConsistentMessages(messages) {
|
|
457
|
+
const _messages = LLMHelper.removeDuplicateUserMessages(messages);
|
|
458
|
+
|
|
459
|
+
return _messages.map((message) => {
|
|
460
|
+
const _message = { ...message };
|
|
461
|
+
let textContent = '';
|
|
462
|
+
|
|
463
|
+
if (message?.parts) {
|
|
464
|
+
textContent = message.parts.map((textBlock) => textBlock?.text || '').join(' ');
|
|
465
|
+
} else if (Array.isArray(message?.content)) {
|
|
466
|
+
textContent = message.content.map((textBlock) => textBlock?.text || '').join(' ');
|
|
467
|
+
} else if (message?.content) {
|
|
468
|
+
textContent = message.content;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
_message.content = textContent;
|
|
472
|
+
|
|
473
|
+
return _message;
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
}
|
|
@@ -10,6 +10,7 @@ import { GroqConnector } from './connectors/Groq.class';
|
|
|
10
10
|
import { BedrockConnector } from './connectors/Bedrock.class';
|
|
11
11
|
import { VertexAIConnector } from './connectors/VertexAI.class';
|
|
12
12
|
import { PerplexityConnector } from './connectors/Perplexity.class';
|
|
13
|
+
import { xAIConnector } from './connectors/xAI';
|
|
13
14
|
|
|
14
15
|
export class LLMService extends ConnectorServiceProvider {
|
|
15
16
|
public register() {
|
|
@@ -22,7 +23,7 @@ export class LLMService extends ConnectorServiceProvider {
|
|
|
22
23
|
ConnectorService.register(TConnectorService.LLM, 'TogetherAI', OpenAIConnector);
|
|
23
24
|
ConnectorService.register(TConnectorService.LLM, 'Bedrock', BedrockConnector);
|
|
24
25
|
ConnectorService.register(TConnectorService.LLM, 'VertexAI', VertexAIConnector);
|
|
25
|
-
ConnectorService.register(TConnectorService.LLM, 'xAI',
|
|
26
|
+
ConnectorService.register(TConnectorService.LLM, 'xAI', xAIConnector);
|
|
26
27
|
ConnectorService.register(TConnectorService.LLM, 'Perplexity', PerplexityConnector);
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -95,7 +95,7 @@ export abstract class ModelsProviderConnector extends SecureConnector {
|
|
|
95
95
|
adjustMaxCompletionTokens: async (
|
|
96
96
|
model: string | TLLMModel | TCustomLLMModel,
|
|
97
97
|
maxCompletionTokens: number,
|
|
98
|
-
hasAPIKey: boolean = false
|
|
98
|
+
hasAPIKey: boolean = false
|
|
99
99
|
) => {
|
|
100
100
|
const teamModels = typeof model === 'string' ? await loadTeamModels() : {};
|
|
101
101
|
const modelInfo = await this.getModelInfo(candidate.readRequest, teamModels, model, hasAPIKey);
|
|
@@ -143,20 +143,26 @@ export abstract class ModelsProviderConnector extends SecureConnector {
|
|
|
143
143
|
acRequest: AccessRequest,
|
|
144
144
|
models: TLLMModelsList,
|
|
145
145
|
model: string | TLLMModel | TCustomLLMModel,
|
|
146
|
-
hasAPIKey: boolean = false
|
|
146
|
+
hasAPIKey: boolean = false
|
|
147
147
|
): Promise<TLLMModel> {
|
|
148
148
|
//model can be passed directly, in which case we do not need to look it up in the models list
|
|
149
|
-
if (typeof model === 'object' && model.modelId) {
|
|
150
|
-
return model;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
//model can be passed as a string, in which case we need to look it up in the models list
|
|
154
149
|
|
|
155
|
-
|
|
156
|
-
const alias = models?.[model as string]?.alias;
|
|
157
|
-
const aliasModelInfo = models?.[alias];
|
|
150
|
+
let modelId, alias, aliasModelInfo, modelInfo;
|
|
158
151
|
|
|
159
|
-
|
|
152
|
+
if (typeof model === 'object' && model.modelId) {
|
|
153
|
+
//return model;
|
|
154
|
+
modelId = model.modelId;
|
|
155
|
+
alias = model.alias;
|
|
156
|
+
aliasModelInfo = models?.[alias];
|
|
157
|
+
modelInfo = model;
|
|
158
|
+
} else {
|
|
159
|
+
//model can be passed as a string, in which case we need to look it up in the models list
|
|
160
|
+
|
|
161
|
+
modelId = await this.getModelId(acRequest, models, model);
|
|
162
|
+
alias = models?.[model as string]?.alias;
|
|
163
|
+
aliasModelInfo = models?.[alias];
|
|
164
|
+
modelInfo = models?.[model as string];
|
|
165
|
+
}
|
|
160
166
|
|
|
161
167
|
const aliasKeyOptions = aliasModelInfo && hasAPIKey ? aliasModelInfo?.keyOptions : null;
|
|
162
168
|
|
package/src/types/LLM.types.ts
CHANGED
|
@@ -90,6 +90,24 @@ export type TLLMParams = {
|
|
|
90
90
|
webSearchCountry?: string;
|
|
91
91
|
webSearchRegion?: string;
|
|
92
92
|
webSearchTimezone?: string;
|
|
93
|
+
|
|
94
|
+
// xAI specific search parameters
|
|
95
|
+
useSearch?: boolean;
|
|
96
|
+
searchMode?: 'auto' | 'on' | 'off';
|
|
97
|
+
returnCitations?: boolean;
|
|
98
|
+
maxSearchResults?: number;
|
|
99
|
+
searchDataSources?: string[];
|
|
100
|
+
searchCountry?: string;
|
|
101
|
+
excludedWebsites?: string[];
|
|
102
|
+
allowedWebsites?: string[];
|
|
103
|
+
includedXHandles?: string[];
|
|
104
|
+
excludedXHandles?: string[];
|
|
105
|
+
postFavoriteCount?: number;
|
|
106
|
+
postViewCount?: number;
|
|
107
|
+
rssLinks?: string;
|
|
108
|
+
safeSearch?: boolean;
|
|
109
|
+
fromDate?: string;
|
|
110
|
+
toDate?: string;
|
|
93
111
|
// #endregion
|
|
94
112
|
|
|
95
113
|
useReasoning?: boolean;
|