@memberjunction/server 2.50.0 → 2.51.0
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/README.md +133 -0
- package/dist/config.d.ts +264 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -1
- package/dist/config.js.map +1 -1
- package/dist/generated/generated.d.ts +3 -0
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +532 -517
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +1 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +13 -11
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/orm.d.ts.map +1 -1
- package/dist/orm.js +6 -0
- package/dist/orm.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +3 -3
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +13 -10
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.js +1 -1
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +49 -8
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +389 -106
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts +61 -0
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -0
- package/dist/resolvers/SqlLoggingConfigResolver.js +477 -0
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -0
- package/dist/resolvers/UserFavoriteResolver.d.ts +3 -3
- package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +6 -6
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/dist/resolvers/UserResolver.d.ts +3 -3
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +6 -6
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +4 -4
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +6 -6
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/package.json +25 -25
- package/src/config.ts +28 -0
- package/src/generated/generated.ts +527 -518
- package/src/generic/ResolverBase.ts +17 -10
- package/src/index.ts +2 -1
- package/src/orm.ts +6 -0
- package/src/resolvers/ActionResolver.ts +21 -26
- package/src/resolvers/FileResolver.ts +1 -1
- package/src/resolvers/RunAIAgentResolver.ts +398 -100
- package/src/resolvers/SqlLoggingConfigResolver.ts +691 -0
- package/src/resolvers/UserFavoriteResolver.ts +6 -6
- package/src/resolvers/UserResolver.ts +6 -6
- package/src/resolvers/UserViewResolver.ts +6 -6
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
1
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID } from 'type-graphql';
|
|
2
2
|
import { UserPayload } from '../types.js';
|
|
3
|
-
import { LogError, LogStatus
|
|
3
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
4
4
|
import { AIAgentEntity } from '@memberjunction/core-entities';
|
|
5
5
|
import { AgentRunner } from '@memberjunction/ai-agents';
|
|
6
|
+
import { ExecuteAgentResult } from '@memberjunction/aiengine';
|
|
7
|
+
import { AIEngine } from '@memberjunction/aiengine';
|
|
6
8
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
9
|
+
import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
|
|
7
10
|
|
|
8
11
|
@ObjectType()
|
|
9
12
|
export class AIAgentRunResult {
|
|
@@ -11,37 +14,323 @@ export class AIAgentRunResult {
|
|
|
11
14
|
success: boolean;
|
|
12
15
|
|
|
13
16
|
@Field({ nullable: true })
|
|
14
|
-
|
|
17
|
+
errorMessage?: string;
|
|
15
18
|
|
|
16
19
|
@Field({ nullable: true })
|
|
17
|
-
|
|
20
|
+
executionTimeMs?: number;
|
|
21
|
+
|
|
22
|
+
@Field()
|
|
23
|
+
payload: string; // JSON serialized ExecuteAgentResult with scalars only
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@ObjectType()
|
|
27
|
+
export class AgentExecutionProgress {
|
|
28
|
+
@Field()
|
|
29
|
+
currentStep: string;
|
|
30
|
+
|
|
31
|
+
@Field()
|
|
32
|
+
percentage: number;
|
|
33
|
+
|
|
34
|
+
@Field()
|
|
35
|
+
message: string;
|
|
18
36
|
|
|
19
37
|
@Field({ nullable: true })
|
|
20
|
-
|
|
38
|
+
agentName?: string;
|
|
21
39
|
|
|
22
40
|
@Field({ nullable: true })
|
|
23
|
-
|
|
41
|
+
agentType?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@ObjectType()
|
|
45
|
+
export class AgentStreamingContent {
|
|
46
|
+
@Field()
|
|
47
|
+
content: string;
|
|
48
|
+
|
|
49
|
+
@Field()
|
|
50
|
+
isPartial: boolean;
|
|
51
|
+
|
|
52
|
+
@Field({ nullable: true })
|
|
53
|
+
stepName?: string;
|
|
54
|
+
|
|
55
|
+
@Field({ nullable: true })
|
|
56
|
+
agentName?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@ObjectType()
|
|
60
|
+
export class AgentExecutionStepSummary {
|
|
61
|
+
@Field()
|
|
62
|
+
stepId: string;
|
|
63
|
+
|
|
64
|
+
@Field()
|
|
65
|
+
stepName: string;
|
|
66
|
+
|
|
67
|
+
@Field({ nullable: true })
|
|
68
|
+
agentName?: string;
|
|
69
|
+
|
|
70
|
+
@Field({ nullable: true })
|
|
71
|
+
agentType?: string;
|
|
72
|
+
|
|
73
|
+
@Field()
|
|
74
|
+
startTime: Date;
|
|
24
75
|
|
|
25
76
|
@Field({ nullable: true })
|
|
26
|
-
|
|
77
|
+
endTime?: Date;
|
|
78
|
+
|
|
79
|
+
@Field()
|
|
80
|
+
status: string;
|
|
27
81
|
|
|
28
82
|
@Field({ nullable: true })
|
|
29
|
-
|
|
83
|
+
result?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@ObjectType()
|
|
87
|
+
export class AgentPartialResult {
|
|
88
|
+
@Field()
|
|
89
|
+
currentStep: string;
|
|
30
90
|
|
|
31
91
|
@Field({ nullable: true })
|
|
32
|
-
|
|
92
|
+
partialOutput?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@ObjectType()
|
|
96
|
+
export class AgentExecutionStreamMessage {
|
|
97
|
+
@Field(() => ID)
|
|
98
|
+
sessionId: string;
|
|
99
|
+
|
|
100
|
+
@Field(() => ID)
|
|
101
|
+
agentRunId: string;
|
|
102
|
+
|
|
103
|
+
@Field()
|
|
104
|
+
type: 'progress' | 'streaming' | 'partial_result' | 'complete';
|
|
105
|
+
|
|
106
|
+
@Field({ nullable: true })
|
|
107
|
+
progress?: AgentExecutionProgress;
|
|
108
|
+
|
|
109
|
+
@Field({ nullable: true })
|
|
110
|
+
streaming?: AgentStreamingContent;
|
|
33
111
|
|
|
34
112
|
@Field({ nullable: true })
|
|
35
|
-
|
|
113
|
+
partialResult?: AgentPartialResult;
|
|
114
|
+
|
|
115
|
+
@Field()
|
|
116
|
+
timestamp: Date;
|
|
36
117
|
}
|
|
37
118
|
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
38
123
|
@Resolver()
|
|
39
124
|
export class RunAIAgentResolver extends ResolverBase {
|
|
125
|
+
/**
|
|
126
|
+
* Sanitize ExecuteAgentResult for JSON serialization
|
|
127
|
+
* Removes circular references and non-serializable objects
|
|
128
|
+
*/
|
|
129
|
+
private sanitizeAgentResult(result: ExecuteAgentResult): any {
|
|
130
|
+
const sanitized: any = {
|
|
131
|
+
success: result.success,
|
|
132
|
+
returnValue: result.returnValue,
|
|
133
|
+
errorMessage: result.errorMessage,
|
|
134
|
+
finalStep: result.finalStep,
|
|
135
|
+
cancelled: result.cancelled,
|
|
136
|
+
cancellationReason: result.cancellationReason
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Safely extract agent run data
|
|
140
|
+
if (result.agentRun) {
|
|
141
|
+
sanitized.agentRun = {
|
|
142
|
+
ID: result.agentRun.ID,
|
|
143
|
+
Status: result.agentRun.Status,
|
|
144
|
+
StartedAt: result.agentRun.StartedAt,
|
|
145
|
+
CompletedAt: result.agentRun.CompletedAt,
|
|
146
|
+
Success: result.agentRun.Success,
|
|
147
|
+
ErrorMessage: result.agentRun.ErrorMessage,
|
|
148
|
+
AgentID: result.agentRun.AgentID,
|
|
149
|
+
Result: result.agentRun.Result,
|
|
150
|
+
TotalTokensUsed: result.agentRun.TotalTokensUsed,
|
|
151
|
+
TotalCost: result.agentRun.TotalCost
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Safely extract execution tree (hierarchical structure with all step data)
|
|
156
|
+
if (result.executionTree && Array.isArray(result.executionTree)) {
|
|
157
|
+
sanitized.executionTree = this.sanitizeExecutionTree(result.executionTree);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return sanitized;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Sanitize execution tree for JSON serialization
|
|
165
|
+
*/
|
|
166
|
+
private sanitizeExecutionTree(nodes: any[]): any[] {
|
|
167
|
+
return nodes.map(node => ({
|
|
168
|
+
step: node.step ? {
|
|
169
|
+
ID: node.step.ID,
|
|
170
|
+
AgentRunID: node.step.AgentRunID,
|
|
171
|
+
StepNumber: node.step.StepNumber,
|
|
172
|
+
StepType: node.step.StepType,
|
|
173
|
+
StepName: node.step.StepName,
|
|
174
|
+
TargetID: node.step.TargetID,
|
|
175
|
+
Status: node.step.Status,
|
|
176
|
+
StartedAt: node.step.StartedAt,
|
|
177
|
+
CompletedAt: node.step.CompletedAt,
|
|
178
|
+
Success: node.step.Success,
|
|
179
|
+
ErrorMessage: node.step.ErrorMessage,
|
|
180
|
+
InputData: node.step.InputData,
|
|
181
|
+
OutputData: node.step.OutputData
|
|
182
|
+
} : null,
|
|
183
|
+
inputData: node.inputData,
|
|
184
|
+
outputData: node.outputData,
|
|
185
|
+
executionType: node.executionType,
|
|
186
|
+
startTime: node.startTime,
|
|
187
|
+
endTime: node.endTime,
|
|
188
|
+
durationMs: node.durationMs,
|
|
189
|
+
nextStepDecision: node.nextStepDecision,
|
|
190
|
+
children: node.children && node.children.length > 0
|
|
191
|
+
? this.sanitizeExecutionTree(node.children)
|
|
192
|
+
: [],
|
|
193
|
+
depth: node.depth,
|
|
194
|
+
parentStepId: node.parentStepId,
|
|
195
|
+
agentHierarchy: node.agentHierarchy
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Parse and validate JSON input
|
|
201
|
+
*/
|
|
202
|
+
private parseJsonInput(jsonString: string | undefined, fieldName: string): any {
|
|
203
|
+
if (!jsonString) return {};
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
return JSON.parse(jsonString);
|
|
207
|
+
} catch (parseError) {
|
|
208
|
+
throw new Error(`Invalid JSON in ${fieldName}: ${(parseError as Error).message}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Validate the agent entity
|
|
214
|
+
*/
|
|
215
|
+
private async validateAgent(agentId: string, currentUser: any): Promise<AIAgentEntity> {
|
|
216
|
+
// Use AIEngine to get cached agent data
|
|
217
|
+
await AIEngine.Instance.Config(false, currentUser);
|
|
218
|
+
|
|
219
|
+
// Find agent in cached collection
|
|
220
|
+
const agentEntity = AIEngine.Instance.Agents.find((a: AIAgentEntity) => a.ID === agentId);
|
|
221
|
+
|
|
222
|
+
if (!agentEntity) {
|
|
223
|
+
throw new Error(`AI Agent with ID ${agentId} not found`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Check if agent is active
|
|
227
|
+
if (agentEntity.Status !== 'Active') {
|
|
228
|
+
throw new Error(`AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return agentEntity;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Create streaming progress callback
|
|
236
|
+
*/
|
|
237
|
+
private createProgressCallback(pubSub: PubSubEngine, sessionId: string, userPayload: UserPayload, agentRunIdRef: { id: string }) {
|
|
238
|
+
return (progress: any) => {
|
|
239
|
+
// Only publish progress for significant steps (not initialization noise)
|
|
240
|
+
const significantSteps = ['prompt_execution', 'action_execution', 'subagent_execution', 'decision_processing'];
|
|
241
|
+
if (!significantSteps.includes(progress.step)) {
|
|
242
|
+
console.log(`🔇 Skipping noise progress: ${progress.step}`);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log('📡 Publishing progress update:', {
|
|
247
|
+
step: progress.step,
|
|
248
|
+
percentage: progress.percentage,
|
|
249
|
+
message: progress.message,
|
|
250
|
+
sessionId,
|
|
251
|
+
agentRunId: agentRunIdRef.id
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Publish progress updates
|
|
255
|
+
const progressMsg: AgentExecutionStreamMessage = {
|
|
256
|
+
sessionId,
|
|
257
|
+
agentRunId: agentRunIdRef.id,
|
|
258
|
+
type: 'progress',
|
|
259
|
+
progress: {
|
|
260
|
+
currentStep: progress.step,
|
|
261
|
+
percentage: progress.percentage,
|
|
262
|
+
message: progress.message,
|
|
263
|
+
agentName: (progress.metadata as any)?.agentName || undefined,
|
|
264
|
+
agentType: (progress.metadata as any)?.agentType || undefined
|
|
265
|
+
},
|
|
266
|
+
timestamp: new Date()
|
|
267
|
+
};
|
|
268
|
+
this.PublishProgressUpdate(pubSub, progressMsg, userPayload);
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private PublishProgressUpdate(pubSub: PubSubEngine, data: any, userPayload: UserPayload) {
|
|
273
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
274
|
+
message: JSON.stringify({
|
|
275
|
+
resolver: 'RunAIAgentResolver',
|
|
276
|
+
type: 'ExecutionProgress',
|
|
277
|
+
status: 'ok',
|
|
278
|
+
data,
|
|
279
|
+
}),
|
|
280
|
+
sessionId: userPayload.sessionId,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
private PublishStreamingUpdate(pubSub: PubSubEngine, data: any, userPayload: UserPayload) {
|
|
286
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
287
|
+
message: JSON.stringify({
|
|
288
|
+
resolver: 'RunAIAgentResolver',
|
|
289
|
+
type: 'StreamingContent',
|
|
290
|
+
status: 'ok',
|
|
291
|
+
data,
|
|
292
|
+
}),
|
|
293
|
+
sessionId: userPayload.sessionId,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Create streaming content callback
|
|
299
|
+
*/
|
|
300
|
+
private createStreamingCallback(pubSub: PubSubEngine, sessionId: string, userPayload: UserPayload, agentRunIdRef: { id: string }) {
|
|
301
|
+
return (chunk: any) => {
|
|
302
|
+
console.log('💬 Publishing streaming content:', {
|
|
303
|
+
content: chunk.content.substring(0, 50) + '...',
|
|
304
|
+
isComplete: chunk.isComplete,
|
|
305
|
+
stepType: chunk.stepType,
|
|
306
|
+
sessionId,
|
|
307
|
+
agentRunId: agentRunIdRef.id
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Publish streaming content
|
|
311
|
+
const streamMsg: AgentExecutionStreamMessage = {
|
|
312
|
+
sessionId,
|
|
313
|
+
agentRunId: agentRunIdRef.id,
|
|
314
|
+
type: 'streaming',
|
|
315
|
+
streaming: {
|
|
316
|
+
content: chunk.content,
|
|
317
|
+
isPartial: !chunk.isComplete,
|
|
318
|
+
stepName: chunk.stepType,
|
|
319
|
+
agentName: chunk.modelName
|
|
320
|
+
},
|
|
321
|
+
timestamp: new Date()
|
|
322
|
+
};
|
|
323
|
+
this.PublishStreamingUpdate(pubSub, streamMsg, userPayload);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
40
327
|
@Mutation(() => AIAgentRunResult)
|
|
41
328
|
async RunAIAgent(
|
|
42
329
|
@Arg('agentId') agentId: string,
|
|
43
330
|
@Ctx() { userPayload }: { userPayload: UserPayload },
|
|
44
331
|
@Arg('messages') messagesJson: string,
|
|
332
|
+
@Arg('sessionId') sessionId: string,
|
|
333
|
+
@PubSub() pubSub: PubSubEngine,
|
|
45
334
|
@Arg('data', { nullable: true }) data?: string,
|
|
46
335
|
@Arg('templateData', { nullable: true }) templateData?: string
|
|
47
336
|
): Promise<AIAgentRunResult> {
|
|
@@ -50,125 +339,134 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
50
339
|
try {
|
|
51
340
|
LogStatus(`=== RUNNING AI AGENT FOR ID: ${agentId} ===`);
|
|
52
341
|
|
|
53
|
-
// Parse messages
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!Array.isArray(parsedMessages)) {
|
|
58
|
-
throw new Error('Messages must be an array');
|
|
59
|
-
}
|
|
60
|
-
} catch (parseError) {
|
|
61
|
-
return {
|
|
62
|
-
success: false,
|
|
63
|
-
error: `Invalid JSON in messages: ${(parseError as Error).message}`,
|
|
64
|
-
executionTimeMs: Date.now() - startTime
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Parse data contexts (JSON strings)
|
|
69
|
-
let parsedData = {};
|
|
70
|
-
let parsedTemplateData = {};
|
|
71
|
-
|
|
72
|
-
if (data) {
|
|
73
|
-
try {
|
|
74
|
-
parsedData = JSON.parse(data);
|
|
75
|
-
} catch (parseError) {
|
|
76
|
-
return {
|
|
77
|
-
success: false,
|
|
78
|
-
error: `Invalid JSON in data: ${(parseError as Error).message}`,
|
|
79
|
-
executionTimeMs: Date.now() - startTime
|
|
80
|
-
};
|
|
81
|
-
}
|
|
342
|
+
// Parse and validate messages
|
|
343
|
+
const parsedMessages = this.parseJsonInput(messagesJson, 'messages');
|
|
344
|
+
if (!Array.isArray(parsedMessages)) {
|
|
345
|
+
throw new Error('Messages must be an array');
|
|
82
346
|
}
|
|
83
347
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
} catch (parseError) {
|
|
88
|
-
return {
|
|
89
|
-
success: false,
|
|
90
|
-
error: `Invalid JSON in template data: ${(parseError as Error).message}`,
|
|
91
|
-
executionTimeMs: Date.now() - startTime
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
}
|
|
348
|
+
// Parse data contexts
|
|
349
|
+
const parsedData = this.parseJsonInput(data, 'data');
|
|
350
|
+
const parsedTemplateData = this.parseJsonInput(templateData, 'templateData');
|
|
95
351
|
|
|
96
|
-
// Get current user
|
|
352
|
+
// Get and validate current user
|
|
97
353
|
const currentUser = this.GetUserFromPayload(userPayload);
|
|
98
354
|
if (!currentUser) {
|
|
99
|
-
|
|
100
|
-
success: false,
|
|
101
|
-
error: 'Unable to determine current user',
|
|
102
|
-
executionTimeMs: Date.now() - startTime
|
|
103
|
-
};
|
|
355
|
+
throw new Error('Unable to determine current user');
|
|
104
356
|
}
|
|
105
357
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// Load the AI agent entity
|
|
109
|
-
const agentEntity = await md.GetEntityObject<AIAgentEntity>('AI Agents', currentUser);
|
|
110
|
-
await agentEntity.Load(agentId);
|
|
111
|
-
|
|
112
|
-
if (!agentEntity.IsSaved) {
|
|
113
|
-
return {
|
|
114
|
-
success: false,
|
|
115
|
-
error: `AI Agent with ID ${agentId} not found`,
|
|
116
|
-
executionTimeMs: Date.now() - startTime
|
|
117
|
-
};
|
|
118
|
-
}
|
|
358
|
+
// Validate agent
|
|
359
|
+
const agentEntity = await this.validateAgent(agentId, currentUser);
|
|
119
360
|
|
|
120
|
-
//
|
|
121
|
-
if (agentEntity.Status !== 'Active') {
|
|
122
|
-
return {
|
|
123
|
-
success: false,
|
|
124
|
-
error: `AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`,
|
|
125
|
-
executionTimeMs: Date.now() - startTime
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Create AI agent runner and execute
|
|
361
|
+
// Create AI agent runner
|
|
130
362
|
const agentRunner = new AgentRunner();
|
|
131
363
|
|
|
132
|
-
//
|
|
364
|
+
// Track agent run ID for streaming (use ref to update later)
|
|
365
|
+
const agentRunIdRef = { id: 'pending' };
|
|
366
|
+
|
|
367
|
+
console.log(`🚀 Starting agent execution with sessionId: ${sessionId}`);
|
|
368
|
+
|
|
369
|
+
// Execute the agent with streaming callbacks
|
|
133
370
|
const result = await agentRunner.RunAgent({
|
|
134
371
|
agent: agentEntity,
|
|
135
372
|
conversationMessages: parsedMessages,
|
|
136
373
|
contextUser: currentUser,
|
|
137
|
-
|
|
138
|
-
|
|
374
|
+
onProgress: this.createProgressCallback(pubSub, sessionId, userPayload, agentRunIdRef),
|
|
375
|
+
onStreaming: this.createStreamingCallback(pubSub, sessionId, userPayload, agentRunIdRef)
|
|
139
376
|
});
|
|
140
377
|
|
|
378
|
+
// Update agent run ID once available
|
|
379
|
+
if (result.agentRun) {
|
|
380
|
+
agentRunIdRef.id = result.agentRun.ID;
|
|
381
|
+
}
|
|
382
|
+
|
|
141
383
|
const executionTime = Date.now() - startTime;
|
|
142
384
|
|
|
143
|
-
|
|
385
|
+
// Publish final events
|
|
386
|
+
this.publishFinalEvents(pubSub, sessionId, userPayload, result);
|
|
387
|
+
|
|
388
|
+
// Create sanitized payload for JSON serialization
|
|
389
|
+
const sanitizedResult = this.sanitizeAgentResult(result);
|
|
390
|
+
const payload = JSON.stringify(sanitizedResult);
|
|
391
|
+
|
|
392
|
+
// Log completion
|
|
393
|
+
if (result.success) {
|
|
144
394
|
LogStatus(`=== AI AGENT RUN COMPLETED FOR: ${agentEntity.Name} (${executionTime}ms) ===`);
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
success: true,
|
|
148
|
-
output: result.rawResult,
|
|
149
|
-
parsedResult: typeof result.returnValue === 'string' ? result.returnValue : JSON.stringify(result.returnValue),
|
|
150
|
-
rawResult: result.rawResult,
|
|
151
|
-
executionTimeMs: executionTime,
|
|
152
|
-
nextStep: result.nextStep
|
|
153
|
-
};
|
|
154
395
|
} else {
|
|
155
396
|
LogError(`AI Agent run failed for ${agentEntity.Name}: ${result.errorMessage}`);
|
|
156
|
-
return {
|
|
157
|
-
success: false,
|
|
158
|
-
error: result.errorMessage,
|
|
159
|
-
executionTimeMs: executionTime,
|
|
160
|
-
nextStep: result.nextStep
|
|
161
|
-
};
|
|
162
397
|
}
|
|
163
398
|
|
|
399
|
+
return {
|
|
400
|
+
success: result.success,
|
|
401
|
+
errorMessage: result.errorMessage || undefined,
|
|
402
|
+
executionTimeMs: executionTime,
|
|
403
|
+
payload
|
|
404
|
+
};
|
|
405
|
+
|
|
164
406
|
} catch (error) {
|
|
165
407
|
const executionTime = Date.now() - startTime;
|
|
166
408
|
LogError(`AI Agent run failed:`, undefined, error);
|
|
167
|
-
|
|
409
|
+
|
|
410
|
+
// Create error payload
|
|
411
|
+
const errorResult = {
|
|
168
412
|
success: false,
|
|
169
|
-
|
|
413
|
+
errorMessage: (error as Error).message || 'Unknown error occurred',
|
|
170
414
|
executionTimeMs: executionTime
|
|
171
415
|
};
|
|
416
|
+
|
|
417
|
+
return {
|
|
418
|
+
success: false,
|
|
419
|
+
errorMessage: errorResult.errorMessage,
|
|
420
|
+
executionTimeMs: executionTime,
|
|
421
|
+
payload: JSON.stringify(errorResult)
|
|
422
|
+
};
|
|
172
423
|
}
|
|
173
424
|
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Publish final streaming events (partial result and completion)
|
|
428
|
+
*/
|
|
429
|
+
private publishFinalEvents(pubSub: PubSubEngine, sessionId: string, userPayload: UserPayload, result: ExecuteAgentResult) {
|
|
430
|
+
if (result.agentRun) {
|
|
431
|
+
// Get the last step from execution tree
|
|
432
|
+
let lastStep = 'Completed';
|
|
433
|
+
if (result.executionTree && result.executionTree.length > 0) {
|
|
434
|
+
// Find the last step by traversing the tree
|
|
435
|
+
const findLastStep = (nodes: any[]): any => {
|
|
436
|
+
let last = nodes[nodes.length - 1];
|
|
437
|
+
if (last.children && last.children.length > 0) {
|
|
438
|
+
return findLastStep(last.children);
|
|
439
|
+
}
|
|
440
|
+
return last;
|
|
441
|
+
};
|
|
442
|
+
const lastNode = findLastStep(result.executionTree);
|
|
443
|
+
lastStep = lastNode.step?.StepName || 'Completed';
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Publish partial result
|
|
447
|
+
const partialResult: AgentPartialResult = {
|
|
448
|
+
currentStep: lastStep,
|
|
449
|
+
partialOutput: result.returnValue || undefined
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
const partialMsg: AgentExecutionStreamMessage = {
|
|
453
|
+
sessionId,
|
|
454
|
+
agentRunId: result.agentRun.ID,
|
|
455
|
+
type: 'partial_result',
|
|
456
|
+
partialResult,
|
|
457
|
+
timestamp: new Date()
|
|
458
|
+
};
|
|
459
|
+
this.PublishStreamingUpdate(pubSub, partialMsg, userPayload);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Publish completion
|
|
463
|
+
const completeMsg: AgentExecutionStreamMessage = {
|
|
464
|
+
sessionId,
|
|
465
|
+
agentRunId: result.agentRun?.ID || 'unknown',
|
|
466
|
+
type: 'complete',
|
|
467
|
+
timestamp: new Date()
|
|
468
|
+
};
|
|
469
|
+
this.PublishStreamingUpdate(pubSub, completeMsg, userPayload);
|
|
470
|
+
}
|
|
471
|
+
|
|
174
472
|
}
|