@smythos/sre 1.5.65 → 1.5.67
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 +25 -25
- package/dist/index.js.map +1 -1
- package/dist/types/Components/FTimestamp.class.d.ts +3 -8
- package/dist/types/Components/Triggers/GmailTrigger.class.d.ts +13 -0
- package/dist/types/Components/Triggers/Trigger.class.d.ts +3 -0
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +16 -2
- package/dist/types/types/LLM.types.d.ts +21 -3
- package/package.json +1 -1
- package/src/Components/FTimestamp.class.ts +46 -5
- package/src/Components/ImageGenerator.class.ts +13 -32
- package/src/Components/MCPClient.class.ts +28 -29
- package/src/helpers/Conversation.helper.ts +2 -0
- package/src/index.ts +193 -193
- package/src/index.ts.bak +193 -193
- package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +248 -29
- package/src/types/LLM.types.ts +24 -3
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { Component } from './Component.class';
|
|
2
2
|
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
3
|
+
import Joi from 'joi';
|
|
3
4
|
export declare class FTimestamp extends Component {
|
|
5
|
+
protected configSchema: Joi.ObjectSchema<any>;
|
|
4
6
|
constructor();
|
|
5
7
|
init(): void;
|
|
6
8
|
process(input: any, config: any, agent: Agent): Promise<{
|
|
7
|
-
Timestamp: number;
|
|
9
|
+
Timestamp: string | number;
|
|
8
10
|
_error: any;
|
|
9
11
|
_debug: string;
|
|
10
12
|
_debug_time: number;
|
|
11
|
-
hash?: undefined;
|
|
12
|
-
} | {
|
|
13
|
-
hash: any;
|
|
14
|
-
_error: any;
|
|
15
|
-
_debug: string;
|
|
16
|
-
_debug_time: number;
|
|
17
|
-
Timestamp?: undefined;
|
|
18
13
|
}>;
|
|
19
14
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
2
|
+
import { Trigger } from './Trigger.class';
|
|
3
|
+
export declare class GmailTrigger extends Trigger {
|
|
4
|
+
init(): void;
|
|
5
|
+
process(input: any, config: any, agent: Agent): Promise<{
|
|
6
|
+
Payload: {};
|
|
7
|
+
Result: any;
|
|
8
|
+
_temp_result: any;
|
|
9
|
+
_error: any;
|
|
10
|
+
_in_progress: boolean;
|
|
11
|
+
_debug: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import { UsageMetadata } from '@google/generative-ai';
|
|
3
|
-
import { TLLMMessageBlock, ToolData, TLLMToolResultMessageBlock, APIKeySource, ILLMRequestFuncParams, TLLMChatResponse, TGoogleAIRequestBody, TLLMPreparedParams } from '@sre/types/LLM.types';
|
|
3
|
+
import { TLLMMessageBlock, ToolData, TLLMToolResultMessageBlock, APIKeySource, ILLMRequestFuncParams, TLLMChatResponse, TGoogleAIRequestBody, ILLMRequestContext, TLLMPreparedParams } from '@sre/types/LLM.types';
|
|
4
4
|
import { LLMConnector } from '../LLMConnector';
|
|
5
5
|
type UsageMetadataWithThoughtsToken = UsageMetadata & {
|
|
6
|
-
thoughtsTokenCount
|
|
6
|
+
thoughtsTokenCount?: number;
|
|
7
|
+
cost?: number;
|
|
7
8
|
};
|
|
8
9
|
export declare class GoogleAIConnector extends LLMConnector {
|
|
9
10
|
name: string;
|
|
@@ -32,6 +33,18 @@ export declare class GoogleAIConnector extends LLMConnector {
|
|
|
32
33
|
teamId: string;
|
|
33
34
|
tier: string;
|
|
34
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Extract text and image tokens from Google AI usage metadata
|
|
38
|
+
*/
|
|
39
|
+
private extractTokenCounts;
|
|
40
|
+
protected reportImageUsage({ usage, context, numberOfImages, }: {
|
|
41
|
+
usage: {
|
|
42
|
+
cost?: number;
|
|
43
|
+
usageMetadata?: UsageMetadataWithThoughtsToken;
|
|
44
|
+
};
|
|
45
|
+
context: ILLMRequestContext;
|
|
46
|
+
numberOfImages?: number;
|
|
47
|
+
}): void;
|
|
35
48
|
formatToolsConfig({ toolDefinitions, toolChoice }: {
|
|
36
49
|
toolDefinitions: any;
|
|
37
50
|
toolChoice?: string;
|
|
@@ -51,6 +64,7 @@ export declare class GoogleAIConnector extends LLMConnector {
|
|
|
51
64
|
private prepareMessagesWithTools;
|
|
52
65
|
private prepareMessagesWithTextQuery;
|
|
53
66
|
private prepareBodyForImageGenRequest;
|
|
67
|
+
private prepareImageEditBody;
|
|
54
68
|
private sanitizeFunctionName;
|
|
55
69
|
private uploadFile;
|
|
56
70
|
private getValidFiles;
|
|
@@ -193,11 +193,29 @@ export type TLLMModel = {
|
|
|
193
193
|
params?: TLLMParams;
|
|
194
194
|
/**
|
|
195
195
|
* Specifies the API interface type to use for this model
|
|
196
|
-
*
|
|
197
|
-
* This determines which OpenAI API endpoint and interface implementation to use
|
|
196
|
+
* This determines which API endpoint and interface implementation to use
|
|
198
197
|
*/
|
|
199
|
-
interface?:
|
|
198
|
+
interface?: LLMInterface;
|
|
199
|
+
/**
|
|
200
|
+
* Indicates whether this model supports image editing functionality
|
|
201
|
+
* Only applicable for image generation models
|
|
202
|
+
*/
|
|
203
|
+
supportsEditing?: boolean;
|
|
200
204
|
};
|
|
205
|
+
/**
|
|
206
|
+
* Enum for different LLM API interfaces
|
|
207
|
+
* Each interface represents a different API endpoint or interaction pattern
|
|
208
|
+
*/
|
|
209
|
+
export declare enum LLMInterface {
|
|
210
|
+
/** OpenAI-style chat completions API */
|
|
211
|
+
ChatCompletions = "chat.completions",
|
|
212
|
+
/** OpenAI-style responses API */
|
|
213
|
+
Responses = "responses",
|
|
214
|
+
/** Google AI generateContent API (for text and multimodal) */
|
|
215
|
+
GenerateContent = "generateContent",
|
|
216
|
+
/** Google AI generateImages API (for traditional Imagen models) */
|
|
217
|
+
GenerateImages = "generateImages"
|
|
218
|
+
}
|
|
201
219
|
export declare const BuiltinLLMProviders: {
|
|
202
220
|
readonly Echo: "Echo";
|
|
203
221
|
readonly OpenAI: "OpenAI";
|
package/package.json
CHANGED
|
@@ -1,25 +1,66 @@
|
|
|
1
1
|
import { Component } from './Component.class';
|
|
2
2
|
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
3
|
+
import Joi from 'joi';
|
|
4
|
+
import dayjs from 'dayjs';
|
|
3
5
|
|
|
4
6
|
export class FTimestamp extends Component {
|
|
7
|
+
protected configSchema = Joi.object({
|
|
8
|
+
format: Joi.alternatives()
|
|
9
|
+
.try(Joi.string().valid('unix', 'iso', 'timestamp'), Joi.string().pattern(/^[YMDHhmsSSZzAa\s\-\/:,\.]*$/, 'custom dayjs format'))
|
|
10
|
+
.default('unix')
|
|
11
|
+
.allow(null)
|
|
12
|
+
.label('Timestamp Format')
|
|
13
|
+
.messages({
|
|
14
|
+
'string.pattern.name': 'Invalid format string: {#value}',
|
|
15
|
+
}),
|
|
16
|
+
});
|
|
17
|
+
|
|
5
18
|
constructor() {
|
|
6
19
|
super();
|
|
7
20
|
}
|
|
8
21
|
init() {}
|
|
9
22
|
async process(input, config, agent: Agent) {
|
|
10
23
|
await super.process(input, config, agent);
|
|
24
|
+
|
|
11
25
|
const logger = this.createComponentLogger(agent, config);
|
|
26
|
+
|
|
27
|
+
const validationResult = await this.validateConfig(config);
|
|
28
|
+
if (validationResult._error) {
|
|
29
|
+
return {
|
|
30
|
+
Timestamp: undefined,
|
|
31
|
+
_error: validationResult._error,
|
|
32
|
+
_debug: logger.output,
|
|
33
|
+
_debug_time: logger.elapsedTime,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
12
36
|
try {
|
|
13
37
|
const _error = undefined;
|
|
14
|
-
const format = config.data.format
|
|
15
|
-
const
|
|
16
|
-
|
|
38
|
+
const format = config.data.format || 'unix';
|
|
39
|
+
const now = dayjs();
|
|
40
|
+
|
|
41
|
+
let Timestamp: number | string;
|
|
42
|
+
|
|
43
|
+
switch (format) {
|
|
44
|
+
case 'unix':
|
|
45
|
+
case 'timestamp':
|
|
46
|
+
Timestamp = Date.now();
|
|
47
|
+
logger.debug(`Unix timestamp: ${Timestamp}`);
|
|
48
|
+
break;
|
|
49
|
+
case 'iso':
|
|
50
|
+
Timestamp = now.toISOString();
|
|
51
|
+
logger.debug(`ISO timestamp: ${Timestamp}`);
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
Timestamp = now.format(format);
|
|
55
|
+
logger.debug(`Custom formatted timestamp (${format}): ${Timestamp}`);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
17
58
|
|
|
18
59
|
return { Timestamp, _error, _debug: logger.output, _debug_time: logger.elapsedTime };
|
|
19
60
|
} catch (err: any) {
|
|
20
61
|
const _error = err?.response?.data || err?.message || err.toString();
|
|
21
|
-
logger.error(` Error processing
|
|
22
|
-
return {
|
|
62
|
+
logger.error(` Error processing timestamp \n${_error}\n`);
|
|
63
|
+
return { Timestamp: undefined, _error, _debug: logger.output, _debug_time: logger.elapsedTime };
|
|
23
64
|
}
|
|
24
65
|
}
|
|
25
66
|
}
|
|
@@ -44,12 +44,6 @@ const IMAGE_GEN_COST_MAP = {
|
|
|
44
44
|
},
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
// Imagen 4 cost map - fixed cost per image
|
|
48
|
-
const IMAGEN_4_COST_MAP = {
|
|
49
|
-
'imagen-4': 0.04, // Standard Imagen 4
|
|
50
|
-
'imagen-4-ultra': 0.06, // Imagen 4 Ultra
|
|
51
|
-
};
|
|
52
|
-
|
|
53
47
|
export class ImageGenerator extends Component {
|
|
54
48
|
protected configSchema = Joi.object({
|
|
55
49
|
model: Joi.string().max(100).required(),
|
|
@@ -344,11 +338,6 @@ const imageGenerator = {
|
|
|
344
338
|
|
|
345
339
|
const files: any[] = parseFiles(input, config);
|
|
346
340
|
|
|
347
|
-
// Imagen models only support image generation, not image editing
|
|
348
|
-
if (files.length > 0) {
|
|
349
|
-
throw new Error('Google AI Image Generation Error: Image editing is not supported. Imagen models only support image generation.');
|
|
350
|
-
}
|
|
351
|
-
|
|
352
341
|
let args: GenerateImageConfig & {
|
|
353
342
|
aspectRatio?: string;
|
|
354
343
|
numberOfImages?: number;
|
|
@@ -360,29 +349,21 @@ const imageGenerator = {
|
|
|
360
349
|
personGeneration: config?.data?.personGeneration || 'allow_adult',
|
|
361
350
|
};
|
|
362
351
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
//
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
// Report fixed cost usage
|
|
375
|
-
imageGenerator.reportUsage(
|
|
376
|
-
{ cost: totalCost },
|
|
377
|
-
{
|
|
378
|
-
modelEntryName: model,
|
|
379
|
-
keySource: model.startsWith(BUILT_IN_MODEL_PREFIX) ? APIKeySource.Smyth : APIKeySource.User,
|
|
380
|
-
agentId: agent.id,
|
|
381
|
-
teamId: agent.teamId,
|
|
382
|
-
}
|
|
383
|
-
);
|
|
352
|
+
let response;
|
|
353
|
+
|
|
354
|
+
// Check if files are provided for image editing
|
|
355
|
+
if (files.length > 0) {
|
|
356
|
+
const validFiles = files.filter((file) => imageGenerator.isValidImageFile('GoogleAI', file.mimetype));
|
|
357
|
+
if (validFiles.length === 0) {
|
|
358
|
+
throw new Error('Supported image file types are: ' + SUPPORTED_MIME_TYPES_MAP.GoogleAI?.image?.join(', '));
|
|
359
|
+
}
|
|
360
|
+
response = await llmInference.imageEditRequest({ query: prompt, files: validFiles, params: { ...args, agentId: agent.id } });
|
|
361
|
+
} else {
|
|
362
|
+
response = await llmInference.imageGenRequest({ query: prompt, params: { ...args, agentId: agent.id } });
|
|
384
363
|
}
|
|
385
364
|
|
|
365
|
+
// Usage reporting is now handled in the GoogleAI connector
|
|
366
|
+
|
|
386
367
|
let output = response?.data?.[0]?.b64_json;
|
|
387
368
|
|
|
388
369
|
if (output) {
|
|
@@ -14,9 +14,9 @@ export class MCPClient extends Component {
|
|
|
14
14
|
model: Joi.string().optional(),
|
|
15
15
|
openAiModel: Joi.string().optional(), // for backward compatibility
|
|
16
16
|
mcpUrl: Joi.string().max(2048).uri().required().description('URL of the MCP'),
|
|
17
|
-
descForModel: Joi.string().max(5000).
|
|
17
|
+
descForModel: Joi.string().max(5000).allow('').label('Description for Model'),
|
|
18
18
|
name: Joi.string().max(500).required().allow(''),
|
|
19
|
-
desc: Joi.string().max(5000).
|
|
19
|
+
desc: Joi.string().max(5000).allow('').label('Description'),
|
|
20
20
|
logoUrl: Joi.string().max(8192).allow(''),
|
|
21
21
|
id: Joi.string().max(200),
|
|
22
22
|
version: Joi.string().max(100).allow(''),
|
|
@@ -51,7 +51,7 @@ export class MCPClient extends Component {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// TODO [Forhad]: Need to check and validate input prompt token
|
|
54
|
-
const { client } = await this.connectMCP(mcpUrl);
|
|
54
|
+
const { client } = await this.connectMCP(mcpUrl, logger);
|
|
55
55
|
|
|
56
56
|
const toolsData = await client.listTools();
|
|
57
57
|
const conv = new Conversation(
|
|
@@ -70,7 +70,7 @@ export class MCPClient extends Component {
|
|
|
70
70
|
],
|
|
71
71
|
paths: {},
|
|
72
72
|
},
|
|
73
|
-
{ agentId: agent?.id }
|
|
73
|
+
{ agentId: agent?.id }
|
|
74
74
|
);
|
|
75
75
|
|
|
76
76
|
for (const tool of toolsData.tools) {
|
|
@@ -105,34 +105,33 @@ export class MCPClient extends Component {
|
|
|
105
105
|
return { _error: `Error on running MCP Client!\n${error?.message || JSON.stringify(error)}`, _debug: logger.output };
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
private async connectMCP(mcpUrl: string) {
|
|
108
|
+
private async connectMCP(mcpUrl: string, logger: any) {
|
|
109
109
|
const client = new Client({ name: 'auto-client', version: '1.0.0' });
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
// 1) Try Streamable HTTP first
|
|
112
112
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
const st = new StreamableHTTPClientTransport(new URL(mcpUrl));
|
|
114
|
+
await client.connect(st);
|
|
115
|
+
logger.debug('Connected to MCP using Streamable HTTP');
|
|
116
|
+
return { client, transport: 'streamable' as const };
|
|
117
117
|
} catch (e: any) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return { client, transport: 'sse' as const };
|
|
118
|
+
logger.debug('Failed to connect to MCP using Streamable HTTP, falling back to SSE');
|
|
119
|
+
// 2) If clearly unsupported, fall back to SSE
|
|
120
|
+
const msg = String(e?.message || e);
|
|
121
|
+
const isUnsupported = /404|405|ENOTFOUND|ECONNREFUSED|CORS/i.test(msg);
|
|
122
|
+
|
|
123
|
+
// 406 means wrong/missing Accept for Streamable → retry Streamable with proper header
|
|
124
|
+
const isAcceptProblem = /406|Not Acceptable|text\/event-stream/i.test(msg);
|
|
125
|
+
if (isAcceptProblem) {
|
|
126
|
+
throw new Error('Server is Streamable; include Accept: application/json, text/event-stream');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!isUnsupported) throw e;
|
|
130
|
+
|
|
131
|
+
// SSE fallback
|
|
132
|
+
const sse = new SSEClientTransport(new URL(mcpUrl));
|
|
133
|
+
await client.connect(sse);
|
|
134
|
+
return { client, transport: 'sse' as const };
|
|
136
135
|
}
|
|
137
|
-
|
|
136
|
+
}
|
|
138
137
|
}
|
|
@@ -281,6 +281,8 @@ export class Conversation extends EventEmitter {
|
|
|
281
281
|
let _content = '';
|
|
282
282
|
const reqMethods = this._reqMethods;
|
|
283
283
|
const toolsConfig = this._toolsConfig;
|
|
284
|
+
//deduplicate tools
|
|
285
|
+
toolsConfig.tools = toolsConfig.tools.filter((tool, index, self) => self.findIndex((t) => t.name === tool.name) === index);
|
|
284
286
|
const endpoints = this._endpoints;
|
|
285
287
|
const baseUrl = this._baseUrl;
|
|
286
288
|
const message_id = 'msg_' + randomUUID();
|