@smythos/sre 1.5.43 → 1.5.44
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/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/types/Components/GenAILLM.class.d.ts +6 -0
- package/dist/types/helpers/AWSLambdaCode.helper.d.ts +8 -5
- package/dist/types/index.d.ts +1 -0
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/Groq.class.d.ts +5 -0
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.d.ts +0 -4
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.d.ts +0 -4
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.d.ts +6 -0
- package/dist/types/types/LLM.types.d.ts +3 -1
- package/package.json +5 -2
- package/src/Components/GenAILLM.class.ts +8 -1
- package/src/helpers/AWSLambdaCode.helper.ts +82 -22
- package/src/index.ts +193 -192
- package/src/index.ts.bak +193 -192
- package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +10 -8
- package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +16 -3
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +2 -2
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +31 -31
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +31 -22
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.ts +11 -0
- package/src/types/LLM.types.ts +5 -1
|
@@ -2,17 +2,7 @@ import EventEmitter from 'events';
|
|
|
2
2
|
import OpenAI from 'openai';
|
|
3
3
|
import { BinaryInput } from '@sre/helpers/BinaryInput.helper';
|
|
4
4
|
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
|
|
5
|
-
import {
|
|
6
|
-
TLLMParams,
|
|
7
|
-
TLLMPreparedParams,
|
|
8
|
-
ILLMRequestContext,
|
|
9
|
-
ToolData,
|
|
10
|
-
TLLMMessageRole,
|
|
11
|
-
APIKeySource,
|
|
12
|
-
TLLMEvent,
|
|
13
|
-
OpenAIToolDefinition,
|
|
14
|
-
LegacyToolDefinition,
|
|
15
|
-
} from '@sre/types/LLM.types';
|
|
5
|
+
import { TLLMParams, TLLMPreparedParams, ILLMRequestContext, ToolData, TLLMMessageRole, APIKeySource, TLLMEvent } from '@sre/types/LLM.types';
|
|
16
6
|
import { OpenAIApiInterface, ToolConfig } from './OpenAIApiInterface';
|
|
17
7
|
import { HandlerDependencies } from '../types';
|
|
18
8
|
import { JSON_RESPONSE_INSTRUCTION, SUPPORTED_MIME_TYPES_MAP } from '@sre/constants';
|
|
@@ -23,6 +13,8 @@ import {
|
|
|
23
13
|
MODELS_WITHOUT_JSON_RESPONSE_SUPPORT,
|
|
24
14
|
} from './constants';
|
|
25
15
|
|
|
16
|
+
import { isValidOpenAIReasoningEffort } from './utils';
|
|
17
|
+
|
|
26
18
|
// File size limits in bytes
|
|
27
19
|
const MAX_IMAGE_SIZE = 20 * 1024 * 1024; // 20MB
|
|
28
20
|
const MAX_DOCUMENT_SIZE = 25 * 1024 * 1024; // 25MB
|
|
@@ -67,9 +59,6 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
67
59
|
|
|
68
60
|
public handleStream(stream: AsyncIterable<OpenAI.ChatCompletionChunk>, context: ILLMRequestContext): EventEmitter {
|
|
69
61
|
const emitter = new EventEmitter();
|
|
70
|
-
const usage_data: OpenAI.Completions.CompletionUsage[] = [];
|
|
71
|
-
const reportedUsage: any[] = [];
|
|
72
|
-
let finishReason = 'stop';
|
|
73
62
|
|
|
74
63
|
// Process stream asynchronously while returning emitter immediately
|
|
75
64
|
(async () => {
|
|
@@ -77,12 +66,14 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
77
66
|
|
|
78
67
|
try {
|
|
79
68
|
// Step 1: Process the stream
|
|
80
|
-
const streamResult = await this.processStream(stream, emitter
|
|
69
|
+
const streamResult = await this.processStream(stream, emitter);
|
|
81
70
|
finalToolsData = streamResult.toolsData;
|
|
82
|
-
|
|
71
|
+
|
|
72
|
+
const finishReason = streamResult.finishReason || 'stop';
|
|
73
|
+
const usageData = streamResult.usageData;
|
|
83
74
|
|
|
84
75
|
// Step 2: Report usage statistics
|
|
85
|
-
this.reportUsageStatistics(
|
|
76
|
+
const reportedUsage = this.reportUsageStatistics(usageData, context);
|
|
86
77
|
|
|
87
78
|
// Step 3: Emit final events
|
|
88
79
|
this.emitFinalEvents(emitter, finalToolsData, reportedUsage, finishReason);
|
|
@@ -172,6 +163,18 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
172
163
|
body.stop = params.stopSequences;
|
|
173
164
|
}
|
|
174
165
|
|
|
166
|
+
// #region GPT 5 specific fields
|
|
167
|
+
const isGPT5ReasoningModels = params.modelEntryName?.includes('gpt-5') && params?.capabilities?.reasoning;
|
|
168
|
+
if (isGPT5ReasoningModels && params?.verbosity) {
|
|
169
|
+
body.verbosity = params.verbosity;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// We need to validate the `reasoningEffort` parameter for OpenAI models, since models like `qwen/qwen3-32b` and `deepseek-r1-distill-llama-70b` (available via Groq) also support this parameter but use different values, such as `none` and `default`. These values are valid in our system but not specifically for OpenAI.
|
|
173
|
+
if (isGPT5ReasoningModels && isValidOpenAIReasoningEffort(params.reasoningEffort)) {
|
|
174
|
+
body.reasoning_effort = params.reasoningEffort;
|
|
175
|
+
}
|
|
176
|
+
// #endregion GPT 5 specific fields
|
|
177
|
+
|
|
175
178
|
// Handle tools configuration
|
|
176
179
|
if (params?.toolsConfig?.tools && params?.toolsConfig?.tools?.length > 0) {
|
|
177
180
|
body.tools = params?.toolsConfig?.tools as OpenAI.ChatCompletionTool[];
|
|
@@ -181,20 +184,13 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
181
184
|
return body;
|
|
182
185
|
}
|
|
183
186
|
|
|
184
|
-
/**
|
|
185
|
-
* Type guard to check if a tool is an OpenAI tool definition
|
|
186
|
-
*/
|
|
187
|
-
private isOpenAIToolDefinition(tool: OpenAIToolDefinition | LegacyToolDefinition): tool is OpenAIToolDefinition {
|
|
188
|
-
return 'parameters' in tool;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
187
|
/**
|
|
192
188
|
* Transform OpenAI tool definitions to ChatCompletionTool format
|
|
193
189
|
*/
|
|
194
190
|
public transformToolsConfig(config: ToolConfig): OpenAI.ChatCompletionTool[] {
|
|
195
191
|
return config.toolDefinitions.map((tool) => {
|
|
196
192
|
// Handle OpenAI tool definition format
|
|
197
|
-
if (
|
|
193
|
+
if ('parameters' in tool) {
|
|
198
194
|
return {
|
|
199
195
|
type: 'function',
|
|
200
196
|
function: {
|
|
@@ -259,11 +255,11 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
259
255
|
*/
|
|
260
256
|
private async processStream(
|
|
261
257
|
stream: AsyncIterable<OpenAI.ChatCompletionChunk>,
|
|
262
|
-
emitter: EventEmitter
|
|
263
|
-
|
|
264
|
-
): Promise<{ toolsData: ToolData[]; finishReason: string }> {
|
|
258
|
+
emitter: EventEmitter
|
|
259
|
+
): Promise<{ toolsData: ToolData[]; finishReason: string; usageData: any[] }> {
|
|
265
260
|
let toolsData: ToolData[] = [];
|
|
266
261
|
let finishReason = 'stop';
|
|
262
|
+
const usageData = [];
|
|
267
263
|
|
|
268
264
|
for await (const part of stream) {
|
|
269
265
|
const delta = part.choices[0]?.delta;
|
|
@@ -271,7 +267,7 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
271
267
|
|
|
272
268
|
// Collect usage statistics
|
|
273
269
|
if (usage) {
|
|
274
|
-
|
|
270
|
+
usageData.push(usage);
|
|
275
271
|
}
|
|
276
272
|
|
|
277
273
|
// Emit data event for delta
|
|
@@ -315,7 +311,7 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
315
311
|
}
|
|
316
312
|
}
|
|
317
313
|
|
|
318
|
-
return { toolsData: this.extractToolCalls(toolsData), finishReason };
|
|
314
|
+
return { toolsData: this.extractToolCalls(toolsData), finishReason, usageData };
|
|
319
315
|
}
|
|
320
316
|
|
|
321
317
|
/**
|
|
@@ -335,12 +331,16 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
|
|
|
335
331
|
/**
|
|
336
332
|
* Report usage statistics
|
|
337
333
|
*/
|
|
338
|
-
private reportUsageStatistics(usage_data: OpenAI.Completions.CompletionUsage[], context: ILLMRequestContext
|
|
334
|
+
private reportUsageStatistics(usage_data: OpenAI.Completions.CompletionUsage[], context: ILLMRequestContext): any[] {
|
|
335
|
+
const reportedUsage: any[] = [];
|
|
336
|
+
|
|
339
337
|
// Report normal usage
|
|
340
338
|
usage_data.forEach((usage) => {
|
|
341
339
|
const reported = this.deps.reportUsage(usage, this.buildUsageContext(context));
|
|
342
340
|
reportedUsage.push(reported);
|
|
343
341
|
});
|
|
342
|
+
|
|
343
|
+
return reportedUsage;
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
/**
|
|
@@ -22,12 +22,12 @@ import { OpenAIApiInterface, ToolConfig } from './OpenAIApiInterface';
|
|
|
22
22
|
import { HandlerDependencies, TToolType } from '../types';
|
|
23
23
|
import { SUPPORTED_MIME_TYPES_MAP } from '@sre/constants';
|
|
24
24
|
import { MODELS_WITHOUT_TEMPERATURE_SUPPORT, SEARCH_TOOL_COSTS } from './constants';
|
|
25
|
+
import { isValidOpenAIReasoningEffort } from './utils';
|
|
25
26
|
|
|
26
27
|
// File size limits in bytes
|
|
27
28
|
const MAX_IMAGE_SIZE = 20 * 1024 * 1024; // 20MB
|
|
28
29
|
const MAX_DOCUMENT_SIZE = 25 * 1024 * 1024; // 25MB
|
|
29
30
|
|
|
30
|
-
type TSearchContextSize = 'low' | 'medium' | 'high';
|
|
31
31
|
type TSearchLocation = {
|
|
32
32
|
type: 'approximate';
|
|
33
33
|
city?: string;
|
|
@@ -75,9 +75,6 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
75
75
|
|
|
76
76
|
public handleStream(stream: Stream<OpenAI.Responses.ResponseStreamEvent>, context: ILLMRequestContext): EventEmitter {
|
|
77
77
|
const emitter = new EventEmitter();
|
|
78
|
-
const usage_data: any[] = [];
|
|
79
|
-
const reportedUsage: any[] = [];
|
|
80
|
-
let finishReason = 'stop';
|
|
81
78
|
|
|
82
79
|
// Process stream asynchronously while returning emitter immediately
|
|
83
80
|
(async () => {
|
|
@@ -85,12 +82,14 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
85
82
|
|
|
86
83
|
try {
|
|
87
84
|
// Step 1: Process the stream
|
|
88
|
-
const streamResult = await this.processStream(stream, emitter
|
|
85
|
+
const streamResult = await this.processStream(stream, emitter);
|
|
89
86
|
finalToolsData = streamResult.toolsData;
|
|
90
|
-
|
|
87
|
+
|
|
88
|
+
const finishReason = streamResult.finishReason || 'stop';
|
|
89
|
+
const usageData = streamResult.usageData;
|
|
91
90
|
|
|
92
91
|
// Step 2: Report usage statistics
|
|
93
|
-
this.reportUsageStatistics(
|
|
92
|
+
const reportedUsage = this.reportUsageStatistics(usageData, context);
|
|
94
93
|
|
|
95
94
|
// Step 3: Emit final events
|
|
96
95
|
this.emitFinalEvents(emitter, finalToolsData, reportedUsage, finishReason);
|
|
@@ -107,11 +106,11 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
107
106
|
*/
|
|
108
107
|
private async processStream(
|
|
109
108
|
stream: Stream<OpenAI.Responses.ResponseStreamEvent>,
|
|
110
|
-
emitter: EventEmitter
|
|
111
|
-
|
|
112
|
-
): Promise<{ toolsData: ToolData[]; finishReason: string }> {
|
|
109
|
+
emitter: EventEmitter
|
|
110
|
+
): Promise<{ toolsData: ToolData[]; finishReason: string; usageData: any[] }> {
|
|
113
111
|
let toolsData: ToolData[] = [];
|
|
114
112
|
let finishReason = 'stop';
|
|
113
|
+
const usageData = [];
|
|
115
114
|
|
|
116
115
|
for await (const part of stream) {
|
|
117
116
|
// Handle different event types from the Responses API stream
|
|
@@ -189,12 +188,12 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
189
188
|
}
|
|
190
189
|
|
|
191
190
|
// Handle usage statistics from response object
|
|
192
|
-
if ('response'
|
|
193
|
-
|
|
191
|
+
if (part?.type === 'response.completed' && part?.response?.usage) {
|
|
192
|
+
usageData.push(part.response.usage);
|
|
194
193
|
}
|
|
195
194
|
}
|
|
196
195
|
|
|
197
|
-
return { toolsData: this.extractToolCalls(toolsData), finishReason };
|
|
196
|
+
return { toolsData: this.extractToolCalls(toolsData), finishReason, usageData };
|
|
198
197
|
}
|
|
199
198
|
|
|
200
199
|
/**
|
|
@@ -214,7 +213,9 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
214
213
|
/**
|
|
215
214
|
* Report usage statistics
|
|
216
215
|
*/
|
|
217
|
-
private reportUsageStatistics(usage_data: any[], context: ILLMRequestContext
|
|
216
|
+
private reportUsageStatistics(usage_data: any[], context: ILLMRequestContext): any[] {
|
|
217
|
+
const reportedUsage: any[] = [];
|
|
218
|
+
|
|
218
219
|
// Report normal usage
|
|
219
220
|
usage_data.forEach((usage) => {
|
|
220
221
|
// Convert ResponseUsage to CompletionUsage format for compatibility
|
|
@@ -234,6 +235,8 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
234
235
|
const reported = this.deps.reportUsage(searchUsage, this.buildUsageContext(context));
|
|
235
236
|
reportedUsage.push(reported);
|
|
236
237
|
}
|
|
238
|
+
|
|
239
|
+
return reportedUsage;
|
|
237
240
|
}
|
|
238
241
|
|
|
239
242
|
/**
|
|
@@ -310,6 +313,19 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
310
313
|
body.top_p = params.topP;
|
|
311
314
|
}
|
|
312
315
|
|
|
316
|
+
// #region GPT 5 specific fields
|
|
317
|
+
|
|
318
|
+
const isGPT5ReasoningModels = params.modelEntryName?.includes('gpt-5') && params?.capabilities?.reasoning;
|
|
319
|
+
if (isGPT5ReasoningModels && params?.verbosity) {
|
|
320
|
+
body.text = { verbosity: params.verbosity };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// We need to validate the `reasoningEffort` parameter for OpenAI models, since models like `qwen/qwen3-32b` and `deepseek-r1-distill-llama-70b` (available via Groq) also support this parameter but use different values, such as `none` and `default`. These values are valid in our system but not specifically for OpenAI.
|
|
324
|
+
if (isGPT5ReasoningModels && isValidOpenAIReasoningEffort(params.reasoningEffort)) {
|
|
325
|
+
body.reasoning = { effort: params.reasoningEffort };
|
|
326
|
+
}
|
|
327
|
+
// #endregion GPT 5 specific fields
|
|
328
|
+
|
|
313
329
|
let tools: OpenAI.Responses.Tool[] = [];
|
|
314
330
|
|
|
315
331
|
if (params?.toolsConfig?.tools && params?.toolsConfig?.tools?.length > 0) {
|
|
@@ -333,20 +349,13 @@ export class ResponsesApiInterface extends OpenAIApiInterface {
|
|
|
333
349
|
return body;
|
|
334
350
|
}
|
|
335
351
|
|
|
336
|
-
/**
|
|
337
|
-
* Type guard to check if a tool is an OpenAI tool definition
|
|
338
|
-
*/
|
|
339
|
-
private isOpenAIToolDefinition(tool: OpenAIToolDefinition | LegacyToolDefinition): tool is OpenAIToolDefinition {
|
|
340
|
-
return 'parameters' in tool;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
352
|
/**
|
|
344
353
|
* Transform OpenAI tool definitions to Responses.Tool format
|
|
345
354
|
*/
|
|
346
355
|
public transformToolsConfig(config: ToolConfig): OpenAI.Responses.Tool[] {
|
|
347
356
|
return config.toolDefinitions.map((tool) => {
|
|
348
357
|
// Handle OpenAI tool definition format
|
|
349
|
-
if (
|
|
358
|
+
if ('parameters' in tool) {
|
|
350
359
|
return {
|
|
351
360
|
type: 'function' as const,
|
|
352
361
|
name: tool.name,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
|
|
3
|
+
// * We may move some OpenAI Connector–related utility functions here in the future.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Type guard to check if a value is a valid OpenAI reasoning effort.
|
|
7
|
+
* Uses array includes for better maintainability when OpenAI adds new values.
|
|
8
|
+
*/
|
|
9
|
+
export function isValidOpenAIReasoningEffort(value: unknown): value is OpenAI.Responses.ResponseCreateParams['reasoning']['effort'] {
|
|
10
|
+
return ['minimal', 'low', 'medium', 'high'].includes(value as string);
|
|
11
|
+
}
|
package/src/types/LLM.types.ts
CHANGED
|
@@ -45,6 +45,9 @@ export type ILLMConnectorCredentials = BasicCredentials | BedrockCredentials | V
|
|
|
45
45
|
export type TOpenAIResponseToolChoice = OpenAI.Responses.ToolChoiceOptions | OpenAI.Responses.ToolChoiceTypes | OpenAI.Responses.ToolChoiceFunction;
|
|
46
46
|
export type TLLMToolChoice = OpenAI.ChatCompletionToolChoiceOption;
|
|
47
47
|
|
|
48
|
+
// Local alias to the upstream OpenAI reasoning effort union type
|
|
49
|
+
export type OpenAIReasoningEffort = NonNullable<OpenAI.Responses.ResponseCreateParams['reasoning']>['effort'];
|
|
50
|
+
|
|
48
51
|
export type TOpenAIToolsInfo = {
|
|
49
52
|
webSearch: {
|
|
50
53
|
enabled: boolean;
|
|
@@ -154,8 +157,9 @@ export type TLLMParams = {
|
|
|
154
157
|
* For GPT-OSS models (20B, 120B): "low" | "medium" | "high"
|
|
155
158
|
* For Qwen 3 32B: "none" | "default"
|
|
156
159
|
*/
|
|
157
|
-
reasoningEffort?: 'none' | 'default' |
|
|
160
|
+
reasoningEffort?: 'none' | 'default' | OpenAIReasoningEffort;
|
|
158
161
|
max_output_tokens?: number;
|
|
162
|
+
verbosity?: OpenAI.Responses.ResponseCreateParams['text']['verbosity'];
|
|
159
163
|
abortSignal?: AbortSignal;
|
|
160
164
|
};
|
|
161
165
|
|