@smythos/sre 1.7.40 → 1.7.42
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 +49 -42
- package/dist/index.js.map +1 -1
- package/dist/types/Components/AgentPlugin.class.d.ts +1 -1
- package/dist/types/Components/RAG/DataSourceCleaner.class.d.ts +4 -4
- package/dist/types/Components/RAG/DataSourceComponent.class.d.ts +5 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/helpers/Conversation.helper.d.ts +10 -13
- package/dist/types/helpers/TemplateString.helper.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/subsystems/IO/VectorDB.service/VectorDBConnector.d.ts +1 -0
- package/dist/types/subsystems/LLMManager/LLM.helper.d.ts +19 -0
- package/dist/types/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.d.ts +15 -10
- package/dist/types/types/LLM.types.d.ts +23 -0
- package/package.json +1 -1
- package/src/Components/AgentPlugin.class.ts +20 -3
- package/src/Components/Classifier.class.ts +79 -16
- package/src/Components/ForEach.class.ts +34 -6
- package/src/Components/GenAILLM.class.ts +54 -23
- package/src/Components/LLMAssistant.class.ts +56 -21
- package/src/Components/RAG/DataSourceCleaner.class.ts +13 -11
- package/src/Components/RAG/DataSourceComponent.class.ts +39 -13
- package/src/Components/RAG/DataSourceIndexer.class.ts +18 -12
- package/src/Components/RAG/DataSourceLookup.class.ts +14 -10
- package/src/Components/ScrapflyWebScrape.class.ts +7 -0
- package/src/config.ts +1 -0
- package/src/helpers/Conversation.helper.ts +112 -26
- package/src/helpers/TemplateString.helper.ts +6 -5
- package/src/index.ts +213 -212
- package/src/index.ts.bak +213 -212
- package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +1 -0
- package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +11 -0
- package/src/subsystems/IO/VectorDB.service/embed/index.ts +9 -11
- package/src/subsystems/LLMManager/LLM.helper.ts +25 -0
- package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +1 -1
- package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +190 -146
- package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.ts +1 -1
- package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.ts +402 -66
- package/src/types/LLM.types.ts +24 -0
- package/src/utils/data.utils.ts +6 -4
- package/src/Components/DataSourceIndexer.class.ts +0 -295
|
@@ -6,13 +6,13 @@ export declare class DataSourceCleaner extends DataSourceComponent {
|
|
|
6
6
|
constructor();
|
|
7
7
|
init(): void;
|
|
8
8
|
process(input: any, config: any, agent: Agent): Promise<{
|
|
9
|
-
_debug: string;
|
|
10
|
-
Success: boolean;
|
|
11
|
-
_error?: undefined;
|
|
12
|
-
} | {
|
|
13
9
|
_debug: string;
|
|
14
10
|
_error: any;
|
|
15
11
|
Success?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
_debug: string;
|
|
14
|
+
Success: boolean;
|
|
15
|
+
_error?: undefined;
|
|
16
16
|
}>;
|
|
17
17
|
processV1(input: any, config: any, agent: Agent): Promise<{
|
|
18
18
|
_debug: string;
|
|
@@ -21,7 +21,11 @@ export declare class DataSourceCompError extends Error {
|
|
|
21
21
|
}
|
|
22
22
|
export declare class DataSourceComponent extends Component {
|
|
23
23
|
constructor();
|
|
24
|
-
resolveVectorDbConnector(namespace: string | NsRecord, teamId: string): Promise<
|
|
24
|
+
resolveVectorDbConnector(namespace: string | NsRecord, teamId: string): Promise<{
|
|
25
|
+
vecDbConnector: VectorDBConnector;
|
|
26
|
+
namespaceRecord: NsRecord;
|
|
27
|
+
}>;
|
|
28
|
+
private resolveNamespaceRecord;
|
|
25
29
|
buildEmbeddingConfig(embedding: {
|
|
26
30
|
dimensions: string;
|
|
27
31
|
modelId: string;
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LLMInference } from '@sre/LLMManager/LLM.inference';
|
|
2
2
|
import { LLMContext } from '@sre/MemoryManager/LLMContext';
|
|
3
|
-
import {
|
|
3
|
+
import { IConversationSettings, TLLMModel } from '@sre/types/LLM.types';
|
|
4
4
|
import EventEmitter from 'events';
|
|
5
5
|
export declare class Conversation extends EventEmitter {
|
|
6
6
|
private _model;
|
|
@@ -30,7 +30,15 @@ export declare class Conversation extends EventEmitter {
|
|
|
30
30
|
agentData: any;
|
|
31
31
|
private _id;
|
|
32
32
|
get id(): string;
|
|
33
|
+
private _toolCallCount;
|
|
34
|
+
private _maxToolCallsPerSession;
|
|
35
|
+
private _disableToolsForNextCall;
|
|
33
36
|
get context(): LLMContext;
|
|
37
|
+
get storeId(): string;
|
|
38
|
+
/**
|
|
39
|
+
* Headers to be added to all tool call requests
|
|
40
|
+
*/
|
|
41
|
+
headers: Record<string, string>;
|
|
34
42
|
private _lastError;
|
|
35
43
|
private _spec;
|
|
36
44
|
private _customToolsDeclarations;
|
|
@@ -41,18 +49,7 @@ export declare class Conversation extends EventEmitter {
|
|
|
41
49
|
get model(): string | TLLMModel;
|
|
42
50
|
private _llmInference;
|
|
43
51
|
get llmInference(): LLMInference;
|
|
44
|
-
constructor(_model: string | TLLMModel, _specSource?: string | Record<string, any>, _settings?:
|
|
45
|
-
maxContextSize?: number;
|
|
46
|
-
maxOutputTokens?: number;
|
|
47
|
-
systemPrompt?: string;
|
|
48
|
-
toolChoice?: string;
|
|
49
|
-
store?: ILLMContextStore;
|
|
50
|
-
experimentalCache?: boolean;
|
|
51
|
-
toolsStrategy?: (toolsConfig: any) => any;
|
|
52
|
-
agentId?: string;
|
|
53
|
-
agentVersion?: string;
|
|
54
|
-
baseUrl?: string;
|
|
55
|
-
});
|
|
52
|
+
constructor(_model: string | TLLMModel, _specSource?: string | Record<string, any>, _settings?: IConversationSettings);
|
|
56
53
|
get ready(): any;
|
|
57
54
|
prompt(message?: string | any, toolHeaders?: {}, concurrentToolCalls?: number, abortSignal?: AbortSignal): Promise<string>;
|
|
58
55
|
streamPrompt(message?: string | any, toolHeaders?: {}, concurrentToolCalls?: number, abortSignal?: AbortSignal): Promise<string>;
|
|
@@ -33,7 +33,7 @@ export declare class TemplateStringHelper {
|
|
|
33
33
|
* unmatched placeholders will be left as is
|
|
34
34
|
* Recursively resolves nested template variables until no more variables are found
|
|
35
35
|
*/
|
|
36
|
-
parse(data: Record<string,
|
|
36
|
+
parse(data: Record<string, unknown>, regex?: TemplateStringMatch, maxDepth?: number): this;
|
|
37
37
|
/**
|
|
38
38
|
* Parses a template string by replacing placeholders with values from the provided data object, keeping the original raw values intact. This is particularly important for BinaryInput instances, as they include buffer data.
|
|
39
39
|
* unmatched placeholders will be left as is
|
package/dist/types/index.d.ts
CHANGED
|
@@ -87,6 +87,7 @@ export * from './Components/APICall/parseUrl';
|
|
|
87
87
|
export * from './Components/Image/imageSettings.config';
|
|
88
88
|
export * from './Components/RAG/DataSourceCleaner.class';
|
|
89
89
|
export * from './Components/RAG/DataSourceComponent.class';
|
|
90
|
+
export * from './Components/RAG/DataSourceIndexer.class';
|
|
90
91
|
export * from './Components/RAG/DataSourceLookup.class';
|
|
91
92
|
export * from './Components/Triggers/Gmail.trigger';
|
|
92
93
|
export * from './Components/Triggers/JobScheduler.trigger';
|
|
@@ -22,6 +22,7 @@ export interface IVectorDBRequest {
|
|
|
22
22
|
}
|
|
23
23
|
export declare abstract class VectorDBConnector extends SecureConnector<IVectorDBRequest> {
|
|
24
24
|
protected readonly USER_METADATA_KEY = "user_metadata";
|
|
25
|
+
protected readonly LEGACY_USER_METADATA_KEY = "metadata";
|
|
25
26
|
abstract id: string;
|
|
26
27
|
abstract getResourceACL(resourceId: string, candidate: IAccessCandidate): Promise<ACL>;
|
|
27
28
|
requester(candidate: AccessCandidate): IVectorDBRequest;
|
|
@@ -133,4 +133,23 @@ export declare class LLMHelper {
|
|
|
133
133
|
* @returns {TLLMMessageBlock[]} The modified array of message objects.
|
|
134
134
|
*/
|
|
135
135
|
static removeDuplicateUserMessages(messages: TLLMMessageBlock[]): TLLMMessageBlock[];
|
|
136
|
+
/**
|
|
137
|
+
* Checks if the given model is part of the Claude 4 family.
|
|
138
|
+
*
|
|
139
|
+
* @param {string} modelId - The model identifier to check.
|
|
140
|
+
* @returns {boolean} True if the model is Claude 4 family, false otherwise.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* const isClaude4 = LLMHelper.isClaude4Family('claude-sonnet-4-20250514');
|
|
144
|
+
* console.log(isClaude4); // true
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* const isClaude4 = LLMHelper.isClaude4Family('claude-opus-4-5');
|
|
148
|
+
* console.log(isClaude4); // true
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* const isClaude4 = LLMHelper.isClaude4Family('gpt-4-turbo');
|
|
152
|
+
* console.log(isClaude4); // false
|
|
153
|
+
*/
|
|
154
|
+
static isClaude4Family(modelId: string): boolean;
|
|
136
155
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import { type GenerateContentResponseUsageMetadata } from '@google/genai/node';
|
|
3
|
-
import { TLLMMessageBlock, ToolData, TLLMToolResultMessageBlock, APIKeySource, ILLMRequestFuncParams, TLLMChatResponse, TGoogleAIRequestBody,
|
|
3
|
+
import { TLLMMessageBlock, ToolData, TLLMToolResultMessageBlock, APIKeySource, ILLMRequestFuncParams, TLLMChatResponse, TGoogleAIRequestBody, TLLMPreparedParams } from '@sre/types/LLM.types';
|
|
4
4
|
import { LLMConnector } from '../LLMConnector';
|
|
5
5
|
type UsageMetadataWithThoughtsToken = GenerateContentResponseUsageMetadata & {
|
|
6
6
|
thoughtsTokenCount?: number;
|
|
@@ -26,6 +26,7 @@ export declare class GoogleAIConnector extends LLMConnector {
|
|
|
26
26
|
sourceId: string;
|
|
27
27
|
input_tokens: number;
|
|
28
28
|
output_tokens: number;
|
|
29
|
+
output_tokens_image: number;
|
|
29
30
|
input_tokens_audio: number;
|
|
30
31
|
input_tokens_cache_read: number;
|
|
31
32
|
input_tokens_cache_read_audio: number;
|
|
@@ -33,22 +34,26 @@ export declare class GoogleAIConnector extends LLMConnector {
|
|
|
33
34
|
keySource: APIKeySource;
|
|
34
35
|
agentId: string;
|
|
35
36
|
teamId: string;
|
|
36
|
-
|
|
37
|
-
outTier: string;
|
|
38
|
-
crTier: string;
|
|
37
|
+
tier: string;
|
|
39
38
|
};
|
|
40
39
|
/**
|
|
41
40
|
* Extract text and image tokens from Google AI usage metadata
|
|
42
41
|
*/
|
|
43
42
|
private extractTokenCounts;
|
|
44
|
-
protected
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
usageMetadata?: UsageMetadataWithThoughtsToken;
|
|
48
|
-
};
|
|
49
|
-
context: ILLMRequestContext;
|
|
43
|
+
protected reportImageCost({ cost, context, numberOfImages }: {
|
|
44
|
+
cost: any;
|
|
45
|
+
context: any;
|
|
50
46
|
numberOfImages?: number;
|
|
51
47
|
}): void;
|
|
48
|
+
/**
|
|
49
|
+
* Normalizes function response values to ensure they conform to Google AI's STRUCT requirement.
|
|
50
|
+
* Gemini expects functionResponse.response to be a STRUCT (JSON object format), not a list or scalar.
|
|
51
|
+
*/
|
|
52
|
+
private normalizeFunctionResponse;
|
|
53
|
+
/**
|
|
54
|
+
* Parses and normalizes function response values, handling string JSON and various data types.
|
|
55
|
+
*/
|
|
56
|
+
private parseFunctionResponse;
|
|
52
57
|
formatToolsConfig({ toolDefinitions, toolChoice }: {
|
|
53
58
|
toolDefinitions: any;
|
|
54
59
|
toolChoice?: string;
|
|
@@ -196,6 +196,7 @@ export type TLLMModel = {
|
|
|
196
196
|
isCustomLLM?: boolean;
|
|
197
197
|
isUserCustomLLM?: boolean;
|
|
198
198
|
modelId?: string;
|
|
199
|
+
modelEntryName?: string;
|
|
199
200
|
tokens?: number;
|
|
200
201
|
completionTokens?: number;
|
|
201
202
|
components?: string[];
|
|
@@ -394,10 +395,32 @@ export type TLLMInputMessage = {
|
|
|
394
395
|
}[];
|
|
395
396
|
};
|
|
396
397
|
export interface ILLMContextStore {
|
|
398
|
+
id: string;
|
|
397
399
|
save(messages: any[]): Promise<void>;
|
|
398
400
|
load(count?: number): Promise<any[]>;
|
|
399
401
|
getMessage(message_id: string): Promise<any[]>;
|
|
400
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* Configuration options for Conversation helper
|
|
405
|
+
*/
|
|
406
|
+
export interface IConversationSettings {
|
|
407
|
+
maxContextSize?: number;
|
|
408
|
+
maxOutputTokens?: number;
|
|
409
|
+
systemPrompt?: string;
|
|
410
|
+
toolChoice?: string;
|
|
411
|
+
store?: ILLMContextStore;
|
|
412
|
+
experimentalCache?: boolean;
|
|
413
|
+
toolsStrategy?: (toolsConfig: any) => any;
|
|
414
|
+
agentId?: string;
|
|
415
|
+
agentVersion?: string;
|
|
416
|
+
baseUrl?: string;
|
|
417
|
+
/**
|
|
418
|
+
* Maximum number of tool calls allowed in a single conversation session.
|
|
419
|
+
* Prevents infinite loops in tool calling scenarios.
|
|
420
|
+
* @default 100
|
|
421
|
+
*/
|
|
422
|
+
maxToolCalls?: number;
|
|
423
|
+
}
|
|
401
424
|
export declare enum APIKeySource {
|
|
402
425
|
Smyth = "smyth-managed",
|
|
403
426
|
User = "user-managed",
|
package/package.json
CHANGED
|
@@ -6,6 +6,8 @@ import { TemplateString } from '@sre/helpers/TemplateString.helper';
|
|
|
6
6
|
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
7
7
|
import { Conversation } from '@sre/helpers/Conversation.helper';
|
|
8
8
|
import { Component } from './Component.class';
|
|
9
|
+
import { LLMInference } from '@sre/LLMManager/LLM.inference';
|
|
10
|
+
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
|
|
9
11
|
|
|
10
12
|
export class AgentPlugin extends Component {
|
|
11
13
|
protected configSchema = Joi.object({
|
|
@@ -84,16 +86,31 @@ export class AgentPlugin extends Component {
|
|
|
84
86
|
|
|
85
87
|
const conv = new Conversation(model, subAgentId, { systemPrompt: descForModel, agentVersion: version });
|
|
86
88
|
|
|
87
|
-
|
|
89
|
+
// # Region: enhance the prompt to produce a JSON output format based on the available component outputs.
|
|
90
|
+
const llmInference: LLMInference = await LLMInference.getInstance(model, AccessCandidate.agent(agent.id));
|
|
91
|
+
|
|
92
|
+
// if the llm is undefined, then it means we removed the model from our system
|
|
93
|
+
if (!llmInference.connector) {
|
|
94
|
+
return {
|
|
95
|
+
_error: `The model '${model}' is not available. Please try a different one.`,
|
|
96
|
+
_debug: logger.output,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const enhancedPrompt = llmInference.connector.enhancePrompt(prompt, config);
|
|
100
|
+
// # End Region: prompt enhancement
|
|
101
|
+
|
|
102
|
+
const result = await conv.prompt(enhancedPrompt, {
|
|
88
103
|
'X-AGENT-ID': subAgentId,
|
|
89
104
|
'X-AGENT-VERSION': version,
|
|
90
105
|
'X-REQUEST-TAG': reqTag, //request Tag identifies the request and tells the called agent that the call comes from internal agent
|
|
91
106
|
'x-caller-session-id': agent.callerSessionId,
|
|
92
107
|
});
|
|
93
108
|
|
|
94
|
-
|
|
109
|
+
const processedResponse = llmInference.connector.postProcess(result);
|
|
110
|
+
|
|
111
|
+
logger.debug(`Response:\n`, processedResponse, '\n');
|
|
95
112
|
|
|
96
|
-
return { Response:
|
|
113
|
+
return { Response: processedResponse, _debug: logger.output };
|
|
97
114
|
} catch (error: any) {
|
|
98
115
|
console.error('Error on running Agent Component: ', error);
|
|
99
116
|
return { _error: `Error on running Agent Component!\n${error?.message || JSON.stringify(error)}`, _debug: logger.output };
|
|
@@ -5,7 +5,9 @@ import { Component } from './Component.class';
|
|
|
5
5
|
import { IAgent as Agent } from '@sre/types/Agent.types';
|
|
6
6
|
import { TemplateString } from '@sre/helpers/TemplateString.helper';
|
|
7
7
|
import { LLMInference } from '@sre/LLMManager/LLM.inference';
|
|
8
|
+
import { LLMHelper } from '@sre/LLMManager/LLM.helper';
|
|
8
9
|
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
|
|
10
|
+
import { TLLMEvent } from '@sre/types/LLM.types';
|
|
9
11
|
|
|
10
12
|
export class Classifier extends Component {
|
|
11
13
|
protected schema = {
|
|
@@ -97,7 +99,7 @@ ${JSON.stringify(categories, null, 2)}`;
|
|
|
97
99
|
prompt = TemplateString(prompt).parse(input).result;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
logger.log(` Enhanced prompt \n${prompt}
|
|
102
|
+
logger.log(` Enhanced prompt \n${prompt}`);
|
|
101
103
|
|
|
102
104
|
if (!prompt) {
|
|
103
105
|
logger.error(` Missing information, Cannot run classifier`);
|
|
@@ -114,21 +116,82 @@ ${JSON.stringify(categories, null, 2)}`;
|
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
try {
|
|
117
|
-
let response
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
let response;
|
|
120
|
+
|
|
121
|
+
// Use streaming for Claude 4 family models
|
|
122
|
+
if (LLMHelper.isClaude4Family(modelId || model)) {
|
|
123
|
+
logger.debug(`\n ⚡ Using streaming for Claude 4 family model`);
|
|
124
|
+
|
|
125
|
+
const contentPromise = new Promise(async (resolve, reject) => {
|
|
126
|
+
let _content = '';
|
|
127
|
+
let eventEmitter;
|
|
128
|
+
|
|
129
|
+
eventEmitter = await llmInference
|
|
130
|
+
.promptStream({
|
|
131
|
+
contextWindow: [{ role: 'user', content: prompt }],
|
|
132
|
+
files: [],
|
|
133
|
+
params: {
|
|
134
|
+
...config.data,
|
|
135
|
+
agentId: agent.id,
|
|
136
|
+
responseFormat: 'json',
|
|
137
|
+
},
|
|
138
|
+
onFallback: (fallbackInfo) => {
|
|
139
|
+
logger.debug(`\n ↩️ Using fallback model: ${fallbackInfo.model}`);
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
.catch((error) => {
|
|
143
|
+
console.error('Error on promptStream: ', error);
|
|
144
|
+
reject(error);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
eventEmitter.on(TLLMEvent.Content, (content) => {
|
|
148
|
+
_content += content;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
eventEmitter.on(TLLMEvent.End, () => {
|
|
152
|
+
resolve(_content);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
eventEmitter.on(TLLMEvent.Error, (error) => {
|
|
156
|
+
reject(error);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
response = await contentPromise.catch((error) => {
|
|
161
|
+
return { error: error.message || error };
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Handle streaming errors
|
|
165
|
+
if (response?.error) {
|
|
166
|
+
const error = response?.error + ' ' + (response?.details || '');
|
|
167
|
+
logger.error(` LLM Error=`, error);
|
|
168
|
+
return { _error: error, _debug: logger.output };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Post-process the streaming response
|
|
172
|
+
const postProcessed = llmInference.connector.postProcess(response);
|
|
173
|
+
if (postProcessed.error) {
|
|
174
|
+
logger.error(` LLM Post-process Error=`, postProcessed.error);
|
|
175
|
+
return { _error: postProcessed.error, _debug: logger.output };
|
|
176
|
+
}
|
|
177
|
+
response = postProcessed;
|
|
178
|
+
} else {
|
|
179
|
+
// Use regular prompt for non-Claude 4 models
|
|
180
|
+
response = await llmInference
|
|
181
|
+
.prompt({
|
|
182
|
+
query: prompt,
|
|
183
|
+
params: { ...config, agentId: agent.id },
|
|
184
|
+
onFallback: (data) => {
|
|
185
|
+
logger.debug(`\n ↩️ Using Fallback Model: ${data.model}`);
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
.catch((error) => ({ error: error }));
|
|
189
|
+
|
|
190
|
+
if (response?.error) {
|
|
191
|
+
const error = response?.error + ' ' + (response?.details || '');
|
|
192
|
+
logger.error(` LLM Error=`, error);
|
|
193
|
+
return { _error: error, _debug: logger.output };
|
|
194
|
+
}
|
|
132
195
|
}
|
|
133
196
|
|
|
134
197
|
// let parsed = parseJson(response);
|
|
@@ -18,6 +18,8 @@ export class ForEach extends Component {
|
|
|
18
18
|
let _in_progress = true;
|
|
19
19
|
const logger = this.createComponentLogger(agent, config);
|
|
20
20
|
try {
|
|
21
|
+
logger.debug(`=== ForEach Log ===`);
|
|
22
|
+
|
|
21
23
|
const inputObject = input.Input;
|
|
22
24
|
let inputArray;
|
|
23
25
|
|
|
@@ -38,18 +40,30 @@ export class ForEach extends Component {
|
|
|
38
40
|
const runtimeData = agent.agentRuntime.getRuntimeData(config.id);
|
|
39
41
|
const _ForEachData = runtimeData._LoopData || { parentId: config.id, loopIndex: 0, loopLength: inputArray.length };
|
|
40
42
|
|
|
41
|
-
logger.debug(`Loop: ${_ForEachData.loopIndex} / ${_ForEachData.loopLength}`);
|
|
42
43
|
delete _ForEachData.branches; //reset branches (the number of branches is calculated in CallComponent@Agent.class.ts )
|
|
43
44
|
|
|
44
45
|
if (_ForEachData.result) {
|
|
45
46
|
_temp_result = _ForEachData.result;
|
|
46
|
-
logger.debug(` => Loop Result : ${JSON.stringify(Loop, null, 2)}`);
|
|
47
|
-
logger.debug(`---------------------------------------------------`);
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
Loop = inputArray[_ForEachData.loopIndex];
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
// Log each iteration: show iteration number, input, and previous iteration details (if available)
|
|
52
|
+
if (Loop !== undefined) {
|
|
53
|
+
logger.debug(` Iteration ${_ForEachData.loopIndex + 1}/${_ForEachData.loopLength}`);
|
|
54
|
+
logger.debug(` In Progress: ${_in_progress}`);
|
|
55
|
+
logger.debug(` Input: \n${JSON.stringify(Loop, null, 2)}`);
|
|
56
|
+
|
|
57
|
+
// Show previous iteration's input and result if available
|
|
58
|
+
if (_ForEachData.loopIndex > 0 && _temp_result && _temp_result[_ForEachData.loopIndex - 1]) {
|
|
59
|
+
const prevInput = inputArray[_ForEachData.loopIndex - 1];
|
|
60
|
+
const prevItem = _temp_result[_ForEachData.loopIndex - 1];
|
|
61
|
+
logger.debug(''); // empty line
|
|
62
|
+
logger.debug(` Previous Input: \n${JSON.stringify(prevInput, null, 2)}`);
|
|
63
|
+
logger.debug(''); // empty line
|
|
64
|
+
logger.debug(` Previous Result: \n${JSON.stringify(prevItem.result || prevItem, null, 2)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
53
67
|
|
|
54
68
|
_in_progress = Loop !== undefined;
|
|
55
69
|
if (_in_progress) {
|
|
@@ -67,12 +81,26 @@ export class ForEach extends Component {
|
|
|
67
81
|
|
|
68
82
|
switch (config?.data?.format) {
|
|
69
83
|
case 'minimal':
|
|
70
|
-
Result = Result.map((item) => cleanupResult(item.result));
|
|
84
|
+
Result = Result.map((item) => cleanupResult(item.result || item));
|
|
71
85
|
break;
|
|
72
86
|
case 'results-array':
|
|
73
|
-
Result = Result.map((item) => Object.values(cleanupResult(item.result))).flat(Infinity);
|
|
87
|
+
Result = Result.map((item) => Object.values(cleanupResult(item.result || item))).flat(Infinity);
|
|
74
88
|
break;
|
|
75
89
|
}
|
|
90
|
+
|
|
91
|
+
// Final summary: Input array, total iterations, and result
|
|
92
|
+
logger.debug(` Total Iterations: ${Result.length}`);
|
|
93
|
+
logger.debug(` In Progress: ${_in_progress}`);
|
|
94
|
+
logger.debug(''); // empty line
|
|
95
|
+
logger.debug(` Input: \n${JSON.stringify(input.Input, null, 2)}`);
|
|
96
|
+
logger.debug(''); // empty line
|
|
97
|
+
logger.debug(
|
|
98
|
+
` Result: \n${JSON.stringify(
|
|
99
|
+
Result.map((item) => item.result || item),
|
|
100
|
+
null,
|
|
101
|
+
2
|
|
102
|
+
)}`
|
|
103
|
+
);
|
|
76
104
|
}
|
|
77
105
|
|
|
78
106
|
return { Loop, Result, _temp_result, _error, _in_progress, _debug: logger.output };
|
|
@@ -107,25 +107,25 @@ export class GenAILLM extends Component {
|
|
|
107
107
|
},
|
|
108
108
|
webSearchCity: {
|
|
109
109
|
type: 'string',
|
|
110
|
-
max:
|
|
110
|
+
max: 255,
|
|
111
111
|
label: 'Web Search City',
|
|
112
112
|
allowEmpty: true,
|
|
113
113
|
},
|
|
114
114
|
webSearchCountry: {
|
|
115
115
|
type: 'string',
|
|
116
|
-
max:
|
|
116
|
+
max: 255,
|
|
117
117
|
label: 'Web Search Country',
|
|
118
118
|
allowEmpty: true,
|
|
119
119
|
},
|
|
120
120
|
webSearchRegion: {
|
|
121
121
|
type: 'string',
|
|
122
|
-
max:
|
|
122
|
+
max: 255,
|
|
123
123
|
label: 'Web Search Region',
|
|
124
124
|
allowEmpty: true,
|
|
125
125
|
},
|
|
126
126
|
webSearchTimezone: {
|
|
127
127
|
type: 'string',
|
|
128
|
-
max:
|
|
128
|
+
max: 255,
|
|
129
129
|
label: 'Web Search Timezone',
|
|
130
130
|
allowEmpty: true,
|
|
131
131
|
},
|
|
@@ -165,7 +165,7 @@ export class GenAILLM extends Component {
|
|
|
165
165
|
},
|
|
166
166
|
searchCountry: {
|
|
167
167
|
type: 'string',
|
|
168
|
-
max:
|
|
168
|
+
max: 255,
|
|
169
169
|
label: 'Search Country',
|
|
170
170
|
allowEmpty: true,
|
|
171
171
|
},
|
|
@@ -247,7 +247,7 @@ export class GenAILLM extends Component {
|
|
|
247
247
|
},
|
|
248
248
|
reasoningEffort: {
|
|
249
249
|
type: 'string',
|
|
250
|
-
valid: ['none', 'default', 'low', 'medium', 'high'],
|
|
250
|
+
valid: ['none', 'default', 'low', 'medium', 'high', 'xhigh'],
|
|
251
251
|
description: 'Controls the level of effort the model will put into reasoning',
|
|
252
252
|
label: 'Reasoning Effort',
|
|
253
253
|
},
|
|
@@ -295,10 +295,10 @@ export class GenAILLM extends Component {
|
|
|
295
295
|
// #region Web Search
|
|
296
296
|
useWebSearch: Joi.boolean().optional().label('Use Web Search'),
|
|
297
297
|
webSearchContextSize: Joi.string().valid('high', 'medium', 'low').optional().label('Web Search Context Size'),
|
|
298
|
-
webSearchCity: Joi.string().max(
|
|
299
|
-
webSearchCountry: Joi.string().max(
|
|
300
|
-
webSearchRegion: Joi.string().max(
|
|
301
|
-
webSearchTimezone: Joi.string().max(
|
|
298
|
+
webSearchCity: Joi.string().max(255).optional().allow('').label('Web Search City'),
|
|
299
|
+
webSearchCountry: Joi.string().max(255).optional().allow('').label('Web Search Country'),
|
|
300
|
+
webSearchRegion: Joi.string().max(255).optional().allow('').label('Web Search Region'),
|
|
301
|
+
webSearchTimezone: Joi.string().max(255).optional().allow('').label('Web Search Timezone'),
|
|
302
302
|
// #endregion
|
|
303
303
|
|
|
304
304
|
// #region xAI Search
|
|
@@ -307,7 +307,7 @@ export class GenAILLM extends Component {
|
|
|
307
307
|
returnCitations: Joi.boolean().optional().allow('').label('Return Citations'),
|
|
308
308
|
maxSearchResults: Joi.number().min(1).max(100).optional().allow('').label('Max Search Results'),
|
|
309
309
|
searchDataSources: Joi.array().items(Joi.string().valid('web', 'x', 'news', 'rss')).max(4).optional().allow('').label('Search Data Sources'),
|
|
310
|
-
searchCountry: Joi.string().
|
|
310
|
+
searchCountry: Joi.string().max(255).optional().allow('').label('Search Country'),
|
|
311
311
|
excludedWebsites: Joi.string().max(10000).optional().allow('').label('Excluded Websites'),
|
|
312
312
|
allowedWebsites: Joi.string().max(10000).optional().allow('').label('Allowed Websites'),
|
|
313
313
|
includedXHandles: Joi.string().max(1000).optional().allow('').label('Included X Handles'),
|
|
@@ -330,7 +330,11 @@ export class GenAILLM extends Component {
|
|
|
330
330
|
|
|
331
331
|
// #region Reasoning
|
|
332
332
|
useReasoning: Joi.boolean().optional().label('Use Reasoning'),
|
|
333
|
-
reasoningEffort: Joi.string()
|
|
333
|
+
reasoningEffort: Joi.string()
|
|
334
|
+
.valid('none', 'default', 'minimal', 'low', 'medium', 'high', 'xhigh')
|
|
335
|
+
.optional()
|
|
336
|
+
.allow('')
|
|
337
|
+
.label('Reasoning Effort'),
|
|
334
338
|
maxThinkingTokens: Joi.number().min(1).optional().label('Maximum Thinking Tokens'),
|
|
335
339
|
// #endregion
|
|
336
340
|
});
|
|
@@ -348,13 +352,24 @@ export class GenAILLM extends Component {
|
|
|
348
352
|
logger.debug(`=== GenAILLM Log ===`);
|
|
349
353
|
let teamId = agent?.teamId;
|
|
350
354
|
|
|
351
|
-
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
355
|
+
// Resolve template variables in config.data without mutating original config
|
|
356
|
+
const resolvedConfigData = {
|
|
357
|
+
...config.data,
|
|
358
|
+
prompt: config.data.prompt && TemplateString(config.data.prompt).parse(input).result,
|
|
359
|
+
webSearchCity: config.data.webSearchCity && TemplateString(config.data.webSearchCity).parse(input).result,
|
|
360
|
+
webSearchCountry: config.data.webSearchCountry && TemplateString(config.data.webSearchCountry).parse(input).result,
|
|
361
|
+
webSearchRegion: config.data.webSearchRegion && TemplateString(config.data.webSearchRegion).parse(input).result,
|
|
362
|
+
webSearchTimezone: config.data.webSearchTimezone && TemplateString(config.data.webSearchTimezone).parse(input).result,
|
|
363
|
+
|
|
364
|
+
searchCountry: config.data.searchCountry && TemplateString(config.data.searchCountry).parse(input).result,
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
const passThrough: boolean = resolvedConfigData.passthrough || false;
|
|
368
|
+
const useContextWindow: boolean = resolvedConfigData.useContextWindow || false;
|
|
369
|
+
const useSystemPrompt: boolean = resolvedConfigData.useSystemPrompt || false;
|
|
370
|
+
const maxTokens: number = parseInt(resolvedConfigData.maxTokens) || 1024;
|
|
371
|
+
const maxContextWindowLength: number = parseInt(resolvedConfigData.maxContextWindowLength) || 1024;
|
|
372
|
+
const model: string = resolvedConfigData.model || 'echo';
|
|
358
373
|
const llmInference: LLMInference = await LLMInference.getInstance(model, AccessCandidate.agent(agent.id));
|
|
359
374
|
|
|
360
375
|
// if the llm is undefined, then it means we removed the model from our system
|
|
@@ -371,7 +386,7 @@ export class GenAILLM extends Component {
|
|
|
371
386
|
|
|
372
387
|
logger.debug(` Model : ${modelId || model}`);
|
|
373
388
|
|
|
374
|
-
|
|
389
|
+
const prompt: any = resolvedConfigData.prompt;
|
|
375
390
|
|
|
376
391
|
let files: any[] = parseFiles(input, config);
|
|
377
392
|
let isMultimodalRequest = false;
|
|
@@ -403,8 +418,24 @@ export class GenAILLM extends Component {
|
|
|
403
418
|
files = validFiles.filter(Boolean);
|
|
404
419
|
|
|
405
420
|
if (files.length === 0) {
|
|
421
|
+
// No valid files after filtering - determine the cause
|
|
422
|
+
const hasDetectedMimeTypes = fileTypes.size > 0;
|
|
423
|
+
|
|
424
|
+
if (!hasDetectedMimeTypes) {
|
|
425
|
+
// Case 1: No mime types detected - files are corrupted/invalid
|
|
426
|
+
return {
|
|
427
|
+
_error: `Unable to process the provided file(s). Please ensure file(s) are not corrupted, have valid formats, and contain readable data.`,
|
|
428
|
+
_debug: logger.output,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Case 2: Files detected but model doesn't support those types
|
|
433
|
+
const detectedTypes = Array.from(fileTypes).join(', ');
|
|
434
|
+
const supportedTypes = new Set(Object.values(supportedFileTypes).flat());
|
|
435
|
+
const supportedTypesText = supportedTypes.size > 0 ? `\nSupported types: ${Array.from(supportedTypes).join(', ')}` : '';
|
|
436
|
+
|
|
406
437
|
return {
|
|
407
|
-
_error: `Model does not support
|
|
438
|
+
_error: `Model '${model}' does not support the provided file type(s): ${detectedTypes}.${supportedTypesText}`,
|
|
408
439
|
_debug: logger.output,
|
|
409
440
|
};
|
|
410
441
|
}
|
|
@@ -420,7 +451,7 @@ export class GenAILLM extends Component {
|
|
|
420
451
|
|
|
421
452
|
// default to json response format
|
|
422
453
|
const hasCustomOutputs = config?.outputs?.some((output) => !output.default);
|
|
423
|
-
|
|
454
|
+
resolvedConfigData.responseFormat = resolvedConfigData?.responseFormat || (hasCustomOutputs ? 'json' : '');
|
|
424
455
|
|
|
425
456
|
// request to LLM
|
|
426
457
|
let response: any;
|
|
@@ -478,7 +509,7 @@ export class GenAILLM extends Component {
|
|
|
478
509
|
contextWindow: messages,
|
|
479
510
|
files,
|
|
480
511
|
params: {
|
|
481
|
-
...
|
|
512
|
+
...resolvedConfigData,
|
|
482
513
|
agentId: agent.id,
|
|
483
514
|
},
|
|
484
515
|
onFallback: (fallbackInfo) => {
|