@memberjunction/server 2.111.0 → 2.112.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/dist/agents/skip-agent.d.ts +4 -4
- package/dist/agents/skip-agent.d.ts.map +1 -1
- package/dist/agents/skip-agent.js +808 -951
- 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 +53 -43
- 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 +1 -3
- 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 +3 -2
- 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 +3 -6
- 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 +22 -10
- 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 +9 -7
- 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 +648 -648
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +2986 -1133
- 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 +15 -10
- 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 +18 -9
- 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 +28 -30
- 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 +60 -50
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +36 -38
- 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 +43 -40
- 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 +8 -6
- 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 +27 -28
- 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 +15 -14
- 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 +48 -44
- 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 +14 -16
- package/dist/rest/EntityCRUDHandler.js.map +1 -1
- package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
- package/dist/rest/RESTEndpointHandler.js +23 -25
- 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 +17 -21
- 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 +4 -6
- 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 +0 -1
- 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 +36 -37
- package/src/agents/skip-agent.ts +1067 -1200
- package/src/agents/skip-sdk.ts +877 -851
- package/src/apolloServer/index.ts +2 -2
- package/src/auth/AuthProviderFactory.ts +8 -14
- package/src/auth/BaseAuthProvider.ts +5 -4
- package/src/auth/IAuthProvider.ts +2 -2
- package/src/auth/exampleNewUserSubClass.ts +9 -2
- package/src/auth/index.ts +31 -26
- package/src/auth/initializeProviders.ts +3 -3
- package/src/auth/newUsers.ts +166 -134
- package/src/auth/providers/Auth0Provider.ts +5 -5
- package/src/auth/providers/CognitoProvider.ts +7 -10
- package/src/auth/providers/GoogleProvider.ts +4 -5
- package/src/auth/providers/MSALProvider.ts +5 -5
- package/src/auth/providers/OktaProvider.ts +6 -7
- package/src/config.ts +63 -54
- package/src/context.ts +42 -30
- package/src/entitySubclasses/entityPermissions.server.ts +3 -3
- package/src/generated/generated.ts +48130 -39930
- package/src/generic/KeyInputOutputTypes.ts +3 -6
- package/src/generic/ResolverBase.ts +119 -78
- package/src/generic/RunViewResolver.ts +27 -23
- package/src/index.ts +66 -42
- package/src/resolvers/ActionResolver.ts +46 -57
- package/src/resolvers/AskSkipResolver.ts +607 -533
- package/src/resolvers/ComponentRegistryResolver.ts +547 -562
- package/src/resolvers/CreateQueryResolver.ts +683 -655
- package/src/resolvers/DatasetResolver.ts +5 -6
- package/src/resolvers/EntityCommunicationsResolver.ts +1 -1
- package/src/resolvers/EntityRecordNameResolver.ts +9 -5
- package/src/resolvers/EntityResolver.ts +9 -7
- package/src/resolvers/FileCategoryResolver.ts +2 -2
- package/src/resolvers/FileResolver.ts +4 -4
- package/src/resolvers/GetDataContextDataResolver.ts +106 -118
- package/src/resolvers/GetDataResolver.ts +194 -205
- package/src/resolvers/MergeRecordsResolver.ts +5 -5
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +1 -1
- package/src/resolvers/QueryResolver.ts +95 -78
- package/src/resolvers/ReportResolver.ts +2 -2
- package/src/resolvers/RunAIAgentResolver.ts +818 -828
- package/src/resolvers/RunAIPromptResolver.ts +693 -709
- package/src/resolvers/RunTemplateResolver.ts +105 -103
- package/src/resolvers/SqlLoggingConfigResolver.ts +69 -72
- package/src/resolvers/SyncDataResolver.ts +386 -352
- package/src/resolvers/SyncRolesUsersResolver.ts +387 -350
- package/src/resolvers/TaskResolver.ts +110 -115
- package/src/resolvers/TransactionGroupResolver.ts +143 -138
- package/src/resolvers/UserFavoriteResolver.ts +17 -8
- package/src/resolvers/UserViewResolver.ts +17 -12
- package/src/rest/EntityCRUDHandler.ts +291 -268
- package/src/rest/RESTEndpointHandler.ts +782 -776
- package/src/rest/ViewOperationsHandler.ts +191 -195
- package/src/scheduler/LearningCycleScheduler.ts +8 -52
- package/src/services/ScheduledJobsService.ts +129 -132
- package/src/services/TaskOrchestrator.ts +792 -776
- package/src/types.ts +15 -9
- package/src/util.ts +112 -109
package/src/agents/skip-sdk.ts
CHANGED
|
@@ -7,26 +7,35 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
10
|
+
SkipAPIRequest,
|
|
11
|
+
SkipAPIResponse,
|
|
12
|
+
SkipMessage,
|
|
13
|
+
SkipAPIAnalysisCompleteResponse,
|
|
14
|
+
SkipAPIClarifyingQuestionResponse,
|
|
15
|
+
SkipRequestPhase,
|
|
16
|
+
SkipAPIRequestAPIKey,
|
|
17
|
+
SkipQueryInfo,
|
|
18
|
+
SkipEntityInfo,
|
|
19
|
+
SkipEntityFieldInfo,
|
|
20
|
+
SkipEntityFieldValueInfo,
|
|
21
|
+
SkipEntityRelationshipInfo,
|
|
22
|
+
SkipAPIAgentNote,
|
|
23
|
+
SkipAPIAgentNoteType,
|
|
24
|
+
SkipAPIArtifact,
|
|
25
|
+
SkipAPIArtifactVersion,
|
|
26
|
+
SkipAPIArtifactType,
|
|
27
27
|
} from '@memberjunction/skip-types';
|
|
28
28
|
import { DataContext } from '@memberjunction/data-context';
|
|
29
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
UserInfo,
|
|
31
|
+
LogStatus,
|
|
32
|
+
LogError,
|
|
33
|
+
Metadata,
|
|
34
|
+
RunQuery,
|
|
35
|
+
EntityInfo,
|
|
36
|
+
EntityFieldInfo,
|
|
37
|
+
EntityRelationshipInfo,
|
|
38
|
+
} from '@memberjunction/global';
|
|
30
39
|
import { sendPostRequest } from '../util.js';
|
|
31
40
|
import { configInfo, baseUrl, publicUrl, graphqlPort, graphqlRootPath, apiKey as callbackAPIKey } from '../config.js';
|
|
32
41
|
import { GetAIAPIKey } from '@memberjunction/ai';
|
|
@@ -41,125 +50,125 @@ import { take } from 'rxjs/operators';
|
|
|
41
50
|
* Configuration options for Skip SDK
|
|
42
51
|
*/
|
|
43
52
|
export interface SkipSDKConfig {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Skip API base URL (e.g., 'https://skip.memberjunction.com')
|
|
55
|
+
*/
|
|
56
|
+
apiUrl?: string;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Skip API key for authentication
|
|
60
|
+
*/
|
|
61
|
+
apiKey?: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Organization ID
|
|
65
|
+
*/
|
|
66
|
+
organizationId?: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Optional organization context information
|
|
70
|
+
*/
|
|
71
|
+
organizationInfo?: string;
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
/**
|
|
66
75
|
* Options for making a Skip API call
|
|
67
76
|
*/
|
|
68
77
|
export interface SkipCallOptions {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Conversation messages (user/assistant)
|
|
80
|
+
*/
|
|
81
|
+
messages: SkipMessage[];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Conversation ID for tracking
|
|
85
|
+
*/
|
|
86
|
+
conversationId: string;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Data context to provide to Skip
|
|
90
|
+
*/
|
|
91
|
+
dataContext?: DataContext;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Request phase (initial_request, clarify_question_response, etc.)
|
|
95
|
+
*/
|
|
96
|
+
requestPhase?: SkipRequestPhase;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Context user for permissions and metadata
|
|
100
|
+
*/
|
|
101
|
+
contextUser: UserInfo;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Database connection for metadata queries
|
|
105
|
+
*/
|
|
106
|
+
dataSource: mssql.ConnectionPool;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Include entity metadata in request
|
|
110
|
+
*/
|
|
111
|
+
includeEntities?: boolean;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Include saved queries in request
|
|
115
|
+
*/
|
|
116
|
+
includeQueries?: boolean;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Include agent notes in request
|
|
120
|
+
*/
|
|
121
|
+
includeNotes?: boolean;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Include agent requests in request
|
|
125
|
+
*/
|
|
126
|
+
includeRequests?: boolean;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Force refresh of entity metadata cache
|
|
130
|
+
*/
|
|
131
|
+
forceEntityRefresh?: boolean;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Include callback API key and access token for Skip to call back to MJ
|
|
135
|
+
*/
|
|
136
|
+
includeCallbackAuth?: boolean;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Callback for streaming status updates during execution
|
|
140
|
+
*/
|
|
141
|
+
onStatusUpdate?: (message: string, responsePhase?: string) => void;
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
/**
|
|
136
145
|
* Result from a Skip API call
|
|
137
146
|
*/
|
|
138
147
|
export interface SkipCallResult {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Whether the call was successful
|
|
150
|
+
*/
|
|
151
|
+
success: boolean;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The final Skip API response
|
|
155
|
+
*/
|
|
156
|
+
response?: SkipAPIResponse;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Response phase (analysis_complete, clarifying_question, status_update)
|
|
160
|
+
*/
|
|
161
|
+
responsePhase?: string;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Error message if failed
|
|
165
|
+
*/
|
|
166
|
+
error?: string;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* All streaming responses received (including intermediate status updates)
|
|
170
|
+
*/
|
|
171
|
+
allResponses?: any[];
|
|
163
172
|
}
|
|
164
173
|
|
|
165
174
|
/**
|
|
@@ -167,760 +176,777 @@ export interface SkipCallResult {
|
|
|
167
176
|
* Provides a clean interface for calling the Skip SaaS API
|
|
168
177
|
*/
|
|
169
178
|
export class SkipSDK {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
// The last response is the final one
|
|
215
|
-
if (responses && responses.length > 0) {
|
|
216
|
-
const finalResponse = responses[responses.length - 1].value as SkipAPIResponse;
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
success: true,
|
|
220
|
-
response: finalResponse,
|
|
221
|
-
responsePhase: finalResponse.responsePhase,
|
|
222
|
-
allResponses: responses
|
|
223
|
-
};
|
|
224
|
-
} else {
|
|
225
|
-
return {
|
|
226
|
-
success: false,
|
|
227
|
-
error: 'No response received from Skip API'
|
|
228
|
-
};
|
|
179
|
+
private config: SkipSDKConfig;
|
|
180
|
+
|
|
181
|
+
// Static cache for Skip entities (shared across all instances)
|
|
182
|
+
private static __skipEntitiesCache$: BehaviorSubject<Promise<SkipEntityInfo[]> | null> = new BehaviorSubject<Promise<
|
|
183
|
+
SkipEntityInfo[]
|
|
184
|
+
> | null>(null);
|
|
185
|
+
private static __lastRefreshTime: number = 0;
|
|
186
|
+
|
|
187
|
+
constructor(config?: SkipSDKConfig) {
|
|
188
|
+
// Use provided config or fall back to MJ server config
|
|
189
|
+
this.config = {
|
|
190
|
+
apiUrl: config?.apiUrl || configInfo.askSkip?.chatURL,
|
|
191
|
+
apiKey: config?.apiKey || configInfo.askSkip?.apiKey,
|
|
192
|
+
organizationId: config?.organizationId || configInfo.askSkip?.orgID,
|
|
193
|
+
organizationInfo: config?.organizationInfo || configInfo.askSkip?.organizationInfo,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Call the Skip chat API
|
|
199
|
+
*/
|
|
200
|
+
async chat(options: SkipCallOptions): Promise<SkipCallResult> {
|
|
201
|
+
LogStatus(`[SkipSDK] Sending request to Skip API: ${this.config.apiUrl}`);
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
// Build the Skip API request
|
|
205
|
+
const skipRequest = await this.buildSkipRequest(options);
|
|
206
|
+
|
|
207
|
+
// Call Skip API with streaming support
|
|
208
|
+
const responses = await sendPostRequest(
|
|
209
|
+
this.config.apiUrl,
|
|
210
|
+
skipRequest,
|
|
211
|
+
true, // useCompression
|
|
212
|
+
this.buildHeaders(),
|
|
213
|
+
(streamMessage: any) => {
|
|
214
|
+
// Handle streaming status updates
|
|
215
|
+
if (streamMessage.type === 'status_update' && options.onStatusUpdate) {
|
|
216
|
+
const statusContent = streamMessage.value?.messages?.[0]?.content;
|
|
217
|
+
const responsePhase = streamMessage.value?.responsePhase;
|
|
218
|
+
if (statusContent) {
|
|
219
|
+
options.onStatusUpdate(statusContent, responsePhase);
|
|
229
220
|
}
|
|
230
|
-
|
|
231
|
-
} catch (error) {
|
|
232
|
-
LogError(`[SkipSDK] Error calling Skip API: ${error}`);
|
|
233
|
-
return {
|
|
234
|
-
success: false,
|
|
235
|
-
error: String(error)
|
|
236
|
-
};
|
|
221
|
+
}
|
|
237
222
|
}
|
|
238
|
-
|
|
223
|
+
);
|
|
239
224
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
private async buildSkipRequest(options: SkipCallOptions): Promise<SkipAPIRequest> {
|
|
244
|
-
const {
|
|
245
|
-
messages,
|
|
246
|
-
conversationId,
|
|
247
|
-
dataContext,
|
|
248
|
-
requestPhase = 'initial_request',
|
|
249
|
-
contextUser,
|
|
250
|
-
dataSource,
|
|
251
|
-
includeEntities = true,
|
|
252
|
-
includeQueries = true,
|
|
253
|
-
includeNotes = true,
|
|
254
|
-
includeRequests = false,
|
|
255
|
-
forceEntityRefresh = false,
|
|
256
|
-
includeCallbackAuth = true
|
|
257
|
-
} = options;
|
|
258
|
-
|
|
259
|
-
// Build base request with metadata
|
|
260
|
-
const baseRequest = await this.buildBaseRequest(
|
|
261
|
-
contextUser,
|
|
262
|
-
dataSource,
|
|
263
|
-
includeEntities,
|
|
264
|
-
includeQueries,
|
|
265
|
-
includeNotes,
|
|
266
|
-
includeRequests,
|
|
267
|
-
forceEntityRefresh,
|
|
268
|
-
includeCallbackAuth,
|
|
269
|
-
{ conversationId, requestPhase }
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
// Build artifacts for this conversation
|
|
273
|
-
const artifacts = await this.buildArtifacts(contextUser, dataSource, conversationId);
|
|
274
|
-
|
|
275
|
-
// Process messages: filter delegation messages and enrich with metadata
|
|
276
|
-
const processedMessages = this.processMessages(messages);
|
|
277
|
-
|
|
278
|
-
// Construct the full Skip API request
|
|
279
|
-
const request: SkipAPIRequest = {
|
|
280
|
-
messages: processedMessages,
|
|
281
|
-
conversationID: conversationId,
|
|
282
|
-
dataContext: dataContext ? CopyScalarsAndArrays(dataContext) as DataContext : undefined,
|
|
283
|
-
requestPhase,
|
|
284
|
-
artifacts,
|
|
285
|
-
entities: baseRequest.entities || [],
|
|
286
|
-
queries: baseRequest.queries || [],
|
|
287
|
-
notes: baseRequest.notes,
|
|
288
|
-
noteTypes: baseRequest.noteTypes,
|
|
289
|
-
userEmail: baseRequest.userEmail,
|
|
290
|
-
organizationID: baseRequest.organizationID,
|
|
291
|
-
organizationInfo: baseRequest.organizationInfo,
|
|
292
|
-
apiKeys: baseRequest.apiKeys,
|
|
293
|
-
callingServerURL: baseRequest.callingServerURL,
|
|
294
|
-
callingServerAPIKey: baseRequest.callingServerAPIKey,
|
|
295
|
-
callingServerAccessToken: baseRequest.callingServerAccessToken
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
return request;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Build base request with metadata, API keys, and callback auth
|
|
303
|
-
*/
|
|
304
|
-
private async buildBaseRequest(
|
|
305
|
-
contextUser: UserInfo,
|
|
306
|
-
dataSource: mssql.ConnectionPool,
|
|
307
|
-
includeEntities: boolean,
|
|
308
|
-
includeQueries: boolean,
|
|
309
|
-
includeNotes: boolean,
|
|
310
|
-
includeRequests: boolean,
|
|
311
|
-
forceEntityRefresh: boolean,
|
|
312
|
-
includeCallbackAuth: boolean,
|
|
313
|
-
additionalTokenInfo: any = {}
|
|
314
|
-
): Promise<Partial<SkipAPIRequest>> {
|
|
315
|
-
const entities = includeEntities ? await this.buildEntities(dataSource, forceEntityRefresh) : [];
|
|
316
|
-
const queries = includeQueries ? this.buildQueries() : [];
|
|
317
|
-
const { notes, noteTypes } = includeNotes ? await this.buildAgentNotes(contextUser) : { notes: [], noteTypes: [] };
|
|
318
|
-
// Note: requests would be built here if includeRequests is true
|
|
319
|
-
|
|
320
|
-
// Setup access token for Skip callbacks if needed
|
|
321
|
-
let accessToken: GetDataAccessToken | undefined;
|
|
322
|
-
if (includeCallbackAuth) {
|
|
323
|
-
const tokenInfo = {
|
|
324
|
-
type: 'skip_api_request',
|
|
325
|
-
userEmail: contextUser.Email,
|
|
326
|
-
userName: contextUser.Name,
|
|
327
|
-
userID: contextUser.ID,
|
|
328
|
-
...additionalTokenInfo
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
accessToken = registerAccessToken(
|
|
332
|
-
undefined,
|
|
333
|
-
1000 * 60 * 10, // 10 minutes
|
|
334
|
-
tokenInfo
|
|
335
|
-
);
|
|
336
|
-
}
|
|
225
|
+
// The last response is the final one
|
|
226
|
+
if (responses && responses.length > 0) {
|
|
227
|
+
const finalResponse = responses[responses.length - 1].value as SkipAPIResponse;
|
|
337
228
|
|
|
338
229
|
return {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
userEmail: contextUser.Email,
|
|
344
|
-
organizationID: this.config.organizationId,
|
|
345
|
-
organizationInfo: this.config.organizationInfo,
|
|
346
|
-
apiKeys: this.buildAPIKeys(),
|
|
347
|
-
callingServerURL: accessToken ? (publicUrl || `${baseUrl}:${graphqlPort}${graphqlRootPath}`) : undefined,
|
|
348
|
-
callingServerAPIKey: accessToken ? callbackAPIKey : undefined,
|
|
349
|
-
callingServerAccessToken: accessToken ? accessToken.Token : undefined
|
|
230
|
+
success: true,
|
|
231
|
+
response: finalResponse,
|
|
232
|
+
responsePhase: finalResponse.responsePhase,
|
|
233
|
+
allResponses: responses,
|
|
350
234
|
};
|
|
235
|
+
} else {
|
|
236
|
+
return {
|
|
237
|
+
success: false,
|
|
238
|
+
error: 'No response received from Skip API',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
LogError(`[SkipSDK] Error calling Skip API: ${error}`);
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
error: String(error),
|
|
246
|
+
};
|
|
351
247
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Build the Skip API request object
|
|
252
|
+
*/
|
|
253
|
+
private async buildSkipRequest(options: SkipCallOptions): Promise<SkipAPIRequest> {
|
|
254
|
+
const {
|
|
255
|
+
messages,
|
|
256
|
+
conversationId,
|
|
257
|
+
dataContext,
|
|
258
|
+
requestPhase = 'initial_request',
|
|
259
|
+
contextUser,
|
|
260
|
+
dataSource,
|
|
261
|
+
includeEntities = true,
|
|
262
|
+
includeQueries = true,
|
|
263
|
+
includeNotes = true,
|
|
264
|
+
includeRequests = false,
|
|
265
|
+
forceEntityRefresh = false,
|
|
266
|
+
includeCallbackAuth = true,
|
|
267
|
+
} = options;
|
|
268
|
+
|
|
269
|
+
// Build base request with metadata
|
|
270
|
+
const baseRequest = await this.buildBaseRequest(
|
|
271
|
+
contextUser,
|
|
272
|
+
dataSource,
|
|
273
|
+
includeEntities,
|
|
274
|
+
includeQueries,
|
|
275
|
+
includeNotes,
|
|
276
|
+
includeRequests,
|
|
277
|
+
forceEntityRefresh,
|
|
278
|
+
includeCallbackAuth,
|
|
279
|
+
{ conversationId, requestPhase }
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// Build artifacts for this conversation
|
|
283
|
+
const artifacts = await this.buildArtifacts(contextUser, dataSource, conversationId);
|
|
284
|
+
|
|
285
|
+
// Process messages: filter delegation messages and enrich with metadata
|
|
286
|
+
const processedMessages = this.processMessages(messages);
|
|
287
|
+
|
|
288
|
+
// Construct the full Skip API request
|
|
289
|
+
const request: SkipAPIRequest = {
|
|
290
|
+
messages: processedMessages,
|
|
291
|
+
conversationID: conversationId,
|
|
292
|
+
dataContext: dataContext ? (CopyScalarsAndArrays(dataContext) as DataContext) : undefined,
|
|
293
|
+
requestPhase,
|
|
294
|
+
artifacts,
|
|
295
|
+
entities: baseRequest.entities || [],
|
|
296
|
+
queries: baseRequest.queries || [],
|
|
297
|
+
notes: baseRequest.notes,
|
|
298
|
+
noteTypes: baseRequest.noteTypes,
|
|
299
|
+
userEmail: baseRequest.userEmail,
|
|
300
|
+
organizationID: baseRequest.organizationID,
|
|
301
|
+
organizationInfo: baseRequest.organizationInfo,
|
|
302
|
+
apiKeys: baseRequest.apiKeys,
|
|
303
|
+
callingServerURL: baseRequest.callingServerURL,
|
|
304
|
+
callingServerAPIKey: baseRequest.callingServerAPIKey,
|
|
305
|
+
callingServerAccessToken: baseRequest.callingServerAccessToken,
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
return request;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Build base request with metadata, API keys, and callback auth
|
|
313
|
+
*/
|
|
314
|
+
private async buildBaseRequest(
|
|
315
|
+
contextUser: UserInfo,
|
|
316
|
+
dataSource: mssql.ConnectionPool,
|
|
317
|
+
includeEntities: boolean,
|
|
318
|
+
includeQueries: boolean,
|
|
319
|
+
includeNotes: boolean,
|
|
320
|
+
includeRequests: boolean,
|
|
321
|
+
forceEntityRefresh: boolean,
|
|
322
|
+
includeCallbackAuth: boolean,
|
|
323
|
+
additionalTokenInfo: any = {}
|
|
324
|
+
): Promise<Partial<SkipAPIRequest>> {
|
|
325
|
+
const entities = includeEntities ? await this.buildEntities(dataSource, forceEntityRefresh) : [];
|
|
326
|
+
const queries = includeQueries ? this.buildQueries() : [];
|
|
327
|
+
const { notes, noteTypes } = includeNotes ? await this.buildAgentNotes(contextUser) : { notes: [], noteTypes: [] };
|
|
328
|
+
// Note: requests would be built here if includeRequests is true
|
|
329
|
+
|
|
330
|
+
// Setup access token for Skip callbacks if needed
|
|
331
|
+
let accessToken: GetDataAccessToken | undefined;
|
|
332
|
+
if (includeCallbackAuth) {
|
|
333
|
+
const tokenInfo = {
|
|
334
|
+
type: 'skip_api_request',
|
|
335
|
+
userEmail: contextUser.Email,
|
|
336
|
+
userName: contextUser.Name,
|
|
337
|
+
userID: contextUser.ID,
|
|
338
|
+
...additionalTokenInfo,
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
accessToken = registerAccessToken(
|
|
342
|
+
undefined,
|
|
343
|
+
1000 * 60 * 10, // 10 minutes
|
|
344
|
+
tokenInfo
|
|
345
|
+
);
|
|
443
346
|
}
|
|
444
347
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
348
|
+
return {
|
|
349
|
+
entities,
|
|
350
|
+
queries,
|
|
351
|
+
notes,
|
|
352
|
+
noteTypes,
|
|
353
|
+
userEmail: contextUser.Email,
|
|
354
|
+
organizationID: this.config.organizationId,
|
|
355
|
+
organizationInfo: this.config.organizationInfo,
|
|
356
|
+
apiKeys: this.buildAPIKeys(),
|
|
357
|
+
callingServerURL: accessToken ? publicUrl || `${baseUrl}:${graphqlPort}${graphqlRootPath}` : undefined,
|
|
358
|
+
callingServerAPIKey: accessToken ? callbackAPIKey : undefined,
|
|
359
|
+
callingServerAccessToken: accessToken ? accessToken.Token : undefined,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Build entity metadata for Skip
|
|
365
|
+
* Copied from AskSkipResolver.BuildSkipEntities - uses cached metadata with refresh logic
|
|
366
|
+
*/
|
|
367
|
+
private async buildEntities(
|
|
368
|
+
dataSource: mssql.ConnectionPool,
|
|
369
|
+
forceRefresh: boolean,
|
|
370
|
+
refreshIntervalMinutes: number = 15
|
|
371
|
+
): Promise<SkipEntityInfo[]> {
|
|
372
|
+
try {
|
|
373
|
+
const now = Date.now();
|
|
374
|
+
const cacheExpired = now - SkipSDK.__lastRefreshTime > refreshIntervalMinutes * 60 * 1000;
|
|
375
|
+
|
|
376
|
+
// If force refresh is requested OR cache expired OR cache is empty, refresh
|
|
377
|
+
if (forceRefresh || cacheExpired || SkipSDK.__skipEntitiesCache$.value === null) {
|
|
378
|
+
LogStatus(`[SkipSDK] Refreshing Skip entities cache (force: ${forceRefresh}, expired: ${cacheExpired})`);
|
|
379
|
+
const newData = this.refreshSkipEntities(dataSource);
|
|
380
|
+
SkipSDK.__skipEntitiesCache$.next(newData);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return SkipSDK.__skipEntitiesCache$.pipe(take(1)).toPromise();
|
|
384
|
+
} catch (e) {
|
|
385
|
+
LogError(`[SkipSDK] buildEntities error: ${e}`);
|
|
386
|
+
return [];
|
|
453
387
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Build saved queries for Skip
|
|
392
|
+
*/
|
|
393
|
+
private buildQueries(status: 'Pending' | 'In-Review' | 'Approved' | 'Rejected' | 'Obsolete' = 'Approved'): SkipQueryInfo[] {
|
|
394
|
+
const md = new Metadata();
|
|
395
|
+
const approvedQueries = md.Queries.filter((q) => q.Status === status);
|
|
396
|
+
|
|
397
|
+
return approvedQueries.map((q) => ({
|
|
398
|
+
id: q.ID,
|
|
399
|
+
name: q.Name,
|
|
400
|
+
description: q.Description,
|
|
401
|
+
category: q.Category,
|
|
402
|
+
categoryPath: this.buildQueryCategoryPath(md, q.CategoryID),
|
|
403
|
+
sql: q.SQL,
|
|
404
|
+
originalSQL: q.OriginalSQL,
|
|
405
|
+
feedback: q.Feedback,
|
|
406
|
+
status: q.Status,
|
|
407
|
+
qualityRank: q.QualityRank,
|
|
408
|
+
createdAt: q.__mj_CreatedAt,
|
|
409
|
+
updatedAt: q.__mj_UpdatedAt,
|
|
410
|
+
categoryID: q.CategoryID,
|
|
411
|
+
embeddingVector: q.EmbeddingVector,
|
|
412
|
+
embeddingModelID: q.EmbeddingModelID,
|
|
413
|
+
embeddingModelName: q.EmbeddingModel,
|
|
414
|
+
fields: q.Fields.map((f) => ({
|
|
415
|
+
id: f.ID,
|
|
416
|
+
queryID: f.QueryID,
|
|
417
|
+
sequence: f.Sequence,
|
|
418
|
+
name: f.Name,
|
|
419
|
+
description: f.Description,
|
|
420
|
+
sqlBaseType: f.SQLBaseType,
|
|
421
|
+
sqlFullType: f.SQLFullType,
|
|
422
|
+
sourceEntityID: f.SourceEntityID,
|
|
423
|
+
sourceEntity: f.SourceEntity,
|
|
424
|
+
sourceFieldName: f.SourceFieldName,
|
|
425
|
+
isComputed: f.IsComputed,
|
|
426
|
+
computationDescription: f.ComputationDescription,
|
|
427
|
+
isSummary: f.IsSummary,
|
|
428
|
+
summaryDescription: f.SummaryDescription,
|
|
429
|
+
createdAt: f.__mj_CreatedAt,
|
|
430
|
+
updatedAt: f.__mj_UpdatedAt,
|
|
431
|
+
})),
|
|
432
|
+
params: q.Parameters.map((p) => ({
|
|
433
|
+
id: p.ID,
|
|
434
|
+
queryID: p.QueryID,
|
|
435
|
+
name: p.Name,
|
|
436
|
+
description: p.Description,
|
|
437
|
+
type: p.Type,
|
|
438
|
+
isRequired: p.IsRequired,
|
|
439
|
+
// LinkedParameterName and LinkedParameterType may not exist on QueryParameterInfo
|
|
440
|
+
defaultValue: p.DefaultValue,
|
|
441
|
+
createdAt: p.__mj_CreatedAt,
|
|
442
|
+
updatedAt: p.__mj_UpdatedAt,
|
|
443
|
+
})),
|
|
444
|
+
}));
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Recursively build category path for a query
|
|
449
|
+
*/
|
|
450
|
+
private buildQueryCategoryPath(md: Metadata, categoryID: string): string {
|
|
451
|
+
const cat = md.QueryCategories.find((c) => c.ID === categoryID);
|
|
452
|
+
if (!cat) return '';
|
|
453
|
+
if (!cat.ParentID) return cat.Name;
|
|
454
|
+
const parentPath = this.buildQueryCategoryPath(md, cat.ParentID);
|
|
455
|
+
return parentPath ? `${parentPath}/${cat.Name}` : cat.Name;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Build agent notes for Skip
|
|
460
|
+
*/
|
|
461
|
+
private async buildAgentNotes(contextUser: UserInfo): Promise<{ notes: SkipAPIAgentNote[]; noteTypes: SkipAPIAgentNoteType[] }> {
|
|
462
|
+
// TODO: Implement agent notes building
|
|
463
|
+
// This would query AIAgentNote entities and convert to SkipAPIAgentNote format
|
|
464
|
+
// For now, returning empty arrays
|
|
465
|
+
return { notes: [], noteTypes: [] };
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Build artifacts for a conversation using optimized query
|
|
470
|
+
* Uses GetConversationArtifactsForAgent query which joins through ConversationDetailArtifact
|
|
471
|
+
* to get artifacts that were outputs from Skip agent's conversation details
|
|
472
|
+
*/
|
|
473
|
+
private async buildArtifacts(
|
|
474
|
+
contextUser: UserInfo,
|
|
475
|
+
dataSource: mssql.ConnectionPool,
|
|
476
|
+
conversationId: string
|
|
477
|
+
): Promise<SkipAPIArtifact[]> {
|
|
478
|
+
try {
|
|
479
|
+
const rq = new RunQuery();
|
|
480
|
+
|
|
481
|
+
// Ensure AIEngine is configured and get Skip agent ID
|
|
482
|
+
await AIEngine.Instance.Config(false, contextUser);
|
|
483
|
+
const skipAgent = AIEngine.Instance.GetAgentByName('Skip');
|
|
484
|
+
const skipAgentId = skipAgent?.ID;
|
|
485
|
+
|
|
486
|
+
if (!skipAgentId) {
|
|
487
|
+
LogError('[SkipSDK] Skip agent not found in AIEngine');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Use optimized query that replaces 4 RunView calls with 1 query
|
|
491
|
+
// This query includes Configuration field needed for component spec extraction
|
|
492
|
+
// Filter by Skip agent ID to only get artifacts created by Skip (not delegation agents)
|
|
493
|
+
const result = await rq.RunQuery(
|
|
494
|
+
{
|
|
495
|
+
QueryName: 'GetConversationArtifactsForAgent',
|
|
496
|
+
CategoryPath: 'MJ/Conversations',
|
|
497
|
+
Parameters: {
|
|
498
|
+
ConversationID: conversationId,
|
|
499
|
+
AgentID: skipAgentId, // Filter to only artifacts created by Skip agent
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
contextUser
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
if (!result.Success || !result.Results || result.Results.length === 0) {
|
|
506
|
+
return [];
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Query returns flat result set: one row per artifact version
|
|
510
|
+
// Group by ArtifactID to build SkipAPIArtifact objects with their versions
|
|
511
|
+
const artifactMap = new Map<
|
|
512
|
+
string,
|
|
513
|
+
{
|
|
514
|
+
artifact: any;
|
|
515
|
+
artifactType: SkipAPIArtifactType;
|
|
516
|
+
versions: SkipAPIArtifactVersion[];
|
|
564
517
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
518
|
+
>();
|
|
519
|
+
|
|
520
|
+
// Process each row (represents one version)
|
|
521
|
+
for (const row of result.Results) {
|
|
522
|
+
const artifactId = row.ArtifactID;
|
|
523
|
+
|
|
524
|
+
// Initialize artifact entry if not exists
|
|
525
|
+
if (!artifactMap.has(artifactId)) {
|
|
526
|
+
// Map database sharingScope values to SkipAPIArtifact expected values
|
|
527
|
+
let sharingScope: 'None' | 'SpecificUsers' | 'Everyone' | 'Public' = 'None';
|
|
528
|
+
const dbSharingScope = (row.SharingScope || '').toLowerCase();
|
|
529
|
+
if (dbSharingScope === 'always' || dbSharingScope === 'everyone') {
|
|
530
|
+
sharingScope = 'Everyone';
|
|
531
|
+
} else if (dbSharingScope === 'public') {
|
|
532
|
+
sharingScope = 'Public';
|
|
533
|
+
} else if (dbSharingScope === 'specific users' || dbSharingScope === 'specificusers') {
|
|
534
|
+
sharingScope = 'SpecificUsers';
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
artifactMap.set(artifactId, {
|
|
538
|
+
artifact: {
|
|
539
|
+
id: artifactId,
|
|
540
|
+
conversationId: conversationId,
|
|
541
|
+
name: row.ArtifactName,
|
|
542
|
+
description: row.ArtifactDescription || '',
|
|
543
|
+
sharingScope: sharingScope,
|
|
544
|
+
comments: row.ArtifactComments || '',
|
|
545
|
+
createdAt: new Date(row.ArtifactCreatedAt),
|
|
546
|
+
updatedAt: new Date(row.ArtifactUpdatedAt),
|
|
587
547
|
},
|
|
588
|
-
{
|
|
589
|
-
|
|
590
|
-
|
|
548
|
+
artifactType: {
|
|
549
|
+
id: row.ArtifactTypeID,
|
|
550
|
+
name: row.ArtifactTypeName,
|
|
551
|
+
description: row.ArtifactTypeDescription,
|
|
552
|
+
contentType: row.ArtifactTypeContentType,
|
|
553
|
+
enabled: true,
|
|
554
|
+
createdAt: new Date(row.ArtifactTypeCreatedAt),
|
|
555
|
+
updatedAt: new Date(row.ArtifactTypeUpdatedAt),
|
|
591
556
|
},
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
}
|
|
596
|
-
];
|
|
597
|
-
}
|
|
557
|
+
versions: [],
|
|
558
|
+
});
|
|
559
|
+
}
|
|
598
560
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
561
|
+
// Add this version to the artifact
|
|
562
|
+
const entry = artifactMap.get(artifactId)!;
|
|
563
|
+
entry.versions.push({
|
|
564
|
+
id: row.VersionID,
|
|
565
|
+
artifactId: artifactId,
|
|
566
|
+
conversationDetailID: row.ConversationDetailID, // Direct from join table!
|
|
567
|
+
version: row.Version,
|
|
568
|
+
configuration: row.Configuration || '',
|
|
569
|
+
content: row.Content || '',
|
|
570
|
+
comments: row.VersionComments || '',
|
|
571
|
+
createdAt: new Date(row.VersionCreatedAt),
|
|
572
|
+
updatedAt: new Date(row.VersionUpdatedAt),
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Convert map to SkipAPIArtifact array
|
|
577
|
+
const artifacts: SkipAPIArtifact[] = Array.from(artifactMap.values()).map((entry) => ({
|
|
578
|
+
...entry.artifact,
|
|
579
|
+
artifactType: entry.artifactType,
|
|
580
|
+
versions: entry.versions,
|
|
581
|
+
}));
|
|
582
|
+
|
|
583
|
+
return artifacts;
|
|
584
|
+
} catch (error) {
|
|
585
|
+
LogError(`Failed to build artifacts for conversation ${conversationId}: ${error}`);
|
|
586
|
+
return [];
|
|
607
587
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Build API keys for AI services
|
|
592
|
+
*/
|
|
593
|
+
private buildAPIKeys(): SkipAPIRequestAPIKey[] {
|
|
594
|
+
return [
|
|
595
|
+
{
|
|
596
|
+
vendorDriverName: 'OpenAILLM',
|
|
597
|
+
apiKey: GetAIAPIKey('OpenAILLM'),
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
vendorDriverName: 'AnthropicLLM',
|
|
601
|
+
apiKey: GetAIAPIKey('AnthropicLLM'),
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
vendorDriverName: 'GeminiLLM',
|
|
605
|
+
apiKey: GetAIAPIKey('GeminiLLM'),
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
vendorDriverName: 'GroqLLM',
|
|
609
|
+
apiKey: GetAIAPIKey('GroqLLM'),
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
vendorDriverName: 'MistralLLM',
|
|
613
|
+
apiKey: GetAIAPIKey('MistralLLM'),
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
vendorDriverName: 'CerebrasLLM',
|
|
617
|
+
apiKey: GetAIAPIKey('CerebrasLLM'),
|
|
618
|
+
},
|
|
619
|
+
];
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Build HTTP headers for Skip API requests
|
|
624
|
+
*/
|
|
625
|
+
private buildHeaders(): Record<string, string> {
|
|
626
|
+
return {
|
|
627
|
+
'x-api-key': this.config.apiKey || '',
|
|
628
|
+
'Content-Type': 'application/json',
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Refreshes the Skip entities cache
|
|
634
|
+
* Rebuilds the entity information that is provided to Skip
|
|
635
|
+
* Copied from AskSkipResolver.refreshSkipEntities
|
|
636
|
+
*/
|
|
637
|
+
private async refreshSkipEntities(dataSource: mssql.ConnectionPool): Promise<SkipEntityInfo[]> {
|
|
638
|
+
try {
|
|
639
|
+
const md = new Metadata();
|
|
640
|
+
const skipSpecialIncludeEntities = (configInfo.askSkip?.entitiesToSend?.includeEntitiesFromExcludedSchemas ?? []).map((e) =>
|
|
641
|
+
e.trim().toLowerCase()
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
// Get the list of entities
|
|
645
|
+
const entities = md.Entities.filter((e) => {
|
|
646
|
+
if (
|
|
647
|
+
!configInfo.askSkip.entitiesToSend.excludeSchemas.includes(e.SchemaName) ||
|
|
648
|
+
skipSpecialIncludeEntities.includes(e.Name.trim().toLowerCase())
|
|
649
|
+
) {
|
|
650
|
+
const sd = e.ScopeDefault?.trim();
|
|
651
|
+
if (sd && sd.length > 0) {
|
|
652
|
+
const scopes = sd.split(',').map((s) => s.trim().toLowerCase()) ?? ['all'];
|
|
653
|
+
return (
|
|
654
|
+
!scopes ||
|
|
655
|
+
scopes.length === 0 ||
|
|
656
|
+
scopes.includes('all') ||
|
|
657
|
+
scopes.includes('ai') ||
|
|
658
|
+
skipSpecialIncludeEntities.includes(e.Name.trim().toLowerCase())
|
|
659
|
+
);
|
|
660
|
+
} else {
|
|
661
|
+
return true; // no scope, so include it
|
|
662
|
+
}
|
|
645
663
|
}
|
|
646
|
-
|
|
664
|
+
return false;
|
|
665
|
+
});
|
|
647
666
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
* Includes fields, relationships, and sample data
|
|
651
|
-
* Copied from AskSkipResolver.PackSingleSkipEntityInfo
|
|
652
|
-
*/
|
|
653
|
-
private async packSingleSkipEntityInfo(e: EntityInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityInfo> {
|
|
654
|
-
try {
|
|
655
|
-
const ret: SkipEntityInfo = {
|
|
656
|
-
id: e.ID,
|
|
657
|
-
name: e.Name,
|
|
658
|
-
schemaName: e.SchemaName,
|
|
659
|
-
baseView: e.BaseView,
|
|
660
|
-
description: e.Description,
|
|
661
|
-
|
|
662
|
-
fields: await Promise.all(e.Fields.filter(f => {
|
|
663
|
-
// we want to check the scopes for the field level and make sure it is either All or AI or has both
|
|
664
|
-
const scopes = f.ScopeDefault?.split(',').map((s) => s.trim().toLowerCase());
|
|
665
|
-
return !scopes || scopes.length === 0 || scopes.includes('all') || scopes.includes('ai');
|
|
666
|
-
}).map(f => {
|
|
667
|
-
return this.packSingleSkipEntityField(f, dataSource);
|
|
668
|
-
})),
|
|
669
|
-
|
|
670
|
-
relatedEntities: e.RelatedEntities.map((r) => {
|
|
671
|
-
return this.packSingleSkipEntityRelationship(r);
|
|
672
|
-
}),
|
|
667
|
+
// Now we have our list of entities, pack em up
|
|
668
|
+
const result = await Promise.all(entities.map((e) => this.packSingleSkipEntityInfo(e, dataSource)));
|
|
673
669
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
}
|
|
680
|
-
catch (e) {
|
|
681
|
-
LogError(`[SkipSDK] packSingleSkipEntityInfo error: ${e}`);
|
|
682
|
-
return null;
|
|
683
|
-
}
|
|
670
|
+
SkipSDK.__lastRefreshTime = Date.now(); // Update last refresh time
|
|
671
|
+
return result;
|
|
672
|
+
} catch (e) {
|
|
673
|
+
LogError(`[SkipSDK] refreshSkipEntities error: ${e}`);
|
|
674
|
+
return [];
|
|
684
675
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Packs information about a single entity for Skip
|
|
680
|
+
* Includes fields, relationships, and sample data
|
|
681
|
+
* Copied from AskSkipResolver.PackSingleSkipEntityInfo
|
|
682
|
+
*/
|
|
683
|
+
private async packSingleSkipEntityInfo(e: EntityInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityInfo> {
|
|
684
|
+
try {
|
|
685
|
+
const ret: SkipEntityInfo = {
|
|
686
|
+
id: e.ID,
|
|
687
|
+
name: e.Name,
|
|
688
|
+
schemaName: e.SchemaName,
|
|
689
|
+
baseView: e.BaseView,
|
|
690
|
+
description: e.Description,
|
|
691
|
+
|
|
692
|
+
fields: await Promise.all(
|
|
693
|
+
e.Fields.filter((f) => {
|
|
694
|
+
// we want to check the scopes for the field level and make sure it is either All or AI or has both
|
|
695
|
+
const scopes = f.ScopeDefault?.split(',').map((s) => s.trim().toLowerCase());
|
|
696
|
+
return !scopes || scopes.length === 0 || scopes.includes('all') || scopes.includes('ai');
|
|
697
|
+
}).map((f) => {
|
|
698
|
+
return this.packSingleSkipEntityField(f, dataSource);
|
|
699
|
+
})
|
|
700
|
+
),
|
|
701
|
+
|
|
702
|
+
relatedEntities: e.RelatedEntities.map((r) => {
|
|
703
|
+
return this.packSingleSkipEntityRelationship(r);
|
|
704
|
+
}),
|
|
705
|
+
|
|
706
|
+
rowsPacked: e.RowsToPackWithSchema,
|
|
707
|
+
rowsSampleMethod: e.RowsToPackSampleMethod,
|
|
708
|
+
rows: await this.packEntityRows(e, dataSource),
|
|
709
|
+
};
|
|
710
|
+
return ret;
|
|
711
|
+
} catch (e) {
|
|
712
|
+
LogError(`[SkipSDK] packSingleSkipEntityInfo error: ${e}`);
|
|
713
|
+
return null;
|
|
712
714
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
extendedType: f.ExtendedType,
|
|
740
|
-
defaultInView: f.DefaultInView,
|
|
741
|
-
defaultColumnWidth: f.DefaultColumnWidth,
|
|
742
|
-
isVirtual: f.IsVirtual,
|
|
743
|
-
isNameField: f.IsNameField,
|
|
744
|
-
relatedEntityID: f.RelatedEntityID,
|
|
745
|
-
relatedEntityFieldName: f.RelatedEntityFieldName,
|
|
746
|
-
relatedEntity: f.RelatedEntity,
|
|
747
|
-
relatedEntitySchemaName: f.RelatedEntitySchemaName,
|
|
748
|
-
relatedEntityBaseView: f.RelatedEntityBaseView,
|
|
749
|
-
possibleValues: await this.packFieldPossibleValues(f, dataSource),
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
catch (e) {
|
|
753
|
-
LogError(`[SkipSDK] packSingleSkipEntityField error: ${e}`);
|
|
754
|
-
return null;
|
|
755
|
-
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Packs information about a single entity relationship
|
|
719
|
+
* These relationships help Skip understand the data model
|
|
720
|
+
* Copied from AskSkipResolver.PackSingleSkipEntityRelationship
|
|
721
|
+
*/
|
|
722
|
+
private packSingleSkipEntityRelationship(r: EntityRelationshipInfo): SkipEntityRelationshipInfo {
|
|
723
|
+
try {
|
|
724
|
+
return {
|
|
725
|
+
entityID: r.EntityID,
|
|
726
|
+
relatedEntityID: r.RelatedEntityID,
|
|
727
|
+
type: r.Type,
|
|
728
|
+
entityKeyField: r.EntityKeyField,
|
|
729
|
+
relatedEntityJoinField: r.RelatedEntityJoinField,
|
|
730
|
+
joinView: r.JoinView,
|
|
731
|
+
joinEntityJoinField: r.JoinEntityJoinField,
|
|
732
|
+
joinEntityInverseJoinField: r.JoinEntityInverseJoinField,
|
|
733
|
+
entity: r.Entity,
|
|
734
|
+
entityBaseView: r.EntityBaseView,
|
|
735
|
+
relatedEntity: r.RelatedEntity,
|
|
736
|
+
relatedEntityBaseView: r.RelatedEntityBaseView,
|
|
737
|
+
};
|
|
738
|
+
} catch (e) {
|
|
739
|
+
LogError(`[SkipSDK] packSingleSkipEntityRelationship error: ${e}`);
|
|
740
|
+
return null;
|
|
756
741
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Packs information about a single entity field
|
|
746
|
+
* Includes metadata and possible values
|
|
747
|
+
* Copied from AskSkipResolver.PackSingleSkipEntityField
|
|
748
|
+
*/
|
|
749
|
+
private async packSingleSkipEntityField(f: EntityFieldInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityFieldInfo> {
|
|
750
|
+
try {
|
|
751
|
+
return {
|
|
752
|
+
entityID: f.EntityID,
|
|
753
|
+
sequence: f.Sequence,
|
|
754
|
+
name: f.Name,
|
|
755
|
+
displayName: f.DisplayName,
|
|
756
|
+
category: f.Category,
|
|
757
|
+
type: f.Type,
|
|
758
|
+
description: f.Description,
|
|
759
|
+
isPrimaryKey: f.IsPrimaryKey,
|
|
760
|
+
allowsNull: f.AllowsNull,
|
|
761
|
+
isUnique: f.IsUnique,
|
|
762
|
+
length: f.Length,
|
|
763
|
+
precision: f.Precision,
|
|
764
|
+
scale: f.Scale,
|
|
765
|
+
sqlFullType: f.SQLFullType,
|
|
766
|
+
defaultValue: f.DefaultValue,
|
|
767
|
+
autoIncrement: f.AutoIncrement,
|
|
768
|
+
valueListType: f.ValueListType,
|
|
769
|
+
extendedType: f.ExtendedType,
|
|
770
|
+
defaultInView: f.DefaultInView,
|
|
771
|
+
defaultColumnWidth: f.DefaultColumnWidth,
|
|
772
|
+
isVirtual: f.IsVirtual,
|
|
773
|
+
isNameField: f.IsNameField,
|
|
774
|
+
relatedEntityID: f.RelatedEntityID,
|
|
775
|
+
relatedEntityFieldName: f.RelatedEntityFieldName,
|
|
776
|
+
relatedEntity: f.RelatedEntity,
|
|
777
|
+
relatedEntitySchemaName: f.RelatedEntitySchemaName,
|
|
778
|
+
relatedEntityBaseView: f.RelatedEntityBaseView,
|
|
779
|
+
possibleValues: await this.packFieldPossibleValues(f, dataSource),
|
|
780
|
+
};
|
|
781
|
+
} catch (e) {
|
|
782
|
+
LogError(`[SkipSDK] packSingleSkipEntityField error: ${e}`);
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Packs entity rows (sample data)
|
|
789
|
+
* Copied from AskSkipResolver.PackEntityRows
|
|
790
|
+
*/
|
|
791
|
+
private async packEntityRows(e: EntityInfo, dataSource: mssql.ConnectionPool): Promise<any[]> {
|
|
792
|
+
try {
|
|
793
|
+
if (e.RowsToPackWithSchema === 'None') return [];
|
|
794
|
+
|
|
795
|
+
// only include columns that have a scopes including either All and/or AI or have Null for ScopeDefault
|
|
796
|
+
const fields = e.Fields.filter((f) => {
|
|
797
|
+
const scopes = f.ScopeDefault?.split(',').map((s) => s.trim().toLowerCase());
|
|
798
|
+
return !scopes || scopes.length === 0 || scopes.includes('all') || scopes.includes('ai');
|
|
799
|
+
})
|
|
800
|
+
.map((f) => `[${f.Name}]`)
|
|
801
|
+
.join(',');
|
|
802
|
+
|
|
803
|
+
// now run the query based on the row packing method
|
|
804
|
+
let sql: string = '';
|
|
805
|
+
switch (e.RowsToPackWithSchema) {
|
|
806
|
+
case 'All':
|
|
807
|
+
sql = `SELECT ${fields} FROM ${e.SchemaName}.${e.BaseView}`;
|
|
808
|
+
break;
|
|
809
|
+
case 'Sample':
|
|
810
|
+
switch (e.RowsToPackSampleMethod) {
|
|
811
|
+
case 'random':
|
|
812
|
+
sql = `SELECT TOP ${e.RowsToPackSampleCount} ${fields} FROM [${e.SchemaName}].[${e.BaseView}] ORDER BY newid()`;
|
|
813
|
+
break;
|
|
814
|
+
case 'top n':
|
|
815
|
+
const orderBy = e.RowsToPackSampleOrder ? ` ORDER BY [${e.RowsToPackSampleOrder}]` : '';
|
|
816
|
+
sql = `SELECT TOP ${e.RowsToPackSampleCount} ${fields} FROM [${e.SchemaName}].[${e.BaseView}]${orderBy}`;
|
|
817
|
+
break;
|
|
818
|
+
case 'bottom n':
|
|
819
|
+
const firstPrimaryKey = e.FirstPrimaryKey.Name;
|
|
820
|
+
const innerOrderBy = e.RowsToPackSampleOrder ? `[${e.RowsToPackSampleOrder}]` : `[${firstPrimaryKey}] DESC`;
|
|
821
|
+
sql = `SELECT * FROM (
|
|
792
822
|
SELECT TOP ${e.RowsToPackSampleCount} ${fields}
|
|
793
823
|
FROM [${e.SchemaName}].[${e.BaseView}]
|
|
794
824
|
ORDER BY ${innerOrderBy}
|
|
795
825
|
) sub
|
|
796
826
|
ORDER BY [${firstPrimaryKey}] ASC;`;
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
LogError(`[SkipSDK] packEntityRows error: ${e}`);
|
|
811
|
-
return [];
|
|
812
|
-
}
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
const request = new mssql.Request(dataSource);
|
|
831
|
+
const result = await request.query(sql);
|
|
832
|
+
if (!result || !result.recordset) {
|
|
833
|
+
return [];
|
|
834
|
+
} else {
|
|
835
|
+
return result.recordset;
|
|
836
|
+
}
|
|
837
|
+
} catch (e) {
|
|
838
|
+
LogError(`[SkipSDK] packEntityRows error: ${e}`);
|
|
839
|
+
return [];
|
|
813
840
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
return []; // if we get here, nothing to pack
|
|
855
|
-
}
|
|
856
|
-
catch (e) {
|
|
857
|
-
LogError(`[SkipSDK] packFieldPossibleValues error: ${e}`);
|
|
858
|
-
return [];
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
/**
|
|
863
|
-
* Gets distinct values for a field from the database
|
|
864
|
-
* Used to provide Skip with information about the possible values
|
|
865
|
-
* Copied from AskSkipResolver.GetFieldDistinctValues
|
|
866
|
-
*/
|
|
867
|
-
private async getFieldDistinctValues(f: EntityFieldInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityFieldValueInfo[]> {
|
|
868
|
-
try {
|
|
869
|
-
const sql = `SELECT DISTINCT ${f.Name} FROM ${f.SchemaName}.${f.BaseView}`;
|
|
870
|
-
const request = new mssql.Request(dataSource);
|
|
871
|
-
const result = await request.query(sql);
|
|
872
|
-
if (!result || !result.recordset) {
|
|
873
|
-
return [];
|
|
874
|
-
}
|
|
875
|
-
else {
|
|
876
|
-
return result.recordset.map((r) => {
|
|
877
|
-
return {
|
|
878
|
-
value: r[f.Name],
|
|
879
|
-
displayValue: r[f.Name]
|
|
880
|
-
};
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
catch (e) {
|
|
885
|
-
LogError(`[SkipSDK] getFieldDistinctValues error: ${e}`);
|
|
886
|
-
return [];
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Packs possible values for an entity field
|
|
845
|
+
* These values help Skip understand the domain and valid values for fields
|
|
846
|
+
* Copied from AskSkipResolver.PackFieldPossibleValues
|
|
847
|
+
*/
|
|
848
|
+
private async packFieldPossibleValues(f: EntityFieldInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityFieldValueInfo[]> {
|
|
849
|
+
try {
|
|
850
|
+
if (f.ValuesToPackWithSchema === 'None') {
|
|
851
|
+
return []; // don't pack anything
|
|
852
|
+
} else if (f.ValuesToPackWithSchema === 'All') {
|
|
853
|
+
// wants ALL of the distinct values
|
|
854
|
+
return await this.getFieldDistinctValues(f, dataSource);
|
|
855
|
+
} else if (f.ValuesToPackWithSchema === 'Auto') {
|
|
856
|
+
// default setting - pack based on the ValueListType
|
|
857
|
+
if (f.ValueListTypeEnum === 'List') {
|
|
858
|
+
// simple list of values in the Entity Field Values table
|
|
859
|
+
return f.EntityFieldValues.map((v) => {
|
|
860
|
+
return { value: v.Value, displayValue: v.Value };
|
|
861
|
+
});
|
|
862
|
+
} else if (f.ValueListTypeEnum === 'ListOrUserEntry') {
|
|
863
|
+
// could be a user provided value, OR the values in the list of possible values.
|
|
864
|
+
// get the distinct list of values from the DB and concat that with the f.EntityFieldValues array - deduped and return
|
|
865
|
+
const values = await this.getFieldDistinctValues(f, dataSource);
|
|
866
|
+
if (!values || values.length === 0) {
|
|
867
|
+
// no result, just return the EntityFieldValues
|
|
868
|
+
return f.EntityFieldValues.map((v) => {
|
|
869
|
+
return { value: v.Value, displayValue: v.Value };
|
|
870
|
+
});
|
|
871
|
+
} else {
|
|
872
|
+
return [
|
|
873
|
+
...new Set([
|
|
874
|
+
...f.EntityFieldValues.map((v) => {
|
|
875
|
+
return { value: v.Value, displayValue: v.Value };
|
|
876
|
+
}),
|
|
877
|
+
...values,
|
|
878
|
+
]),
|
|
879
|
+
];
|
|
880
|
+
}
|
|
887
881
|
}
|
|
882
|
+
}
|
|
883
|
+
return []; // if we get here, nothing to pack
|
|
884
|
+
} catch (e) {
|
|
885
|
+
LogError(`[SkipSDK] packFieldPossibleValues error: ${e}`);
|
|
886
|
+
return [];
|
|
888
887
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
*/
|
|
915
|
-
private isDelegationMessage(content: string): boolean {
|
|
916
|
-
if (!content) return false;
|
|
917
|
-
|
|
918
|
-
const lowerContent = content.toLowerCase();
|
|
919
|
-
|
|
920
|
-
// Check for both "delegating" or "delegate" AND "skip" in any order
|
|
921
|
-
const hasDelegatingOrDelegate = lowerContent.includes('delegating') || lowerContent.includes('delegate');
|
|
922
|
-
const hasSkip = lowerContent.includes('skip');
|
|
923
|
-
|
|
924
|
-
return hasDelegatingOrDelegate && hasSkip;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Gets distinct values for a field from the database
|
|
892
|
+
* Used to provide Skip with information about the possible values
|
|
893
|
+
* Copied from AskSkipResolver.GetFieldDistinctValues
|
|
894
|
+
*/
|
|
895
|
+
private async getFieldDistinctValues(f: EntityFieldInfo, dataSource: mssql.ConnectionPool): Promise<SkipEntityFieldValueInfo[]> {
|
|
896
|
+
try {
|
|
897
|
+
const sql = `SELECT DISTINCT ${f.Name} FROM ${f.SchemaName}.${f.BaseView}`;
|
|
898
|
+
const request = new mssql.Request(dataSource);
|
|
899
|
+
const result = await request.query(sql);
|
|
900
|
+
if (!result || !result.recordset) {
|
|
901
|
+
return [];
|
|
902
|
+
} else {
|
|
903
|
+
return result.recordset.map((r) => {
|
|
904
|
+
return {
|
|
905
|
+
value: r[f.Name],
|
|
906
|
+
displayValue: r[f.Name],
|
|
907
|
+
};
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
} catch (e) {
|
|
911
|
+
LogError(`[SkipSDK] getFieldDistinctValues error: ${e}`);
|
|
912
|
+
return [];
|
|
925
913
|
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Process messages: filter delegation messages and add metadata fields
|
|
918
|
+
* Messages coming in should already have conversationDetailID if they exist in the database
|
|
919
|
+
*/
|
|
920
|
+
private processMessages(messages: SkipMessage[]): SkipMessage[] {
|
|
921
|
+
// Filter out delegation messages (administrative messages that shouldn't go to Skip)
|
|
922
|
+
const filteredMessages = messages.filter((msg) => !this.isDelegationMessage(msg.content));
|
|
923
|
+
|
|
924
|
+
// Enrich messages with default metadata if not already present
|
|
925
|
+
return filteredMessages.map((msg) => ({
|
|
926
|
+
...msg,
|
|
927
|
+
// Add default metadata fields if not already present
|
|
928
|
+
// Messages from DB already have conversationDetailID, temp messages get temp-X
|
|
929
|
+
hiddenToUser: msg.hiddenToUser ?? false,
|
|
930
|
+
userRating: msg.userRating ?? null,
|
|
931
|
+
userFeedback: msg.userFeedback ?? null,
|
|
932
|
+
reflectionInsights: msg.reflectionInsights ?? null,
|
|
933
|
+
summaryOfEarlierConveration: msg.summaryOfEarlierConveration ?? null,
|
|
934
|
+
}));
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* Check if a message is a delegation message that should be filtered out
|
|
939
|
+
* Uses flexible pattern matching to detect variations of delegation messages
|
|
940
|
+
*/
|
|
941
|
+
private isDelegationMessage(content: string): boolean {
|
|
942
|
+
if (!content) return false;
|
|
943
|
+
|
|
944
|
+
const lowerContent = content.toLowerCase();
|
|
945
|
+
|
|
946
|
+
// Check for both "delegating" or "delegate" AND "skip" in any order
|
|
947
|
+
const hasDelegatingOrDelegate = lowerContent.includes('delegating') || lowerContent.includes('delegate');
|
|
948
|
+
const hasSkip = lowerContent.includes('skip');
|
|
949
|
+
|
|
950
|
+
return hasDelegatingOrDelegate && hasSkip;
|
|
951
|
+
}
|
|
926
952
|
}
|