@memberjunction/server 2.112.0 → 2.113.1
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/agents/skip-agent.d.ts +4 -4
- package/dist/agents/skip-agent.d.ts.map +1 -1
- package/dist/agents/skip-agent.js +951 -808
- package/dist/agents/skip-agent.js.map +1 -1
- package/dist/agents/skip-sdk.d.ts +1 -1
- package/dist/agents/skip-sdk.d.ts.map +1 -1
- package/dist/agents/skip-sdk.js +43 -53
- package/dist/agents/skip-sdk.js.map +1 -1
- package/dist/apolloServer/index.js +1 -1
- package/dist/auth/AuthProviderFactory.d.ts +1 -1
- package/dist/auth/AuthProviderFactory.d.ts.map +1 -1
- package/dist/auth/AuthProviderFactory.js +3 -1
- package/dist/auth/AuthProviderFactory.js.map +1 -1
- package/dist/auth/BaseAuthProvider.d.ts +1 -1
- package/dist/auth/BaseAuthProvider.d.ts.map +1 -1
- package/dist/auth/BaseAuthProvider.js +2 -3
- package/dist/auth/BaseAuthProvider.js.map +1 -1
- package/dist/auth/IAuthProvider.d.ts +1 -1
- package/dist/auth/IAuthProvider.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.js +1 -1
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +6 -6
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/initializeProviders.js +1 -1
- package/dist/auth/initializeProviders.js.map +1 -1
- package/dist/auth/newUsers.d.ts +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +7 -7
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/auth/providers/Auth0Provider.d.ts +1 -1
- package/dist/auth/providers/Auth0Provider.d.ts.map +1 -1
- package/dist/auth/providers/Auth0Provider.js +1 -1
- package/dist/auth/providers/Auth0Provider.js.map +1 -1
- package/dist/auth/providers/CognitoProvider.d.ts +1 -1
- package/dist/auth/providers/CognitoProvider.d.ts.map +1 -1
- package/dist/auth/providers/CognitoProvider.js +6 -3
- package/dist/auth/providers/CognitoProvider.js.map +1 -1
- package/dist/auth/providers/GoogleProvider.d.ts +1 -1
- package/dist/auth/providers/GoogleProvider.d.ts.map +1 -1
- package/dist/auth/providers/GoogleProvider.js +1 -1
- package/dist/auth/providers/GoogleProvider.js.map +1 -1
- package/dist/auth/providers/MSALProvider.d.ts +1 -1
- package/dist/auth/providers/MSALProvider.d.ts.map +1 -1
- package/dist/auth/providers/MSALProvider.js +1 -1
- package/dist/auth/providers/MSALProvider.js.map +1 -1
- package/dist/auth/providers/OktaProvider.d.ts +1 -1
- package/dist/auth/providers/OktaProvider.d.ts.map +1 -1
- package/dist/auth/providers/OktaProvider.js +1 -1
- package/dist/auth/providers/OktaProvider.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -22
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +7 -9
- package/dist/context.js.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.js +1 -1
- package/dist/entitySubclasses/entityPermissions.server.js.map +1 -1
- package/dist/generated/generated.d.ts +788 -658
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +2050 -3054
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/KeyInputOutputTypes.d.ts +1 -1
- package/dist/generic/KeyInputOutputTypes.d.ts.map +1 -1
- package/dist/generic/KeyInputOutputTypes.js +1 -1
- package/dist/generic/KeyInputOutputTypes.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 +10 -15
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +15 -15
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -18
- package/dist/index.js.map +1 -1
- package/dist/resolvers/ActionResolver.d.ts +2 -2
- package/dist/resolvers/ActionResolver.d.ts.map +1 -1
- package/dist/resolvers/ActionResolver.js +30 -28
- package/dist/resolvers/ActionResolver.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +2 -2
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +50 -60
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +38 -36
- package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/CreateQueryResolver.js +40 -43
- package/dist/resolvers/CreateQueryResolver.js.map +1 -1
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
- package/dist/resolvers/DatasetResolver.js +1 -1
- package/dist/resolvers/DatasetResolver.js.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts +1 -1
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js +1 -1
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
- package/dist/resolvers/EntityResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityResolver.js +1 -1
- package/dist/resolvers/EntityResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +1 -1
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.js +1 -1
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts +1 -1
- package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataContextDataResolver.js +5 -5
- package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +6 -8
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts +3 -3
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +3 -3
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js +1 -1
- package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -1
- package/dist/resolvers/QueryResolver.d.ts.map +1 -1
- package/dist/resolvers/QueryResolver.js +11 -11
- package/dist/resolvers/QueryResolver.js.map +1 -1
- package/dist/resolvers/ReportResolver.js +1 -1
- package/dist/resolvers/ReportResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +28 -27
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.js +31 -31
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -1
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
- package/dist/resolvers/RunTemplateResolver.js +9 -9
- package/dist/resolvers/RunTemplateResolver.js.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
- package/dist/resolvers/SqlLoggingConfigResolver.js +10 -10
- package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +14 -15
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +44 -48
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/TaskResolver.d.ts.map +1 -1
- package/dist/resolvers/TaskResolver.js +7 -7
- package/dist/resolvers/TaskResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js +12 -12
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +1 -1
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts +1 -1
- package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
- package/dist/rest/EntityCRUDHandler.js +16 -14
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +25 -23
- package/dist/rest/RESTEndpointHandler.js.map +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts +1 -1
- package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
- package/dist/rest/ViewOperationsHandler.js +21 -17
- package/dist/rest/ViewOperationsHandler.js.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.d.ts.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.js.map +1 -1
- package/dist/services/ScheduledJobsService.d.ts.map +1 -1
- package/dist/services/ScheduledJobsService.js +6 -4
- package/dist/services/ScheduledJobsService.js.map +1 -1
- package/dist/services/TaskOrchestrator.d.ts +1 -1
- package/dist/services/TaskOrchestrator.d.ts.map +1 -1
- package/dist/services/TaskOrchestrator.js +30 -30
- package/dist/services/TaskOrchestrator.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +2 -2
- package/dist/util.js.map +1 -1
- package/package.json +39 -36
- package/src/agents/skip-agent.ts +1200 -1067
- package/src/agents/skip-sdk.ts +851 -877
- package/src/apolloServer/index.ts +2 -2
- package/src/auth/AuthProviderFactory.ts +14 -8
- package/src/auth/BaseAuthProvider.ts +4 -5
- package/src/auth/IAuthProvider.ts +2 -2
- package/src/auth/exampleNewUserSubClass.ts +2 -9
- package/src/auth/index.ts +26 -31
- package/src/auth/initializeProviders.ts +3 -3
- package/src/auth/newUsers.ts +134 -166
- package/src/auth/providers/Auth0Provider.ts +5 -5
- package/src/auth/providers/CognitoProvider.ts +10 -7
- package/src/auth/providers/GoogleProvider.ts +5 -4
- package/src/auth/providers/MSALProvider.ts +5 -5
- package/src/auth/providers/OktaProvider.ts +7 -6
- package/src/config.ts +54 -63
- package/src/context.ts +30 -42
- package/src/entitySubclasses/entityPermissions.server.ts +3 -3
- package/src/generated/generated.ts +40442 -48106
- package/src/generic/KeyInputOutputTypes.ts +6 -3
- package/src/generic/ResolverBase.ts +78 -119
- package/src/generic/RunViewResolver.ts +23 -27
- package/src/index.ts +48 -66
- package/src/resolvers/ActionResolver.ts +57 -46
- package/src/resolvers/AskSkipResolver.ts +533 -607
- package/src/resolvers/ComponentRegistryResolver.ts +562 -547
- package/src/resolvers/CreateQueryResolver.ts +655 -683
- package/src/resolvers/DatasetResolver.ts +6 -5
- package/src/resolvers/EntityCommunicationsResolver.ts +1 -1
- package/src/resolvers/EntityRecordNameResolver.ts +5 -9
- package/src/resolvers/EntityResolver.ts +7 -9
- package/src/resolvers/FileCategoryResolver.ts +2 -2
- package/src/resolvers/FileResolver.ts +4 -4
- package/src/resolvers/GetDataContextDataResolver.ts +118 -106
- package/src/resolvers/GetDataResolver.ts +205 -194
- package/src/resolvers/MergeRecordsResolver.ts +5 -5
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +1 -1
- package/src/resolvers/QueryResolver.ts +78 -95
- package/src/resolvers/ReportResolver.ts +2 -2
- package/src/resolvers/RunAIAgentResolver.ts +828 -818
- package/src/resolvers/RunAIPromptResolver.ts +709 -693
- package/src/resolvers/RunTemplateResolver.ts +103 -105
- package/src/resolvers/SqlLoggingConfigResolver.ts +72 -69
- package/src/resolvers/SyncDataResolver.ts +352 -386
- package/src/resolvers/SyncRolesUsersResolver.ts +350 -387
- package/src/resolvers/TaskResolver.ts +115 -110
- package/src/resolvers/TransactionGroupResolver.ts +138 -143
- package/src/resolvers/UserFavoriteResolver.ts +8 -17
- package/src/resolvers/UserViewResolver.ts +12 -17
- package/src/rest/EntityCRUDHandler.ts +268 -291
- package/src/rest/RESTEndpointHandler.ts +776 -782
- package/src/rest/ViewOperationsHandler.ts +195 -191
- package/src/scheduler/LearningCycleScheduler.ts +52 -8
- package/src/services/ScheduledJobsService.ts +132 -129
- package/src/services/TaskOrchestrator.ts +776 -792
- package/src/types.ts +9 -15
- package/src/util.ts +109 -112
|
@@ -1,29 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Resolver,
|
|
3
|
-
Mutation,
|
|
4
|
-
Query,
|
|
5
|
-
Arg,
|
|
6
|
-
Ctx,
|
|
7
|
-
ObjectType,
|
|
8
|
-
Field,
|
|
9
|
-
PubSub,
|
|
10
|
-
PubSubEngine,
|
|
11
|
-
Subscription,
|
|
12
|
-
Root,
|
|
13
|
-
ResolverFilterData,
|
|
14
|
-
ID,
|
|
15
|
-
} from 'type-graphql';
|
|
1
|
+
import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID } from 'type-graphql';
|
|
16
2
|
import { AppContext, UserPayload } from '../types.js';
|
|
17
|
-
import { DatabaseProviderBase, LogError, LogStatus, Metadata, RunView, UserInfo } from '@memberjunction/
|
|
18
|
-
import {
|
|
19
|
-
AIAgentEntityExtended,
|
|
20
|
-
ArtifactEntity,
|
|
21
|
-
ArtifactVersionEntity,
|
|
22
|
-
ConversationDetailArtifactEntity,
|
|
23
|
-
ConversationDetailEntity,
|
|
24
|
-
UserNotificationEntity,
|
|
25
|
-
AIAgentRunEntityExtended,
|
|
26
|
-
} from '@memberjunction/core-entities';
|
|
3
|
+
import { DatabaseProviderBase, LogError, LogStatus, Metadata, RunView, UserInfo } from '@memberjunction/core';
|
|
4
|
+
import { AIAgentEntityExtended, ArtifactEntity, ArtifactVersionEntity, ConversationDetailArtifactEntity, ConversationDetailEntity, UserNotificationEntity, AIAgentRunEntityExtended } from '@memberjunction/core-entities';
|
|
27
5
|
import { AgentRunner } from '@memberjunction/ai-agents';
|
|
28
6
|
import { ExecuteAgentResult } from '@memberjunction/ai-core-plus';
|
|
29
7
|
import { AIEngine } from '@memberjunction/aiengine';
|
|
@@ -35,878 +13,910 @@ import { SafeJSONParse } from '@memberjunction/global';
|
|
|
35
13
|
|
|
36
14
|
@ObjectType()
|
|
37
15
|
export class AIAgentRunResult {
|
|
38
|
-
|
|
39
|
-
|
|
16
|
+
@Field()
|
|
17
|
+
success: boolean;
|
|
40
18
|
|
|
41
|
-
|
|
42
|
-
|
|
19
|
+
@Field({ nullable: true })
|
|
20
|
+
errorMessage?: string;
|
|
43
21
|
|
|
44
|
-
|
|
45
|
-
|
|
22
|
+
@Field({ nullable: true })
|
|
23
|
+
executionTimeMs?: number;
|
|
46
24
|
|
|
47
|
-
|
|
48
|
-
|
|
25
|
+
@Field()
|
|
26
|
+
result: string; // JSON serialized ExecuteAgentResult with scalars only
|
|
49
27
|
}
|
|
50
28
|
|
|
51
29
|
@ObjectType()
|
|
52
30
|
export class AgentExecutionProgress {
|
|
53
|
-
|
|
54
|
-
|
|
31
|
+
@Field()
|
|
32
|
+
currentStep: string;
|
|
55
33
|
|
|
56
|
-
|
|
57
|
-
|
|
34
|
+
@Field()
|
|
35
|
+
percentage: number;
|
|
58
36
|
|
|
59
|
-
|
|
60
|
-
|
|
37
|
+
@Field()
|
|
38
|
+
message: string;
|
|
61
39
|
|
|
62
|
-
|
|
63
|
-
|
|
40
|
+
@Field({ nullable: true })
|
|
41
|
+
agentName?: string;
|
|
64
42
|
|
|
65
|
-
|
|
66
|
-
|
|
43
|
+
@Field({ nullable: true })
|
|
44
|
+
agentType?: string;
|
|
67
45
|
}
|
|
68
46
|
|
|
69
47
|
@ObjectType()
|
|
70
48
|
export class AgentStreamingContent {
|
|
71
|
-
|
|
72
|
-
|
|
49
|
+
@Field()
|
|
50
|
+
content: string;
|
|
73
51
|
|
|
74
|
-
|
|
75
|
-
|
|
52
|
+
@Field()
|
|
53
|
+
isPartial: boolean;
|
|
76
54
|
|
|
77
|
-
|
|
78
|
-
|
|
55
|
+
@Field({ nullable: true })
|
|
56
|
+
stepName?: string;
|
|
79
57
|
|
|
80
|
-
|
|
81
|
-
|
|
58
|
+
@Field({ nullable: true })
|
|
59
|
+
agentName?: string;
|
|
82
60
|
}
|
|
83
61
|
|
|
84
62
|
@ObjectType()
|
|
85
63
|
export class AgentExecutionStepSummary {
|
|
86
|
-
|
|
87
|
-
|
|
64
|
+
@Field()
|
|
65
|
+
stepId: string;
|
|
88
66
|
|
|
89
|
-
|
|
90
|
-
|
|
67
|
+
@Field()
|
|
68
|
+
stepName: string;
|
|
91
69
|
|
|
92
|
-
|
|
93
|
-
|
|
70
|
+
@Field({ nullable: true })
|
|
71
|
+
agentName?: string;
|
|
94
72
|
|
|
95
|
-
|
|
96
|
-
|
|
73
|
+
@Field({ nullable: true })
|
|
74
|
+
agentType?: string;
|
|
97
75
|
|
|
98
|
-
|
|
99
|
-
|
|
76
|
+
@Field()
|
|
77
|
+
startTime: Date;
|
|
100
78
|
|
|
101
|
-
|
|
102
|
-
|
|
79
|
+
@Field({ nullable: true })
|
|
80
|
+
endTime?: Date;
|
|
103
81
|
|
|
104
|
-
|
|
105
|
-
|
|
82
|
+
@Field()
|
|
83
|
+
status: string;
|
|
106
84
|
|
|
107
|
-
|
|
108
|
-
|
|
85
|
+
@Field({ nullable: true })
|
|
86
|
+
result?: string;
|
|
109
87
|
}
|
|
110
88
|
|
|
111
89
|
@ObjectType()
|
|
112
90
|
export class AgentPartialResult {
|
|
113
|
-
|
|
114
|
-
|
|
91
|
+
@Field()
|
|
92
|
+
currentStep: string;
|
|
115
93
|
|
|
116
|
-
|
|
117
|
-
|
|
94
|
+
@Field({ nullable: true })
|
|
95
|
+
partialOutput?: string;
|
|
118
96
|
}
|
|
119
97
|
|
|
120
98
|
@ObjectType()
|
|
121
99
|
export class AgentExecutionStreamMessage {
|
|
122
|
-
|
|
123
|
-
|
|
100
|
+
@Field(() => ID)
|
|
101
|
+
sessionId: string;
|
|
124
102
|
|
|
125
|
-
|
|
126
|
-
|
|
103
|
+
@Field(() => ID)
|
|
104
|
+
agentRunId: string;
|
|
127
105
|
|
|
128
|
-
|
|
129
|
-
|
|
106
|
+
@Field()
|
|
107
|
+
type: 'progress' | 'streaming' | 'partial_result' | 'complete';
|
|
130
108
|
|
|
131
|
-
|
|
132
|
-
|
|
109
|
+
@Field({ nullable: true })
|
|
110
|
+
progress?: AgentExecutionProgress;
|
|
133
111
|
|
|
134
|
-
|
|
135
|
-
|
|
112
|
+
@Field({ nullable: true })
|
|
113
|
+
streaming?: AgentStreamingContent;
|
|
136
114
|
|
|
137
|
-
|
|
138
|
-
|
|
115
|
+
@Field({ nullable: true })
|
|
116
|
+
partialResult?: AgentPartialResult;
|
|
139
117
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
118
|
+
@Field()
|
|
119
|
+
timestamp: Date;
|
|
120
|
+
|
|
121
|
+
// Not a GraphQL field - used internally for streaming
|
|
122
|
+
agentRun?: any;
|
|
145
123
|
}
|
|
146
124
|
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
147
129
|
@Resolver()
|
|
148
130
|
export class RunAIAgentResolver extends ResolverBase {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Sanitize ExecuteAgentResult for JSON serialization
|
|
133
|
+
* Removes circular references and non-serializable objects
|
|
134
|
+
*/
|
|
135
|
+
private sanitizeAgentResult(result: ExecuteAgentResult): any {
|
|
136
|
+
const sanitized: any = {
|
|
137
|
+
success: result.success,
|
|
138
|
+
payload: result.payload,
|
|
139
|
+
suggestedResponses: result.suggestedResponses,
|
|
140
|
+
errorMessage: result.agentRun?.ErrorMessage,
|
|
141
|
+
finalStep: result.agentRun?.FinalStep,
|
|
142
|
+
cancelled: result.agentRun?.Status === 'Cancelled',
|
|
143
|
+
cancellationReason: result.agentRun?.CancellationReason
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Safely extract agent run data using GetAll() for proper serialization
|
|
147
|
+
if (result.agentRun && typeof result.agentRun.GetAll === 'function') {
|
|
148
|
+
// Use GetAll() to get the full serialized object including extended properties
|
|
149
|
+
sanitized.agentRun = result.agentRun.GetAll();
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// shouldn't ever get here
|
|
153
|
+
console.error('❌ Unexpected agent run structure:', result.agentRun);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return sanitized;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Parse and validate JSON input
|
|
162
|
+
*/
|
|
163
|
+
private parseJsonInput(jsonString: string | undefined, fieldName: string): any {
|
|
164
|
+
if (!jsonString) return {};
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
return JSON.parse(jsonString);
|
|
168
|
+
} catch (parseError) {
|
|
169
|
+
throw new Error(`Invalid JSON in ${fieldName}: ${(parseError as Error).message}`);
|
|
170
|
+
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Validate the agent entity
|
|
175
|
+
*/
|
|
176
|
+
private async validateAgent(agentId: string, currentUser: any): Promise<AIAgentEntityExtended> {
|
|
177
|
+
// Use AIEngine to get cached agent data
|
|
178
|
+
await AIEngine.Instance.Config(false, currentUser);
|
|
179
|
+
|
|
180
|
+
// Find agent in cached collection
|
|
181
|
+
const agentEntity = AIEngine.Instance.Agents.find((a: AIAgentEntityExtended) => a.ID === agentId);
|
|
182
|
+
|
|
183
|
+
if (!agentEntity) {
|
|
184
|
+
throw new Error(`AI Agent with ID ${agentId} not found`);
|
|
185
|
+
}
|
|
175
186
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (!jsonString) return {};
|
|
187
|
+
// Check if agent is active
|
|
188
|
+
if (agentEntity.Status !== 'Active') {
|
|
189
|
+
throw new Error(`AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`);
|
|
190
|
+
}
|
|
181
191
|
|
|
182
|
-
|
|
183
|
-
return JSON.parse(jsonString);
|
|
184
|
-
} catch (parseError) {
|
|
185
|
-
throw new Error(`Invalid JSON in ${fieldName}: ${(parseError as Error).message}`);
|
|
192
|
+
return agentEntity;
|
|
186
193
|
}
|
|
187
|
-
}
|
|
188
194
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Create streaming progress callback
|
|
197
|
+
*/
|
|
198
|
+
private createProgressCallback(pubSub: PubSubEngine, sessionId: string, userPayload: UserPayload, agentRunRef: { current: any }) {
|
|
199
|
+
return (progress: any) => {
|
|
200
|
+
// Only publish progress for significant steps (not initialization noise)
|
|
201
|
+
const significantSteps = ['prompt_execution', 'action_execution', 'subagent_execution', 'decision_processing'];
|
|
202
|
+
if (!significantSteps.includes(progress.step)) {
|
|
203
|
+
console.log(`🔇 Skipping noise progress: ${progress.step}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Get the agent run from the progress metadata or use the ref
|
|
208
|
+
const agentRun = progress.metadata?.agentRun || agentRunRef.current;
|
|
209
|
+
if (!agentRun) {
|
|
210
|
+
console.error('❌ No agent run available for progress callback');
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
console.log('📡 Publishing progress update:', {
|
|
215
|
+
step: progress.step,
|
|
216
|
+
percentage: progress.percentage,
|
|
217
|
+
message: progress.message,
|
|
218
|
+
sessionId,
|
|
219
|
+
agentRunId: agentRun.ID
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Publish progress updates with the full serialized agent run
|
|
223
|
+
const progressMsg: AgentExecutionStreamMessage = {
|
|
224
|
+
sessionId,
|
|
225
|
+
agentRunId: agentRun.ID,
|
|
226
|
+
type: 'progress',
|
|
227
|
+
agentRun: agentRun.GetAll(), // Serialize the full agent run
|
|
228
|
+
progress: {
|
|
229
|
+
currentStep: progress.step,
|
|
230
|
+
percentage: progress.percentage,
|
|
231
|
+
message: progress.message,
|
|
232
|
+
agentName: (progress.metadata as any)?.agentName || undefined,
|
|
233
|
+
agentType: (progress.metadata as any)?.agentType || undefined
|
|
234
|
+
},
|
|
235
|
+
timestamp: new Date()
|
|
236
|
+
};
|
|
237
|
+
this.PublishProgressUpdate(pubSub, progressMsg, userPayload);
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private PublishProgressUpdate(pubSub: PubSubEngine, data: any, userPayload: UserPayload) {
|
|
242
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
243
|
+
message: JSON.stringify({
|
|
244
|
+
resolver: 'RunAIAgentResolver',
|
|
245
|
+
type: 'ExecutionProgress',
|
|
246
|
+
status: 'ok',
|
|
247
|
+
data,
|
|
248
|
+
}),
|
|
249
|
+
sessionId: userPayload.sessionId,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
195
252
|
|
|
196
|
-
// Find agent in cached collection
|
|
197
|
-
const agentEntity = AIEngine.Instance.Agents.find((a: AIAgentEntityExtended) => a.ID === agentId);
|
|
198
253
|
|
|
199
|
-
|
|
200
|
-
|
|
254
|
+
private PublishStreamingUpdate(pubSub: PubSubEngine, data: any, userPayload: UserPayload) {
|
|
255
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
256
|
+
message: JSON.stringify({
|
|
257
|
+
resolver: 'RunAIAgentResolver',
|
|
258
|
+
type: 'StreamingContent',
|
|
259
|
+
status: 'ok',
|
|
260
|
+
data,
|
|
261
|
+
}),
|
|
262
|
+
sessionId: userPayload.sessionId,
|
|
263
|
+
});
|
|
201
264
|
}
|
|
202
265
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
266
|
+
/**
|
|
267
|
+
* Create streaming content callback
|
|
268
|
+
*/
|
|
269
|
+
private createStreamingCallback(pubSub: PubSubEngine, sessionId: string, userPayload: UserPayload, agentRunRef: { current: any }) {
|
|
270
|
+
return (chunk: any) => {
|
|
271
|
+
// Use the agent run from the ref
|
|
272
|
+
const agentRun = agentRunRef.current;
|
|
273
|
+
if (!agentRun) {
|
|
274
|
+
console.error('❌ No agent run available for streaming callback');
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
console.log('💬 Publishing streaming content:', {
|
|
279
|
+
content: chunk.content.substring(0, 50) + '...',
|
|
280
|
+
isComplete: chunk.isComplete,
|
|
281
|
+
stepType: chunk.stepType,
|
|
282
|
+
sessionId,
|
|
283
|
+
agentRunId: agentRun.ID
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Publish streaming content with the full serialized agent run
|
|
287
|
+
const streamMsg: AgentExecutionStreamMessage = {
|
|
288
|
+
sessionId,
|
|
289
|
+
agentRunId: agentRun.ID,
|
|
290
|
+
type: 'streaming',
|
|
291
|
+
agentRun: agentRun.GetAll(), // Include the full serialized agent run
|
|
292
|
+
streaming: {
|
|
293
|
+
content: chunk.content,
|
|
294
|
+
isPartial: !chunk.isComplete,
|
|
295
|
+
stepName: chunk.stepType,
|
|
296
|
+
agentName: chunk.modelName
|
|
297
|
+
},
|
|
298
|
+
timestamp: new Date()
|
|
299
|
+
};
|
|
300
|
+
this.PublishStreamingUpdate(pubSub, streamMsg, userPayload);
|
|
301
|
+
};
|
|
206
302
|
}
|
|
207
303
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
// Get and validate current user
|
|
359
|
-
const currentUser = this.GetUserFromPayload(userPayload);
|
|
360
|
-
if (!currentUser) {
|
|
361
|
-
throw new Error('Unable to determine current user');
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Validate agent
|
|
365
|
-
const agentEntity = await this.validateAgent(agentId, currentUser);
|
|
366
|
-
|
|
367
|
-
// @jordanfanapour IMPORTANT TO-DO for various engine classes (via base engine class) and here for AI Agent Runner and for AI Prompt Runner, need to be able to pass in a IMetadataProvider for it to use
|
|
368
|
-
// for multi-user server environments like this one
|
|
369
|
-
// Create AI agent runner
|
|
370
|
-
const agentRunner = new AgentRunner();
|
|
371
|
-
|
|
372
|
-
// Track agent run for streaming (use ref to update later)
|
|
373
|
-
const agentRunRef = { current: null as any };
|
|
374
|
-
|
|
375
|
-
console.log(`🚀 Starting agent execution with sessionId: ${sessionId}`);
|
|
376
|
-
|
|
377
|
-
// Execute the agent with streaming callbacks
|
|
378
|
-
const result = await agentRunner.RunAgent({
|
|
379
|
-
agent: agentEntity,
|
|
380
|
-
conversationMessages: parsedMessages,
|
|
381
|
-
payload: payload ? SafeJSONParse(payload) : undefined,
|
|
382
|
-
contextUser: currentUser,
|
|
383
|
-
onProgress: this.createProgressCallback(pubSub, sessionId, userPayload, agentRunRef),
|
|
384
|
-
onStreaming: this.createStreamingCallback(pubSub, sessionId, userPayload, agentRunRef),
|
|
385
|
-
lastRunId: lastRunId,
|
|
386
|
-
autoPopulateLastRunPayload: autoPopulateLastRunPayload,
|
|
387
|
-
configurationId: configurationId,
|
|
388
|
-
data: parsedData,
|
|
389
|
-
conversationDetailId: conversationDetailId,
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Update agent run ref once available
|
|
393
|
-
if (result.agentRun) {
|
|
394
|
-
agentRunRef.current = result.agentRun;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const executionTime = Date.now() - startTime;
|
|
398
|
-
|
|
399
|
-
// Publish final events
|
|
400
|
-
this.publishFinalEvents(pubSub, sessionId, userPayload, result);
|
|
401
|
-
|
|
402
|
-
// Process completion for artifacts and notifications (if enabled)
|
|
403
|
-
if (result.success && conversationDetailId && result.payload) {
|
|
404
|
-
const currentUser = this.GetUserFromPayload(userPayload);
|
|
405
|
-
|
|
406
|
-
if (createArtifacts) {
|
|
407
|
-
const artifactInfo = await this.processAgentCompletionForArtifacts(
|
|
408
|
-
result.agentRun,
|
|
409
|
-
result.payload,
|
|
410
|
-
currentUser,
|
|
411
|
-
conversationDetailId,
|
|
412
|
-
sourceArtifactId
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
// Create notification if enabled and artifact was created successfully
|
|
416
|
-
if (createNotification && artifactInfo.artifactId && artifactInfo.versionId && artifactInfo.versionNumber) {
|
|
417
|
-
await this.createCompletionNotification(
|
|
418
|
-
result.agentRun,
|
|
419
|
-
{
|
|
420
|
-
artifactId: artifactInfo.artifactId,
|
|
421
|
-
versionId: artifactInfo.versionId,
|
|
422
|
-
versionNumber: artifactInfo.versionNumber,
|
|
423
|
-
},
|
|
424
|
-
conversationDetailId,
|
|
425
|
-
currentUser,
|
|
426
|
-
pubSub,
|
|
427
|
-
userPayload
|
|
428
|
-
);
|
|
429
|
-
}
|
|
304
|
+
/**
|
|
305
|
+
* Internal method that handles the core AI agent execution logic.
|
|
306
|
+
* This method is called by both the regular and system user resolvers.
|
|
307
|
+
* @private
|
|
308
|
+
*/
|
|
309
|
+
private async executeAIAgent(
|
|
310
|
+
p: DatabaseProviderBase,
|
|
311
|
+
agentId: string,
|
|
312
|
+
userPayload: UserPayload,
|
|
313
|
+
messagesJson: string,
|
|
314
|
+
sessionId: string,
|
|
315
|
+
pubSub: PubSubEngine,
|
|
316
|
+
data?: string,
|
|
317
|
+
payload?: string,
|
|
318
|
+
templateData?: string,
|
|
319
|
+
lastRunId?: string,
|
|
320
|
+
autoPopulateLastRunPayload?: boolean,
|
|
321
|
+
configurationId?: string,
|
|
322
|
+
conversationDetailId?: string,
|
|
323
|
+
createArtifacts: boolean = false,
|
|
324
|
+
createNotification: boolean = false,
|
|
325
|
+
sourceArtifactId?: string,
|
|
326
|
+
sourceArtifactVersionId?: string
|
|
327
|
+
): Promise<AIAgentRunResult> {
|
|
328
|
+
const startTime = Date.now();
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
LogStatus(`=== RUNNING AI AGENT FOR ID: ${agentId} ===`);
|
|
332
|
+
|
|
333
|
+
// Parse and validate messages
|
|
334
|
+
const parsedMessages = this.parseJsonInput(messagesJson, 'messages');
|
|
335
|
+
if (!Array.isArray(parsedMessages)) {
|
|
336
|
+
throw new Error('Messages must be an array');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Parse data contexts
|
|
340
|
+
const parsedData = this.parseJsonInput(data, 'data');
|
|
341
|
+
const parsedTemplateData = this.parseJsonInput(templateData, 'templateData');
|
|
342
|
+
|
|
343
|
+
// Get and validate current user
|
|
344
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
345
|
+
if (!currentUser) {
|
|
346
|
+
throw new Error('Unable to determine current user');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Validate agent
|
|
350
|
+
const agentEntity = await this.validateAgent(agentId, currentUser);
|
|
351
|
+
|
|
352
|
+
// @jordanfanapour IMPORTANT TO-DO for various engine classes (via base engine class) and here for AI Agent Runner and for AI Prompt Runner, need to be able to pass in a IMetadataProvider for it to use
|
|
353
|
+
// for multi-user server environments like this one
|
|
354
|
+
// Create AI agent runner
|
|
355
|
+
const agentRunner = new AgentRunner();
|
|
356
|
+
|
|
357
|
+
// Track agent run for streaming (use ref to update later)
|
|
358
|
+
const agentRunRef = { current: null as any };
|
|
359
|
+
|
|
360
|
+
console.log(`🚀 Starting agent execution with sessionId: ${sessionId}`);
|
|
361
|
+
|
|
362
|
+
// Execute the agent with streaming callbacks
|
|
363
|
+
const result = await agentRunner.RunAgent({
|
|
364
|
+
agent: agentEntity,
|
|
365
|
+
conversationMessages: parsedMessages,
|
|
366
|
+
payload: payload ? SafeJSONParse(payload) : undefined,
|
|
367
|
+
contextUser: currentUser,
|
|
368
|
+
onProgress: this.createProgressCallback(pubSub, sessionId, userPayload, agentRunRef),
|
|
369
|
+
onStreaming: this.createStreamingCallback(pubSub, sessionId, userPayload, agentRunRef),
|
|
370
|
+
lastRunId: lastRunId,
|
|
371
|
+
autoPopulateLastRunPayload: autoPopulateLastRunPayload,
|
|
372
|
+
configurationId: configurationId,
|
|
373
|
+
data: parsedData,
|
|
374
|
+
conversationDetailId: conversationDetailId,
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Update agent run ref once available
|
|
378
|
+
if (result.agentRun) {
|
|
379
|
+
agentRunRef.current = result.agentRun;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const executionTime = Date.now() - startTime;
|
|
383
|
+
|
|
384
|
+
// Publish final events
|
|
385
|
+
this.publishFinalEvents(pubSub, sessionId, userPayload, result);
|
|
386
|
+
|
|
387
|
+
// Process completion for artifacts and notifications (if enabled)
|
|
388
|
+
if (result.success && conversationDetailId && result.payload) {
|
|
389
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
390
|
+
|
|
391
|
+
if (createArtifacts) {
|
|
392
|
+
const artifactInfo = await this.processAgentCompletionForArtifacts(
|
|
393
|
+
result.agentRun,
|
|
394
|
+
result.payload,
|
|
395
|
+
currentUser,
|
|
396
|
+
conversationDetailId,
|
|
397
|
+
sourceArtifactId
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
// Create notification if enabled and artifact was created successfully
|
|
401
|
+
if (createNotification && artifactInfo.artifactId && artifactInfo.versionId && artifactInfo.versionNumber) {
|
|
402
|
+
await this.createCompletionNotification(
|
|
403
|
+
result.agentRun,
|
|
404
|
+
{
|
|
405
|
+
artifactId: artifactInfo.artifactId,
|
|
406
|
+
versionId: artifactInfo.versionId,
|
|
407
|
+
versionNumber: artifactInfo.versionNumber
|
|
408
|
+
},
|
|
409
|
+
conversationDetailId,
|
|
410
|
+
currentUser,
|
|
411
|
+
pubSub,
|
|
412
|
+
userPayload
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Create sanitized payload for JSON serialization
|
|
419
|
+
const sanitizedResult = this.sanitizeAgentResult(result);
|
|
420
|
+
const returnResult = JSON.stringify(sanitizedResult);
|
|
421
|
+
|
|
422
|
+
// Log completion
|
|
423
|
+
if (result.success) {
|
|
424
|
+
LogStatus(`=== AI AGENT RUN COMPLETED FOR: ${agentEntity.Name} (${executionTime}ms) ===`);
|
|
425
|
+
} else {
|
|
426
|
+
LogError(`AI Agent run failed for ${agentEntity.Name}: ${result.agentRun?.ErrorMessage}`);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
success: result.success,
|
|
431
|
+
errorMessage: result.agentRun?.ErrorMessage || undefined,
|
|
432
|
+
executionTimeMs: executionTime,
|
|
433
|
+
result: returnResult
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
} catch (error) {
|
|
437
|
+
const executionTime = Date.now() - startTime;
|
|
438
|
+
LogError(`AI Agent run failed:`, undefined, error);
|
|
439
|
+
|
|
440
|
+
// Create error payload
|
|
441
|
+
const errorResult = {
|
|
442
|
+
success: false,
|
|
443
|
+
errorMessage: (error as Error).message || 'Unknown error occurred',
|
|
444
|
+
executionTimeMs: executionTime
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
success: false,
|
|
449
|
+
errorMessage: errorResult.errorMessage,
|
|
450
|
+
executionTimeMs: executionTime,
|
|
451
|
+
result: JSON.stringify(errorResult)
|
|
452
|
+
};
|
|
430
453
|
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// Create sanitized payload for JSON serialization
|
|
434
|
-
const sanitizedResult = this.sanitizeAgentResult(result);
|
|
435
|
-
const returnResult = JSON.stringify(sanitizedResult);
|
|
436
|
-
|
|
437
|
-
// Log completion
|
|
438
|
-
if (result.success) {
|
|
439
|
-
LogStatus(`=== AI AGENT RUN COMPLETED FOR: ${agentEntity.Name} (${executionTime}ms) ===`);
|
|
440
|
-
} else {
|
|
441
|
-
LogError(`AI Agent run failed for ${agentEntity.Name}: ${result.agentRun?.ErrorMessage}`);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
return {
|
|
445
|
-
success: result.success,
|
|
446
|
-
errorMessage: result.agentRun?.ErrorMessage || undefined,
|
|
447
|
-
executionTimeMs: executionTime,
|
|
448
|
-
result: returnResult,
|
|
449
|
-
};
|
|
450
|
-
} catch (error) {
|
|
451
|
-
const executionTime = Date.now() - startTime;
|
|
452
|
-
LogError(`AI Agent run failed:`, undefined, error);
|
|
453
|
-
|
|
454
|
-
// Create error payload
|
|
455
|
-
const errorResult = {
|
|
456
|
-
success: false,
|
|
457
|
-
errorMessage: (error as Error).message || 'Unknown error occurred',
|
|
458
|
-
executionTimeMs: executionTime,
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
return {
|
|
462
|
-
success: false,
|
|
463
|
-
errorMessage: errorResult.errorMessage,
|
|
464
|
-
executionTimeMs: executionTime,
|
|
465
|
-
result: JSON.stringify(errorResult),
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/**
|
|
471
|
-
* Publish final streaming events (partial result and completion)
|
|
472
|
-
*/
|
|
473
|
-
private publishFinalEvents(pubSub: PubSubEngine, sessionId: string, userPayload: UserPayload, result: ExecuteAgentResult) {
|
|
474
|
-
if (result.agentRun) {
|
|
475
|
-
// Get the last step from agent run
|
|
476
|
-
let lastStep = 'Completed';
|
|
477
|
-
if (result.agentRun?.Steps && result.agentRun.Steps.length > 0) {
|
|
478
|
-
// Get the last step from the Steps array
|
|
479
|
-
const lastStepEntity = result.agentRun.Steps[result.agentRun.Steps.length - 1];
|
|
480
|
-
lastStep = lastStepEntity?.StepName || 'Completed';
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
// Publish partial result
|
|
484
|
-
const partialResult: AgentPartialResult = {
|
|
485
|
-
currentStep: lastStep,
|
|
486
|
-
partialOutput: result.payload || undefined,
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
const partialMsg: AgentExecutionStreamMessage = {
|
|
490
|
-
sessionId,
|
|
491
|
-
agentRunId: result.agentRun.ID,
|
|
492
|
-
type: 'partial_result',
|
|
493
|
-
partialResult,
|
|
494
|
-
timestamp: new Date(),
|
|
495
|
-
};
|
|
496
|
-
this.PublishStreamingUpdate(pubSub, partialMsg, userPayload);
|
|
497
454
|
}
|
|
498
455
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
messagesJson,
|
|
537
|
-
sessionId,
|
|
538
|
-
pubSub,
|
|
539
|
-
data,
|
|
540
|
-
payload,
|
|
541
|
-
templateData,
|
|
542
|
-
lastRunId,
|
|
543
|
-
autoPopulateLastRunPayload,
|
|
544
|
-
configurationId,
|
|
545
|
-
conversationDetailId,
|
|
546
|
-
createArtifacts || false,
|
|
547
|
-
createNotification || false,
|
|
548
|
-
sourceArtifactId,
|
|
549
|
-
sourceArtifactVersionId
|
|
550
|
-
);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* System user query for running AI agents with elevated privileges.
|
|
555
|
-
* Requires the @RequireSystemUser decorator to ensure only system users can access.
|
|
556
|
-
*/
|
|
557
|
-
@RequireSystemUser()
|
|
558
|
-
@Query(() => AIAgentRunResult)
|
|
559
|
-
async RunAIAgentSystemUser(
|
|
560
|
-
@Arg('agentId') agentId: string,
|
|
561
|
-
@Ctx() { userPayload, providers }: AppContext,
|
|
562
|
-
@Arg('messages') messagesJson: string,
|
|
563
|
-
@Arg('sessionId') sessionId: string,
|
|
564
|
-
@PubSub() pubSub: PubSubEngine,
|
|
565
|
-
@Arg('data', { nullable: true }) data?: string,
|
|
566
|
-
@Arg('payload', { nullable: true }) payload?: string,
|
|
567
|
-
@Arg('templateData', { nullable: true }) templateData?: string,
|
|
568
|
-
@Arg('lastRunId', { nullable: true }) lastRunId?: string,
|
|
569
|
-
@Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
|
|
570
|
-
@Arg('configurationId', { nullable: true }) configurationId?: string,
|
|
571
|
-
@Arg('conversationDetailId', { nullable: true }) conversationDetailId?: string,
|
|
572
|
-
@Arg('createArtifacts', { nullable: true }) createArtifacts?: boolean,
|
|
573
|
-
@Arg('createNotification', { nullable: true }) createNotification?: boolean,
|
|
574
|
-
@Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
|
|
575
|
-
@Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string
|
|
576
|
-
): Promise<AIAgentRunResult> {
|
|
577
|
-
const p = GetReadWriteProvider(providers);
|
|
578
|
-
return this.executeAIAgent(
|
|
579
|
-
p,
|
|
580
|
-
agentId,
|
|
581
|
-
userPayload,
|
|
582
|
-
messagesJson,
|
|
583
|
-
sessionId,
|
|
584
|
-
pubSub,
|
|
585
|
-
data,
|
|
586
|
-
payload,
|
|
587
|
-
templateData,
|
|
588
|
-
lastRunId,
|
|
589
|
-
autoPopulateLastRunPayload,
|
|
590
|
-
configurationId,
|
|
591
|
-
conversationDetailId,
|
|
592
|
-
createArtifacts || false,
|
|
593
|
-
createNotification || false,
|
|
594
|
-
sourceArtifactId,
|
|
595
|
-
sourceArtifactVersionId
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* Get the maximum version number for an artifact
|
|
601
|
-
* Used when creating new version of an explicitly specified artifact
|
|
602
|
-
*/
|
|
603
|
-
private async getMaxVersionForArtifact(artifactId: string, contextUser: UserInfo): Promise<number> {
|
|
604
|
-
try {
|
|
605
|
-
const rv = new RunView();
|
|
606
|
-
|
|
607
|
-
// Query all versions for this artifact to find max version number
|
|
608
|
-
const result = await rv.RunView<ArtifactVersionEntity>(
|
|
609
|
-
{
|
|
610
|
-
EntityName: 'MJ: Artifact Versions',
|
|
611
|
-
ExtraFilter: `ArtifactID='${artifactId}'`,
|
|
612
|
-
OrderBy: 'VersionNumber DESC',
|
|
613
|
-
MaxRows: 1,
|
|
614
|
-
ResultType: 'entity_object',
|
|
615
|
-
},
|
|
616
|
-
contextUser
|
|
617
|
-
);
|
|
618
|
-
|
|
619
|
-
if (result.Success && result.Results && result.Results.length > 0) {
|
|
620
|
-
return result.Results[0].VersionNumber || 0;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
return 0; // No versions found, will create version 1
|
|
624
|
-
} catch (error) {
|
|
625
|
-
LogError(`Error getting max version for artifact: ${(error as Error).message}`);
|
|
626
|
-
return 0;
|
|
456
|
+
/**
|
|
457
|
+
* Publish final streaming events (partial result and completion)
|
|
458
|
+
*/
|
|
459
|
+
private publishFinalEvents(pubSub: PubSubEngine, sessionId: string, userPayload: UserPayload, result: ExecuteAgentResult) {
|
|
460
|
+
if (result.agentRun) {
|
|
461
|
+
// Get the last step from agent run
|
|
462
|
+
let lastStep = 'Completed';
|
|
463
|
+
if (result.agentRun?.Steps && result.agentRun.Steps.length > 0) {
|
|
464
|
+
// Get the last step from the Steps array
|
|
465
|
+
const lastStepEntity = result.agentRun.Steps[result.agentRun.Steps.length - 1];
|
|
466
|
+
lastStep = lastStepEntity?.StepName || 'Completed';
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Publish partial result
|
|
470
|
+
const partialResult: AgentPartialResult = {
|
|
471
|
+
currentStep: lastStep,
|
|
472
|
+
partialOutput: result.payload || undefined
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const partialMsg: AgentExecutionStreamMessage = {
|
|
476
|
+
sessionId,
|
|
477
|
+
agentRunId: result.agentRun.ID,
|
|
478
|
+
type: 'partial_result',
|
|
479
|
+
partialResult,
|
|
480
|
+
timestamp: new Date()
|
|
481
|
+
};
|
|
482
|
+
this.PublishStreamingUpdate(pubSub, partialMsg, userPayload);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Publish completion
|
|
486
|
+
const completeMsg: AgentExecutionStreamMessage = {
|
|
487
|
+
sessionId,
|
|
488
|
+
agentRunId: result.agentRun?.ID || 'unknown',
|
|
489
|
+
type: 'complete',
|
|
490
|
+
timestamp: new Date()
|
|
491
|
+
};
|
|
492
|
+
this.PublishStreamingUpdate(pubSub, completeMsg, userPayload);
|
|
627
493
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
{
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
} catch (error) {
|
|
672
|
-
LogError(`Error finding previous artifact: ${(error as Error).message}`);
|
|
673
|
-
return null;
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Public mutation for regular users to run AI agents with authentication.
|
|
497
|
+
*/
|
|
498
|
+
@Mutation(() => AIAgentRunResult)
|
|
499
|
+
async RunAIAgent(
|
|
500
|
+
@Arg('agentId') agentId: string,
|
|
501
|
+
@Ctx() { userPayload, providers }: AppContext,
|
|
502
|
+
@Arg('messages') messagesJson: string,
|
|
503
|
+
@Arg('sessionId') sessionId: string,
|
|
504
|
+
@PubSub() pubSub: PubSubEngine,
|
|
505
|
+
@Arg('data', { nullable: true }) data?: string,
|
|
506
|
+
@Arg('payload', { nullable: true }) payload?: string,
|
|
507
|
+
@Arg('templateData', { nullable: true }) templateData?: string,
|
|
508
|
+
@Arg('lastRunId', { nullable: true }) lastRunId?: string,
|
|
509
|
+
@Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
|
|
510
|
+
@Arg('configurationId', { nullable: true }) configurationId?: string,
|
|
511
|
+
@Arg('conversationDetailId', { nullable: true }) conversationDetailId?: string,
|
|
512
|
+
@Arg('createArtifacts', { nullable: true }) createArtifacts?: boolean,
|
|
513
|
+
@Arg('createNotification', { nullable: true }) createNotification?: boolean,
|
|
514
|
+
@Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
|
|
515
|
+
@Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string
|
|
516
|
+
): Promise<AIAgentRunResult> {
|
|
517
|
+
const p = GetReadWriteProvider(providers);
|
|
518
|
+
return this.executeAIAgent(
|
|
519
|
+
p,
|
|
520
|
+
agentId,
|
|
521
|
+
userPayload,
|
|
522
|
+
messagesJson,
|
|
523
|
+
sessionId,
|
|
524
|
+
pubSub,
|
|
525
|
+
data,
|
|
526
|
+
payload,
|
|
527
|
+
templateData,
|
|
528
|
+
lastRunId,
|
|
529
|
+
autoPopulateLastRunPayload,
|
|
530
|
+
configurationId,
|
|
531
|
+
conversationDetailId,
|
|
532
|
+
createArtifacts || false,
|
|
533
|
+
createNotification || false,
|
|
534
|
+
sourceArtifactId,
|
|
535
|
+
sourceArtifactVersionId
|
|
536
|
+
);
|
|
674
537
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* System user query for running AI agents with elevated privileges.
|
|
541
|
+
* Requires the @RequireSystemUser decorator to ensure only system users can access.
|
|
542
|
+
*/
|
|
543
|
+
@RequireSystemUser()
|
|
544
|
+
@Query(() => AIAgentRunResult)
|
|
545
|
+
async RunAIAgentSystemUser(
|
|
546
|
+
@Arg('agentId') agentId: string,
|
|
547
|
+
@Ctx() { userPayload, providers }: AppContext,
|
|
548
|
+
@Arg('messages') messagesJson: string,
|
|
549
|
+
@Arg('sessionId') sessionId: string,
|
|
550
|
+
@PubSub() pubSub: PubSubEngine,
|
|
551
|
+
@Arg('data', { nullable: true }) data?: string,
|
|
552
|
+
@Arg('payload', { nullable: true }) payload?: string,
|
|
553
|
+
@Arg('templateData', { nullable: true }) templateData?: string,
|
|
554
|
+
@Arg('lastRunId', { nullable: true }) lastRunId?: string,
|
|
555
|
+
@Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
|
|
556
|
+
@Arg('configurationId', { nullable: true }) configurationId?: string,
|
|
557
|
+
@Arg('conversationDetailId', { nullable: true }) conversationDetailId?: string,
|
|
558
|
+
@Arg('createArtifacts', { nullable: true }) createArtifacts?: boolean,
|
|
559
|
+
@Arg('createNotification', { nullable: true }) createNotification?: boolean,
|
|
560
|
+
@Arg('sourceArtifactId', { nullable: true }) sourceArtifactId?: string,
|
|
561
|
+
@Arg('sourceArtifactVersionId', { nullable: true }) sourceArtifactVersionId?: string
|
|
562
|
+
): Promise<AIAgentRunResult> {
|
|
563
|
+
const p = GetReadWriteProvider(providers);
|
|
564
|
+
return this.executeAIAgent(
|
|
565
|
+
p,
|
|
566
|
+
agentId,
|
|
567
|
+
userPayload,
|
|
568
|
+
messagesJson,
|
|
569
|
+
sessionId,
|
|
570
|
+
pubSub,
|
|
571
|
+
data,
|
|
572
|
+
payload,
|
|
573
|
+
templateData,
|
|
574
|
+
lastRunId,
|
|
575
|
+
autoPopulateLastRunPayload,
|
|
576
|
+
configurationId,
|
|
577
|
+
conversationDetailId,
|
|
578
|
+
createArtifacts || false,
|
|
579
|
+
createNotification || false,
|
|
580
|
+
sourceArtifactId,
|
|
581
|
+
sourceArtifactVersionId
|
|
582
|
+
);
|
|
692
583
|
}
|
|
693
584
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
585
|
+
/**
|
|
586
|
+
* Get the maximum version number for an artifact
|
|
587
|
+
* Used when creating new version of an explicitly specified artifact
|
|
588
|
+
*/
|
|
589
|
+
private async getMaxVersionForArtifact(
|
|
590
|
+
artifactId: string,
|
|
591
|
+
contextUser: UserInfo
|
|
592
|
+
): Promise<number> {
|
|
593
|
+
try {
|
|
594
|
+
const rv = new RunView();
|
|
595
|
+
|
|
596
|
+
// Query all versions for this artifact to find max version number
|
|
597
|
+
const result = await rv.RunView<ArtifactVersionEntity>({
|
|
598
|
+
EntityName: 'MJ: Artifact Versions',
|
|
599
|
+
ExtraFilter: `ArtifactID='${artifactId}'`,
|
|
600
|
+
OrderBy: 'VersionNumber DESC',
|
|
601
|
+
MaxRows: 1,
|
|
602
|
+
ResultType: 'entity_object'
|
|
603
|
+
}, contextUser);
|
|
604
|
+
|
|
605
|
+
if (result.Success && result.Results && result.Results.length > 0) {
|
|
606
|
+
return result.Results[0].VersionNumber || 0;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return 0; // No versions found, will create version 1
|
|
610
|
+
} catch (error) {
|
|
611
|
+
LogError(`Error getting max version for artifact: ${(error as Error).message}`);
|
|
612
|
+
return 0;
|
|
613
|
+
}
|
|
697
614
|
}
|
|
698
615
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
616
|
+
/**
|
|
617
|
+
* Find the most recent artifact for a conversation detail to determine versioning
|
|
618
|
+
* Returns artifact info if exists, null if this is first artifact
|
|
619
|
+
*/
|
|
620
|
+
private async findPreviousArtifactForMessage(
|
|
621
|
+
conversationDetailId: string,
|
|
622
|
+
contextUser: UserInfo
|
|
623
|
+
): Promise<{ artifactId: string; versionNumber: number } | null> {
|
|
624
|
+
try {
|
|
625
|
+
const rv = new RunView();
|
|
626
|
+
|
|
627
|
+
// Query junction table to find artifacts for this message
|
|
628
|
+
const result = await rv.RunView<ConversationDetailArtifactEntity>({
|
|
629
|
+
EntityName: 'MJ: Conversation Detail Artifacts',
|
|
630
|
+
ExtraFilter: `ConversationDetailID='${conversationDetailId}' AND Direction='Output'`,
|
|
631
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
632
|
+
MaxRows: 1,
|
|
633
|
+
ResultType: 'entity_object'
|
|
634
|
+
}, contextUser);
|
|
635
|
+
|
|
636
|
+
if (!result.Success || !result.Results || result.Results.length === 0) {
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const junction = result.Results[0];
|
|
703
641
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
642
|
+
// Load the artifact version to get version number and artifact ID
|
|
643
|
+
const md = new Metadata();
|
|
644
|
+
const version = await md.GetEntityObject<ArtifactVersionEntity>(
|
|
645
|
+
'MJ: Artifact Versions',
|
|
646
|
+
contextUser
|
|
647
|
+
);
|
|
648
|
+
|
|
649
|
+
if (!(await version.Load(junction.ArtifactVersionID))) {
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
return {
|
|
654
|
+
artifactId: version.ArtifactID,
|
|
655
|
+
versionNumber: version.VersionNumber
|
|
656
|
+
};
|
|
657
|
+
} catch (error) {
|
|
658
|
+
LogError(`Error finding previous artifact: ${(error as Error).message}`);
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
707
661
|
}
|
|
708
662
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
}
|
|
725
|
-
// Priority 2: Try to find previous artifact for this message (fallback)
|
|
726
|
-
else {
|
|
727
|
-
const previousArtifact = await this.findPreviousArtifactForMessage(conversationDetailId, contextUser);
|
|
728
|
-
|
|
729
|
-
if (previousArtifact) {
|
|
730
|
-
// Create new version of existing artifact
|
|
731
|
-
artifactId = previousArtifact.artifactId;
|
|
732
|
-
newVersionNumber = previousArtifact.versionNumber + 1;
|
|
733
|
-
LogStatus(`Creating version ${newVersionNumber} of existing artifact ${artifactId}`);
|
|
734
|
-
} else {
|
|
735
|
-
// Create new artifact header
|
|
736
|
-
const artifact = await md.GetEntityObject<ArtifactEntity>('MJ: Artifacts', contextUser);
|
|
737
|
-
|
|
738
|
-
// Get agent info for naming and visibility control
|
|
739
|
-
await AIEngine.Instance.Config(false, contextUser);
|
|
740
|
-
const agent = AIEngine.Instance.Agents.find((a) => a.ID === agentRun.AgentID);
|
|
741
|
-
const agentName = agent?.Name || 'Agent';
|
|
742
|
-
|
|
743
|
-
artifact.Name = `${agentName} Payload - ${new Date().toLocaleString()}`;
|
|
744
|
-
artifact.Description = `Payload returned by ${agentName}`;
|
|
745
|
-
|
|
746
|
-
// Use agent's DefaultArtifactTypeID if available, otherwise JSON
|
|
747
|
-
const defaultArtifactTypeId = (agent as any)?.DefaultArtifactTypeID;
|
|
748
|
-
artifact.TypeID = defaultArtifactTypeId || JSON_ARTIFACT_TYPE_ID;
|
|
749
|
-
|
|
750
|
-
artifact.UserID = contextUser.ID;
|
|
751
|
-
artifact.EnvironmentID = (contextUser as any).EnvironmentID || 'F51358F3-9447-4176-B313-BF8025FD8D09';
|
|
752
|
-
|
|
753
|
-
// Set visibility based on agent's ArtifactCreationMode
|
|
754
|
-
// Will compile after CodeGen adds the new fields
|
|
755
|
-
const creationMode = agent.ArtifactCreationMode;
|
|
756
|
-
if (creationMode === 'System Only') {
|
|
757
|
-
artifact.Visibility = 'System Only';
|
|
758
|
-
LogStatus(`Artifact marked as "System Only" per agent configuration`);
|
|
759
|
-
} else {
|
|
760
|
-
artifact.Visibility = 'Always';
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (!(await artifact.Save())) {
|
|
764
|
-
throw new Error('Failed to save artifact');
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
artifactId = artifact.ID;
|
|
768
|
-
newVersionNumber = 1;
|
|
769
|
-
isNewArtifact = true;
|
|
770
|
-
LogStatus(`Created new artifact: ${artifact.Name} (${artifactId})`);
|
|
663
|
+
/**
|
|
664
|
+
* Process agent completion to create artifacts from payload
|
|
665
|
+
* Called after agent run completes successfully
|
|
666
|
+
*/
|
|
667
|
+
private async processAgentCompletionForArtifacts(
|
|
668
|
+
agentRun: AIAgentRunEntityExtended,
|
|
669
|
+
payload: any,
|
|
670
|
+
contextUser: UserInfo,
|
|
671
|
+
conversationDetailId?: string,
|
|
672
|
+
sourceArtifactId?: string
|
|
673
|
+
): Promise<{ artifactId?: string; versionId?: string; versionNumber?: number }> {
|
|
674
|
+
// Validate inputs
|
|
675
|
+
if (!payload || Object.keys(payload).length === 0) {
|
|
676
|
+
LogStatus('No payload to create artifact from');
|
|
677
|
+
return {};
|
|
771
678
|
}
|
|
772
|
-
}
|
|
773
679
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
version.Content = JSON.stringify(payload, null, 2);
|
|
779
|
-
version.UserID = contextUser.ID;
|
|
680
|
+
if (!conversationDetailId) {
|
|
681
|
+
LogStatus('Skipping artifact creation - no conversationDetailId provided');
|
|
682
|
+
return {};
|
|
683
|
+
}
|
|
780
684
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
685
|
+
// Check agent's ArtifactCreationMode
|
|
686
|
+
await AIEngine.Instance.Config(false, contextUser);
|
|
687
|
+
const agent = AIEngine.Instance.Agents.find(a => a.ID === agentRun.AgentID);
|
|
688
|
+
const creationMode = agent?.ArtifactCreationMode;
|
|
784
689
|
|
|
785
|
-
|
|
690
|
+
if (creationMode === 'Never') {
|
|
691
|
+
LogStatus(`Skipping artifact creation - agent "${agent?.Name}" has ArtifactCreationMode='Never'`);
|
|
692
|
+
return {};
|
|
693
|
+
}
|
|
786
694
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
695
|
+
try {
|
|
696
|
+
const md = new Metadata();
|
|
697
|
+
const JSON_ARTIFACT_TYPE_ID = 'ae674c7e-ea0d-49ea-89e4-0649f5eb20d4';
|
|
698
|
+
|
|
699
|
+
// 1. Determine if creating new artifact or new version
|
|
700
|
+
let artifactId: string;
|
|
701
|
+
let newVersionNumber: number;
|
|
702
|
+
let isNewArtifact = false;
|
|
703
|
+
|
|
704
|
+
// Priority 1: Use explicit source artifact if provided (agent continuity/refinement)
|
|
705
|
+
if (sourceArtifactId) {
|
|
706
|
+
const maxVersion = await this.getMaxVersionForArtifact(sourceArtifactId, contextUser);
|
|
707
|
+
artifactId = sourceArtifactId;
|
|
708
|
+
newVersionNumber = maxVersion + 1;
|
|
709
|
+
LogStatus(`Creating version ${newVersionNumber} of source artifact ${artifactId} (explicit source)`);
|
|
710
|
+
}
|
|
711
|
+
// Priority 2: Try to find previous artifact for this message (fallback)
|
|
712
|
+
else {
|
|
713
|
+
const previousArtifact = await this.findPreviousArtifactForMessage(
|
|
714
|
+
conversationDetailId,
|
|
715
|
+
contextUser
|
|
716
|
+
);
|
|
717
|
+
|
|
718
|
+
if (previousArtifact) {
|
|
719
|
+
// Create new version of existing artifact
|
|
720
|
+
artifactId = previousArtifact.artifactId;
|
|
721
|
+
newVersionNumber = previousArtifact.versionNumber + 1;
|
|
722
|
+
LogStatus(`Creating version ${newVersionNumber} of existing artifact ${artifactId}`);
|
|
723
|
+
} else {
|
|
724
|
+
// Create new artifact header
|
|
725
|
+
const artifact = await md.GetEntityObject<ArtifactEntity>(
|
|
726
|
+
'MJ: Artifacts',
|
|
727
|
+
contextUser
|
|
728
|
+
);
|
|
729
|
+
|
|
730
|
+
// Get agent info for naming and visibility control
|
|
731
|
+
await AIEngine.Instance.Config(false, contextUser);
|
|
732
|
+
const agent = AIEngine.Instance.Agents.find(a => a.ID === agentRun.AgentID);
|
|
733
|
+
const agentName = agent?.Name || 'Agent';
|
|
734
|
+
|
|
735
|
+
artifact.Name = `${agentName} Payload - ${new Date().toLocaleString()}`;
|
|
736
|
+
artifact.Description = `Payload returned by ${agentName}`;
|
|
737
|
+
|
|
738
|
+
// Use agent's DefaultArtifactTypeID if available, otherwise JSON
|
|
739
|
+
const defaultArtifactTypeId = (agent as any)?.DefaultArtifactTypeID;
|
|
740
|
+
artifact.TypeID = defaultArtifactTypeId || JSON_ARTIFACT_TYPE_ID;
|
|
741
|
+
|
|
742
|
+
artifact.UserID = contextUser.ID;
|
|
743
|
+
artifact.EnvironmentID = (contextUser as any).EnvironmentID ||
|
|
744
|
+
'F51358F3-9447-4176-B313-BF8025FD8D09';
|
|
745
|
+
|
|
746
|
+
// Set visibility based on agent's ArtifactCreationMode
|
|
747
|
+
// Will compile after CodeGen adds the new fields
|
|
748
|
+
const creationMode = agent.ArtifactCreationMode;
|
|
749
|
+
if (creationMode === 'System Only') {
|
|
750
|
+
artifact.Visibility = 'System Only';
|
|
751
|
+
LogStatus(`Artifact marked as "System Only" per agent configuration`);
|
|
752
|
+
} else {
|
|
753
|
+
artifact.Visibility = 'Always';
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
if (!(await artifact.Save())) {
|
|
757
|
+
throw new Error('Failed to save artifact');
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
artifactId = artifact.ID;
|
|
761
|
+
newVersionNumber = 1;
|
|
762
|
+
isNewArtifact = true;
|
|
763
|
+
LogStatus(`Created new artifact: ${artifact.Name} (${artifactId})`);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
792
766
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
767
|
+
// 2. Create artifact version with content
|
|
768
|
+
const version = await md.GetEntityObject<ArtifactVersionEntity>(
|
|
769
|
+
'MJ: Artifact Versions',
|
|
770
|
+
contextUser
|
|
771
|
+
);
|
|
772
|
+
version.ArtifactID = artifactId;
|
|
773
|
+
version.VersionNumber = newVersionNumber;
|
|
774
|
+
version.Content = JSON.stringify(payload, null, 2);
|
|
775
|
+
version.UserID = contextUser.ID;
|
|
776
|
+
|
|
777
|
+
if (!(await version.Save())) {
|
|
778
|
+
throw new Error('Failed to save artifact version');
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
LogStatus(`Created artifact version ${newVersionNumber} (${version.ID})`);
|
|
782
|
+
|
|
783
|
+
// If this is the first version of a new artifact, check for extracted Name attribute and update artifact
|
|
784
|
+
if (isNewArtifact && newVersionNumber === 1) {
|
|
785
|
+
const nameAttr = (version as any).Attributes?.find((attr: any) =>
|
|
786
|
+
attr.StandardProperty === 'name' || attr.Name?.toLowerCase() === 'name'
|
|
787
|
+
);
|
|
788
|
+
|
|
789
|
+
// Check for valid name value (not null, not empty, not string "null")
|
|
790
|
+
let extractedName = nameAttr?.Value?.trim();
|
|
791
|
+
if (extractedName && extractedName.toLowerCase() !== 'null') {
|
|
792
|
+
// Strip surrounding quotes (double or single) from start and end
|
|
793
|
+
extractedName = extractedName.replace(/^["']|["']$/g, '');
|
|
794
|
+
|
|
795
|
+
// Load artifact to update with extracted name
|
|
796
|
+
const artifact = await md.GetEntityObject<ArtifactEntity>(
|
|
797
|
+
'MJ: Artifacts',
|
|
798
|
+
contextUser
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
if (!(await artifact.Load(artifactId))) {
|
|
802
|
+
LogError('Failed to reload artifact for name update');
|
|
803
|
+
} else {
|
|
804
|
+
artifact.Name = extractedName;
|
|
805
|
+
if (await artifact.Save()) {
|
|
806
|
+
LogStatus(`✨ Updated artifact name to: ${artifact.Name}`);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
808
810
|
}
|
|
809
|
-
|
|
811
|
+
|
|
812
|
+
// 3. Create junction record linking artifact to conversation detail
|
|
813
|
+
const junction = await md.GetEntityObject<ConversationDetailArtifactEntity>(
|
|
814
|
+
'MJ: Conversation Detail Artifacts',
|
|
815
|
+
contextUser
|
|
816
|
+
);
|
|
817
|
+
junction.ConversationDetailID = conversationDetailId;
|
|
818
|
+
junction.ArtifactVersionID = version.ID;
|
|
819
|
+
junction.Direction = 'Output';
|
|
820
|
+
|
|
821
|
+
if (!(await junction.Save())) {
|
|
822
|
+
throw new Error('Failed to create artifact-message association');
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
LogStatus(`Linked artifact to conversation detail ${conversationDetailId}`);
|
|
826
|
+
|
|
827
|
+
return {
|
|
828
|
+
artifactId,
|
|
829
|
+
versionId: version.ID,
|
|
830
|
+
versionNumber: newVersionNumber
|
|
831
|
+
};
|
|
832
|
+
} catch (error) {
|
|
833
|
+
LogError(`Failed to process agent completion for artifacts: ${(error as Error).message}`);
|
|
834
|
+
return {};
|
|
810
835
|
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
// 3. Create junction record linking artifact to conversation detail
|
|
814
|
-
const junction = await md.GetEntityObject<ConversationDetailArtifactEntity>('MJ: Conversation Detail Artifacts', contextUser);
|
|
815
|
-
junction.ConversationDetailID = conversationDetailId;
|
|
816
|
-
junction.ArtifactVersionID = version.ID;
|
|
817
|
-
junction.Direction = 'Output';
|
|
818
|
-
|
|
819
|
-
if (!(await junction.Save())) {
|
|
820
|
-
throw new Error('Failed to create artifact-message association');
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
LogStatus(`Linked artifact to conversation detail ${conversationDetailId}`);
|
|
824
|
-
|
|
825
|
-
return {
|
|
826
|
-
artifactId,
|
|
827
|
-
versionId: version.ID,
|
|
828
|
-
versionNumber: newVersionNumber,
|
|
829
|
-
};
|
|
830
|
-
} catch (error) {
|
|
831
|
-
LogError(`Failed to process agent completion for artifacts: ${(error as Error).message}`);
|
|
832
|
-
return {};
|
|
833
836
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Create a user notification for agent completion with artifact
|
|
840
|
+
* Notification includes navigation link back to the conversation
|
|
841
|
+
*/
|
|
842
|
+
private async createCompletionNotification(
|
|
843
|
+
agentRun: AIAgentRunEntityExtended,
|
|
844
|
+
artifactInfo: { artifactId: string; versionId: string; versionNumber: number },
|
|
845
|
+
conversationDetailId: string,
|
|
846
|
+
contextUser: UserInfo,
|
|
847
|
+
pubSub: PubSubEngine,
|
|
848
|
+
userPayload: UserPayload
|
|
849
|
+
): Promise<void> {
|
|
850
|
+
try {
|
|
851
|
+
const md = new Metadata();
|
|
852
|
+
|
|
853
|
+
// Get agent info for notification message
|
|
854
|
+
await AIEngine.Instance.Config(false, contextUser);
|
|
855
|
+
const agent = AIEngine.Instance.Agents.find(a => a.ID === agentRun.AgentID);
|
|
856
|
+
const agentName = agent?.Name || 'Agent';
|
|
857
|
+
|
|
858
|
+
// Load conversation detail to get conversation info
|
|
859
|
+
const detail = await md.GetEntityObject<ConversationDetailEntity>(
|
|
860
|
+
'Conversation Details',
|
|
861
|
+
contextUser
|
|
862
|
+
);
|
|
863
|
+
if (!(await detail.Load(conversationDetailId))) {
|
|
864
|
+
throw new Error(`Failed to load conversation detail ${conversationDetailId}`);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// Create notification entity
|
|
868
|
+
const notification = await md.GetEntityObject<UserNotificationEntity>(
|
|
869
|
+
'User Notifications',
|
|
870
|
+
contextUser
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
notification.UserID = contextUser.ID;
|
|
874
|
+
notification.Title = `${agentName} completed your request`;
|
|
875
|
+
|
|
876
|
+
// Craft message based on versioning
|
|
877
|
+
if (artifactInfo.versionNumber > 1) {
|
|
878
|
+
notification.Message = `${agentName} has finished processing and created version ${artifactInfo.versionNumber}`;
|
|
879
|
+
} else {
|
|
880
|
+
notification.Message = `${agentName} has finished processing and created a new artifact`;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// Store navigation configuration as JSON
|
|
884
|
+
// Client will parse this to navigate to the conversation with artifact visible
|
|
885
|
+
notification.ResourceConfiguration = JSON.stringify({
|
|
886
|
+
type: 'conversation',
|
|
887
|
+
conversationId: detail.ConversationID,
|
|
888
|
+
messageId: conversationDetailId,
|
|
889
|
+
artifactId: artifactInfo.artifactId,
|
|
890
|
+
versionNumber: artifactInfo.versionNumber
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
notification.Unread = true; // Default unread
|
|
894
|
+
// ResourceTypeID and ResourceRecordID left null - using custom navigation
|
|
895
|
+
|
|
896
|
+
if (!(await notification.Save())) {
|
|
897
|
+
throw new Error('Failed to save notification');
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
LogStatus(`📬 Created notification ${notification.ID} for user ${contextUser.ID}`);
|
|
901
|
+
|
|
902
|
+
// Publish real-time notification event so client updates immediately
|
|
903
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
904
|
+
userPayload: JSON.stringify(userPayload),
|
|
905
|
+
message: JSON.stringify({
|
|
906
|
+
type: 'notification',
|
|
907
|
+
notificationId: notification.ID,
|
|
908
|
+
action: 'create',
|
|
909
|
+
title: notification.Title,
|
|
910
|
+
message: notification.Message
|
|
911
|
+
})
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
LogStatus(`📡 Published notification event to client`);
|
|
915
|
+
|
|
916
|
+
} catch (error) {
|
|
917
|
+
LogError(`Failed to create completion notification: ${(error as Error).message}`);
|
|
918
|
+
// Don't throw - notification failure shouldn't fail the agent run
|
|
919
|
+
}
|
|
910
920
|
}
|
|
911
|
-
|
|
912
|
-
}
|
|
921
|
+
|
|
922
|
+
}
|