@smythos/sre 1.7.16 → 1.7.17
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 +9 -9
- package/dist/index.js.map +1 -1
- package/dist/types/subsystems/AgentManager/Agent.class.d.ts +2 -1
- package/dist/types/subsystems/AgentManager/EmbodimentSettings.class.d.ts +1 -0
- package/dist/types/types/Agent.types.d.ts +1 -0
- package/package.json +1 -1
- package/src/Components/APIEndpoint.class.ts +26 -20
- package/src/Components/ServerlessCode.class.ts +28 -18
- package/src/helpers/Conversation.helper.ts +6 -2
- package/src/subsystems/AgentManager/Agent.class.ts +4 -1
- package/src/subsystems/AgentManager/AgentRuntime.class.ts +1 -0
- package/src/subsystems/AgentManager/EmbodimentSettings.class.ts +8 -0
- package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +1 -1
- package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +8 -1
- package/src/subsystems/ObservabilityManager/Telemetry.service/connectors/OTel/OTel.class.ts +2 -1
- package/src/types/Agent.types.ts +2 -0
|
@@ -10,6 +10,7 @@ export declare class Agent implements IAgent {
|
|
|
10
10
|
name: any;
|
|
11
11
|
data: any;
|
|
12
12
|
teamId: any;
|
|
13
|
+
conversationId: string;
|
|
13
14
|
components: any;
|
|
14
15
|
connections: any;
|
|
15
16
|
endpoints: any;
|
|
@@ -51,7 +52,7 @@ export declare class Agent implements IAgent {
|
|
|
51
52
|
private parseVariables;
|
|
52
53
|
process(endpointPath: any, input: any): Promise<any>;
|
|
53
54
|
private updateTasksCount;
|
|
54
|
-
postProcess(
|
|
55
|
+
postProcess(_result: any): Promise<any>;
|
|
55
56
|
private hasLoopAncestor;
|
|
56
57
|
private clearChildLoopRuntimeComponentData;
|
|
57
58
|
private getComponentMissingInputs;
|
package/package.json
CHANGED
|
@@ -78,25 +78,6 @@ export class APIEndpoint extends Component {
|
|
|
78
78
|
let query = req && !isTrigger ? req.query : {};
|
|
79
79
|
const _authInfo = req ? req._agent_authinfo : undefined;
|
|
80
80
|
|
|
81
|
-
// parse template variables
|
|
82
|
-
for (const [key, value] of Object.entries(body)) {
|
|
83
|
-
if (isKeyTemplateVar(value as string)) {
|
|
84
|
-
body[key] = await parseKey(value as string, agent?.teamId);
|
|
85
|
-
} else if (isTemplateVar(value as string)) {
|
|
86
|
-
//body[key] = parseTemplate(value as string, input, { escapeString: false });
|
|
87
|
-
body[key] = TemplateString(value as string).parse(input).result;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
for (const [key, value] of Object.entries(query)) {
|
|
92
|
-
if (isKeyTemplateVar(value as string)) {
|
|
93
|
-
query[key] = await parseKey(value as string, agent?.teamId);
|
|
94
|
-
} else if (isTemplateVar(value as string)) {
|
|
95
|
-
//query[key] = parseTemplate(value as string, input, { escapeString: false });
|
|
96
|
-
query[key] = TemplateString(value as string).parse(input).result;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
81
|
// set default value and agent variables
|
|
101
82
|
const inputsWithDefaultValue = config.inputs.filter(
|
|
102
83
|
(input) => input.defaultVal !== undefined && input.defaultVal !== '' && input.defaultVal !== null
|
|
@@ -158,15 +139,23 @@ export class APIEndpoint extends Component {
|
|
|
158
139
|
//body = input;
|
|
159
140
|
}
|
|
160
141
|
|
|
161
|
-
//
|
|
142
|
+
// #region parse all template variables (after debugger injection and defaults are set)
|
|
143
|
+
body = await resolveTemplateVariables(body, input, agent);
|
|
144
|
+
query = await resolveTemplateVariables(query, input, agent);
|
|
145
|
+
// #endregion parse all template variables
|
|
146
|
+
|
|
147
|
+
// #region ensure strong data type
|
|
162
148
|
body = await performTypeInference(body, config.inputs, agent);
|
|
163
149
|
query = await performTypeInference(query, config.inputs, agent);
|
|
150
|
+
// #endregion ensure strong data type
|
|
164
151
|
|
|
152
|
+
// #region log inputs
|
|
165
153
|
logger.debug('Parsing inputs');
|
|
166
154
|
logger.debug(' Headers', headers);
|
|
167
155
|
logger.debug(' Body', body);
|
|
168
156
|
logger.debug(' Params', params);
|
|
169
157
|
logger.debug(' Query', query);
|
|
158
|
+
// #endregion log inputs
|
|
170
159
|
|
|
171
160
|
//Handle JSON Data
|
|
172
161
|
//FIXME : this is a workaround that parses any json string in the body, we should only parse the json string in the body if the data type is explicitely set to JSON
|
|
@@ -251,3 +240,20 @@ export class APIEndpoint extends Component {
|
|
|
251
240
|
return output;
|
|
252
241
|
}
|
|
253
242
|
}
|
|
243
|
+
|
|
244
|
+
async function resolveTemplateVariables(data: any, input: any, agent: Agent): Promise<any> {
|
|
245
|
+
for (const [key, value] of Object.entries(data)) {
|
|
246
|
+
if (isKeyTemplateVar(value as string)) {
|
|
247
|
+
data[key] = await parseKey(value as string, agent.teamId);
|
|
248
|
+
} else if (isTemplateVar(value as string)) {
|
|
249
|
+
// Parse using input values first, then agent variables.
|
|
250
|
+
// This correctly resolves cases where input values reference agent variables with the same name.
|
|
251
|
+
// Example: agent variables { user_id: "123" }, input { user_id: "{{user_id}}" }.
|
|
252
|
+
data[key] = TemplateString(value as string)
|
|
253
|
+
.parse(input)
|
|
254
|
+
.parse(agent.agentVariables).result;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return data;
|
|
259
|
+
}
|
|
@@ -5,9 +5,9 @@ import { ConnectorService } from '@sre/Core/ConnectorsService';
|
|
|
5
5
|
import { AWSCredentials, AWSRegionConfig } from '@sre/types/AWS.types';
|
|
6
6
|
import { calculateExecutionCost, generateCodeFromLegacyComponent, getLambdaCredentials, reportUsage } from '@sre/helpers/AWSLambdaCode.helper';
|
|
7
7
|
import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
|
|
8
|
+
import { TemplateString } from '@sre/helpers/TemplateString.helper';
|
|
8
9
|
|
|
9
10
|
export class ServerlessCode extends Component {
|
|
10
|
-
|
|
11
11
|
protected configSchema = Joi.object({
|
|
12
12
|
code_imports: Joi.string().max(1000).allow('').label('Imports'),
|
|
13
13
|
code_body: Joi.string().max(500000).allow('').label('Code'),
|
|
@@ -26,10 +26,10 @@ export class ServerlessCode extends Component {
|
|
|
26
26
|
constructor() {
|
|
27
27
|
super();
|
|
28
28
|
}
|
|
29
|
-
init() {
|
|
29
|
+
init() {}
|
|
30
30
|
|
|
31
31
|
async process(input, config, agent: Agent) {
|
|
32
|
-
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
32
|
+
await new Promise((resolve) => setTimeout(resolve, 10000));
|
|
33
33
|
await super.process(input, config, agent);
|
|
34
34
|
const logger = this.createComponentLogger(agent, config);
|
|
35
35
|
try {
|
|
@@ -39,22 +39,29 @@ export class ServerlessCode extends Component {
|
|
|
39
39
|
const componentInputs = agent.components[config.id]?.inputs || {};
|
|
40
40
|
|
|
41
41
|
let codeInputs = {};
|
|
42
|
+
|
|
42
43
|
for (let field of componentInputs) {
|
|
43
|
-
|
|
44
|
+
// Parse using input values first, then agent variables.
|
|
45
|
+
// This correctly resolves cases where input values reference agent variables with the same name.
|
|
46
|
+
// Example: agent variables { user_id: "123" }, input { user_id: "{{user_id}}" }.
|
|
47
|
+
const inputValue = TemplateString(input[field.name]).parse(input).parse(agent.agentVariables).result;
|
|
48
|
+
|
|
49
|
+
const _type = typeof inputValue;
|
|
50
|
+
|
|
44
51
|
switch (_type) {
|
|
45
52
|
case 'string':
|
|
46
53
|
try {
|
|
47
|
-
codeInputs[field.name] = JSON.parse(
|
|
54
|
+
codeInputs[field.name] = JSON.parse(inputValue.replace(/\\"/g, '"'));
|
|
48
55
|
} catch (error) {
|
|
49
|
-
codeInputs[field.name] = `${
|
|
56
|
+
codeInputs[field.name] = `${inputValue}`;
|
|
50
57
|
}
|
|
51
58
|
break;
|
|
52
59
|
case 'number':
|
|
53
60
|
case 'boolean':
|
|
54
|
-
codeInputs[field.name] =
|
|
61
|
+
codeInputs[field.name] = inputValue;
|
|
55
62
|
break;
|
|
56
63
|
default:
|
|
57
|
-
codeInputs[field.name] =
|
|
64
|
+
codeInputs[field.name] = inputValue;
|
|
58
65
|
break;
|
|
59
66
|
}
|
|
60
67
|
}
|
|
@@ -62,35 +69,38 @@ export class ServerlessCode extends Component {
|
|
|
62
69
|
logger.debug(`\nInput Variables: \n${JSON.stringify(codeInputs, null, 2)}\n`);
|
|
63
70
|
|
|
64
71
|
let codeConnector = ConnectorService.getCodeConnector();
|
|
65
|
-
let codeCredentials: AWSCredentials & AWSRegionConfig & { isUserProvidedKeys: boolean } =
|
|
66
|
-
await getLambdaCredentials(agent, config);
|
|
72
|
+
let codeCredentials: AWSCredentials & AWSRegionConfig & { isUserProvidedKeys: boolean } = await getLambdaCredentials(agent, config);
|
|
67
73
|
|
|
68
74
|
if (codeCredentials.isUserProvidedKeys) {
|
|
69
75
|
codeConnector = codeConnector.instance({
|
|
70
76
|
region: codeCredentials.region,
|
|
71
77
|
accessKeyId: codeCredentials.accessKeyId,
|
|
72
78
|
secretAccessKey: codeCredentials.secretAccessKey,
|
|
73
|
-
})
|
|
79
|
+
});
|
|
74
80
|
}
|
|
75
81
|
let code = config?.data?.code;
|
|
76
82
|
if (!code) {
|
|
77
|
-
code = generateCodeFromLegacyComponent(config.data.code_body, config.data.code_imports, Object.keys(codeInputs))
|
|
83
|
+
code = generateCodeFromLegacyComponent(config.data.code_body, config.data.code_imports, Object.keys(codeInputs));
|
|
78
84
|
}
|
|
79
85
|
// Deploy lambda function if it doesn't exist or the code hash is different
|
|
80
|
-
await codeConnector.agent(agent.id)
|
|
81
|
-
|
|
86
|
+
await codeConnector.agent(agent.id).deploy(
|
|
87
|
+
config.id,
|
|
88
|
+
{
|
|
82
89
|
code,
|
|
83
90
|
inputs: codeInputs,
|
|
84
|
-
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
85
93
|
runtime: 'nodejs',
|
|
86
|
-
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
87
96
|
|
|
88
97
|
try {
|
|
89
98
|
const executionResponse = await codeConnector.agent(agent.id).execute(config.id, codeInputs);
|
|
90
99
|
const executionTime = executionResponse.executionTime;
|
|
91
100
|
logger.debug(
|
|
92
|
-
`Code result:\n ${
|
|
93
|
-
|
|
101
|
+
`Code result:\n ${
|
|
102
|
+
typeof executionResponse.output === 'object' ? JSON.stringify(executionResponse.output, null, 2) : executionResponse.output
|
|
103
|
+
}\n`
|
|
94
104
|
);
|
|
95
105
|
logger.debug(`Execution time: ${executionTime}ms\n`);
|
|
96
106
|
|
|
@@ -697,7 +697,7 @@ export class Conversation extends EventEmitter {
|
|
|
697
697
|
|
|
698
698
|
reqConfig.headers['X-CACHE-ID'] = this._context?.llmCache?.id;
|
|
699
699
|
|
|
700
|
-
reqConfig.headers['X-REQUEST-TAG'] = this.id;
|
|
700
|
+
//reqConfig.headers['X-REQUEST-TAG'] = this.id;
|
|
701
701
|
/*
|
|
702
702
|
* Objective for the following conditions:
|
|
703
703
|
* - In case it is not a debug call and there is no monitor id, then we need to run the agent locally to reduce latency
|
|
@@ -717,6 +717,10 @@ export class Conversation extends EventEmitter {
|
|
|
717
717
|
//reqConfig.headers['X-AGENT-HAS-ATTACHMENTS'] !== undefined;
|
|
718
718
|
reqConfig.headers['x-conversation-id'] !== undefined;
|
|
719
719
|
|
|
720
|
+
//we force the conversationId header after checking that it was not remotely set
|
|
721
|
+
if (!reqConfig.headers['x-conversation-id']) {
|
|
722
|
+
reqConfig.headers['x-conversation-id'] = this.id;
|
|
723
|
+
}
|
|
720
724
|
if (canRunLocally && !requiresRemoteCall) {
|
|
721
725
|
console.log('RUNNING AGENT LOCALLY');
|
|
722
726
|
let agentProcess;
|
|
@@ -754,7 +758,7 @@ export class Conversation extends EventEmitter {
|
|
|
754
758
|
});
|
|
755
759
|
};
|
|
756
760
|
|
|
757
|
-
|
|
761
|
+
eventSource = new EventSource(monitUrl, {
|
|
758
762
|
fetch: customFetch,
|
|
759
763
|
});
|
|
760
764
|
let monitorId = '';
|
|
@@ -24,6 +24,8 @@ export class Agent implements IAgent {
|
|
|
24
24
|
public name: any;
|
|
25
25
|
public data: any;
|
|
26
26
|
public teamId: any;
|
|
27
|
+
//if the agent was triggered from a conversation, this will be the conversation id
|
|
28
|
+
public conversationId: string;
|
|
27
29
|
public components: any;
|
|
28
30
|
public connections: any;
|
|
29
31
|
public endpoints: any = {};
|
|
@@ -406,7 +408,8 @@ export class Agent implements IAgent {
|
|
|
406
408
|
}
|
|
407
409
|
|
|
408
410
|
@hookAsync('SREAgent.postProcess')
|
|
409
|
-
public async postProcess(
|
|
411
|
+
public async postProcess(_result) {
|
|
412
|
+
let result = JSON.parse(JSON.stringify(_result)); //deep clone the result to avoid modifying the original object
|
|
410
413
|
if (Array.isArray(result)) result = result.flat(Infinity);
|
|
411
414
|
if (!Array.isArray(result)) result = [result];
|
|
412
415
|
|
|
@@ -44,4 +44,12 @@ export class EmbodimentSettings {
|
|
|
44
44
|
}
|
|
45
45
|
return _embodiment?.properties;
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
public getAll() {
|
|
49
|
+
const obj = {};
|
|
50
|
+
this._embodiments.forEach((embodiment: any) => {
|
|
51
|
+
obj[embodiment.type.toLowerCase()] = embodiment.properties;
|
|
52
|
+
});
|
|
53
|
+
return obj;
|
|
54
|
+
}
|
|
47
55
|
}
|
|
@@ -289,7 +289,7 @@ export class MilvusVectorDB extends VectorDBConnector {
|
|
|
289
289
|
//const teamId = await this.accountConnector.getCandidateTeam(acRequest.candidate);
|
|
290
290
|
const preparedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
|
|
291
291
|
|
|
292
|
-
const isDeleteByFilter = typeof deleteTarget === 'object';
|
|
292
|
+
const isDeleteByFilter = typeof deleteTarget === 'object' && !Array.isArray(deleteTarget);
|
|
293
293
|
if (isDeleteByFilter) {
|
|
294
294
|
const supportedFields: SchemaFieldNames[] = ['datasourceId'];
|
|
295
295
|
if (!supportedFields.some((field) => field in deleteTarget)) {
|
|
@@ -139,6 +139,7 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
139
139
|
protected async deleteNamespace(acRequest: AccessRequest, namespace: string): Promise<void> {
|
|
140
140
|
//const teamId = await this.accountConnector.getCandidateTeam(acRequest.candidate);
|
|
141
141
|
//const candidate = AccessCandidate.team(teamId);
|
|
142
|
+
|
|
142
143
|
const preparedNs = this.constructNsName(acRequest.candidate as AccessCandidate, namespace);
|
|
143
144
|
|
|
144
145
|
await this.client
|
|
@@ -146,6 +147,7 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
146
147
|
.namespace(this.constructNsName(acRequest.candidate as AccessCandidate, namespace))
|
|
147
148
|
.deleteAll()
|
|
148
149
|
.catch((e) => {
|
|
150
|
+
console.error(`Error deleting namespace ${namespace}: ${e}`);
|
|
149
151
|
if (e?.name == 'PineconeNotFoundError') {
|
|
150
152
|
console.warn(`Namespace ${namespace} does not exist and was requested to be deleted`);
|
|
151
153
|
return;
|
|
@@ -153,6 +155,11 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
153
155
|
throw e;
|
|
154
156
|
});
|
|
155
157
|
|
|
158
|
+
// delete the linked datasources from nkv
|
|
159
|
+
await this.nkvConnector
|
|
160
|
+
.requester(acRequest.candidate as AccessCandidate)
|
|
161
|
+
.deleteAll(`vectorDB:${this.id}:namespaces:${preparedNs}:datasources`);
|
|
162
|
+
|
|
156
163
|
await this.deleteACL(AccessCandidate.clone(acRequest.candidate), namespace);
|
|
157
164
|
}
|
|
158
165
|
|
|
@@ -258,7 +265,7 @@ export class PineconeVectorDB extends VectorDBConnector {
|
|
|
258
265
|
|
|
259
266
|
@SecureConnector.AccessControl
|
|
260
267
|
protected async delete(acRequest: AccessRequest, namespace: string, deleteTarget: DeleteTarget): Promise<void> {
|
|
261
|
-
const isDeleteByFilter = typeof deleteTarget === 'object';
|
|
268
|
+
const isDeleteByFilter = typeof deleteTarget === 'object' && !Array.isArray(deleteTarget);
|
|
262
269
|
|
|
263
270
|
if (isDeleteByFilter) {
|
|
264
271
|
// TODO: handle delete by filter logic
|
|
@@ -447,6 +447,7 @@ export class OTel extends TelemetryConnector {
|
|
|
447
447
|
// nested process has a subID that needs to be removed
|
|
448
448
|
// a process can be nested if it was called by a parent process : e.g conversation => agent , agent => sub-agent, agent => forked process ....etc
|
|
449
449
|
const agentProcessId = agent.agentRuntime.processID;
|
|
450
|
+
const conversationId = agent.conversationId || agent.agentRequest?.header('X-CONVERSATION-ID');
|
|
450
451
|
const processId = agentProcessId.split(':').shift();
|
|
451
452
|
|
|
452
453
|
const agentId = agent.id;
|
|
@@ -462,7 +463,7 @@ export class OTel extends TelemetryConnector {
|
|
|
462
463
|
const input = { body, query, headers, processInput: agentInput };
|
|
463
464
|
|
|
464
465
|
let convSpan;
|
|
465
|
-
const ctx = OTelContextRegistry.get(agentId, processId);
|
|
466
|
+
const ctx = OTelContextRegistry.get(agentId, processId) || OTelContextRegistry.get(agentId, conversationId);
|
|
466
467
|
|
|
467
468
|
if (ctx) {
|
|
468
469
|
convSpan = ctx.rootSpan;
|
package/src/types/Agent.types.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type TAgentProcessParams = {
|
|
|
15
15
|
|
|
16
16
|
//TODO : refactor & document this interface
|
|
17
17
|
export interface IAgent {
|
|
18
|
+
//if the agent was triggered from a conversation, this will be the conversation id
|
|
19
|
+
conversationId: string;
|
|
18
20
|
id: any;
|
|
19
21
|
jobID: any; //forkedAgent
|
|
20
22
|
async: boolean; //forkedAgent
|