@memberjunction/server 2.1.2 → 2.1.3
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/apolloServer/TransactionPlugin.d.ts +4 -0
- package/dist/apolloServer/TransactionPlugin.d.ts.map +1 -0
- package/dist/apolloServer/TransactionPlugin.js +46 -0
- package/dist/apolloServer/TransactionPlugin.js.map +1 -0
- package/dist/apolloServer/index.d.ts +11 -0
- package/dist/apolloServer/index.d.ts.map +1 -0
- package/dist/apolloServer/index.js +25 -0
- package/dist/apolloServer/index.js.map +1 -0
- package/dist/auth/exampleNewUserSubClass.d.ts +6 -0
- package/dist/auth/exampleNewUserSubClass.d.ts.map +1 -0
- package/dist/auth/exampleNewUserSubClass.js +49 -0
- package/dist/auth/exampleNewUserSubClass.js.map +1 -0
- package/dist/auth/index.d.ts +30 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +121 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/newUsers.d.ts +5 -0
- package/dist/auth/newUsers.d.ts.map +1 -0
- package/{src/auth/newUsers.ts → dist/auth/newUsers.js} +20 -14
- package/dist/auth/newUsers.js.map +1 -0
- package/dist/auth/tokenExpiredError.d.ts +5 -0
- package/dist/auth/tokenExpiredError.d.ts.map +1 -0
- package/dist/auth/tokenExpiredError.js +12 -0
- package/dist/auth/tokenExpiredError.js.map +1 -0
- package/dist/cache.d.ts +3 -0
- package/dist/cache.d.ts.map +1 -0
- package/{src/cache.ts → dist/cache.js} +4 -6
- package/dist/cache.js.map +1 -0
- package/dist/config.d.ts +196 -0
- package/dist/config.d.ts.map +1 -0
- package/{src/config.ts → dist/config.js} +25 -49
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +17 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +84 -0
- package/dist/context.js.map +1 -0
- package/dist/directives/Public.d.ts +4 -0
- package/dist/directives/Public.d.ts.map +1 -0
- package/dist/directives/Public.js +30 -0
- package/dist/directives/Public.js.map +1 -0
- package/dist/directives/index.d.ts +2 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/directives/index.js +2 -0
- package/dist/directives/index.js.map +1 -0
- package/dist/entitySubclasses/DuplicateRunEntity.server.d.ts +6 -0
- package/dist/entitySubclasses/DuplicateRunEntity.server.d.ts.map +1 -0
- package/dist/entitySubclasses/DuplicateRunEntity.server.js +33 -0
- package/dist/entitySubclasses/DuplicateRunEntity.server.js.map +1 -0
- package/dist/entitySubclasses/entityPermissions.server.d.ts +23 -0
- package/dist/entitySubclasses/entityPermissions.server.d.ts.map +1 -0
- package/dist/entitySubclasses/entityPermissions.server.js +93 -0
- package/dist/entitySubclasses/entityPermissions.server.js.map +1 -0
- package/dist/entitySubclasses/userViewEntity.server.d.ts +13 -0
- package/dist/entitySubclasses/userViewEntity.server.d.ts.map +1 -0
- package/dist/entitySubclasses/userViewEntity.server.js +161 -0
- package/dist/entitySubclasses/userViewEntity.server.js.map +1 -0
- package/dist/generated/generated.d.ts +6679 -0
- package/dist/generated/generated.d.ts.map +1 -0
- package/dist/generated/generated.js +40786 -0
- package/dist/generated/generated.js.map +1 -0
- package/dist/generic/DeleteOptionsInput.d.ts +5 -0
- package/dist/generic/DeleteOptionsInput.d.ts.map +1 -0
- package/dist/generic/DeleteOptionsInput.js +27 -0
- package/dist/generic/DeleteOptionsInput.js.map +1 -0
- package/dist/generic/KeyInputOutputTypes.d.ts +16 -0
- package/dist/generic/KeyInputOutputTypes.d.ts.map +1 -0
- package/dist/generic/KeyInputOutputTypes.js +65 -0
- package/dist/generic/KeyInputOutputTypes.js.map +1 -0
- package/dist/generic/KeyValuePairInput.d.ts +5 -0
- package/dist/generic/KeyValuePairInput.d.ts.map +1 -0
- package/dist/generic/KeyValuePairInput.js +27 -0
- package/dist/generic/KeyValuePairInput.js.map +1 -0
- package/dist/generic/PushStatusResolver.d.ts +14 -0
- package/dist/generic/PushStatusResolver.d.ts.map +1 -0
- package/dist/generic/PushStatusResolver.js +58 -0
- package/dist/generic/PushStatusResolver.js.map +1 -0
- package/dist/generic/ResolverBase.d.ts +39 -0
- package/dist/generic/ResolverBase.d.ts.map +1 -0
- package/dist/generic/ResolverBase.js +573 -0
- package/dist/generic/ResolverBase.js.map +1 -0
- package/dist/generic/RunViewResolver.d.ts +123 -0
- package/dist/generic/RunViewResolver.d.ts.map +1 -0
- package/dist/generic/RunViewResolver.js +728 -0
- package/dist/generic/RunViewResolver.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +108 -0
- package/dist/index.js.map +1 -0
- package/dist/orm.d.ts +4 -0
- package/dist/orm.d.ts.map +1 -0
- package/dist/orm.js +32 -0
- package/dist/orm.js.map +1 -0
- package/dist/resolvers/AskSkipResolver.d.ts +54 -0
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -0
- package/dist/resolvers/AskSkipResolver.js +805 -0
- package/dist/resolvers/AskSkipResolver.js.map +1 -0
- package/dist/resolvers/ColorResolver.d.ts +23 -0
- package/dist/resolvers/ColorResolver.d.ts.map +1 -0
- package/dist/resolvers/ColorResolver.js +97 -0
- package/dist/resolvers/ColorResolver.js.map +1 -0
- package/dist/resolvers/DatasetResolver.d.ts +42 -0
- package/dist/resolvers/DatasetResolver.d.ts.map +1 -0
- package/dist/resolvers/DatasetResolver.js +179 -0
- package/dist/resolvers/DatasetResolver.js.map +1 -0
- package/dist/resolvers/EntityCommunicationsResolver.d.ts +50 -0
- package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -0
- package/dist/resolvers/EntityCommunicationsResolver.js +280 -0
- package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -0
- package/dist/resolvers/EntityRecordNameResolver.d.ts +21 -0
- package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -0
- package/dist/resolvers/EntityRecordNameResolver.js +117 -0
- package/dist/resolvers/EntityRecordNameResolver.js.map +1 -0
- package/dist/resolvers/EntityResolver.d.ts +6 -0
- package/dist/resolvers/EntityResolver.d.ts.map +1 -0
- package/dist/resolvers/EntityResolver.js +57 -0
- package/dist/resolvers/EntityResolver.js.map +1 -0
- package/dist/resolvers/FileCategoryResolver.d.ts +6 -0
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -0
- package/dist/resolvers/FileCategoryResolver.js +61 -0
- package/dist/resolvers/FileCategoryResolver.js.map +1 -0
- package/dist/resolvers/FileResolver.d.ts +24 -0
- package/dist/resolvers/FileResolver.d.ts.map +1 -0
- package/dist/resolvers/FileResolver.js +166 -0
- package/dist/resolvers/FileResolver.js.map +1 -0
- package/dist/resolvers/MergeRecordsResolver.d.ts +59 -0
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -0
- package/dist/resolvers/MergeRecordsResolver.js +282 -0
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -0
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts +29 -0
- package/dist/resolvers/PotentialDuplicateRecordResolver.d.ts.map +1 -0
- package/dist/resolvers/PotentialDuplicateRecordResolver.js +125 -0
- package/dist/resolvers/PotentialDuplicateRecordResolver.js.map +1 -0
- package/dist/resolvers/QueryResolver.d.ts +13 -0
- package/dist/resolvers/QueryResolver.d.ts.map +1 -0
- package/dist/resolvers/QueryResolver.js +77 -0
- package/dist/resolvers/QueryResolver.js.map +1 -0
- package/dist/resolvers/ReportResolver.d.ts +20 -0
- package/dist/resolvers/ReportResolver.d.ts.map +1 -0
- package/dist/resolvers/ReportResolver.js +182 -0
- package/dist/resolvers/ReportResolver.js.map +1 -0
- package/dist/resolvers/UserFavoriteResolver.d.ts +42 -0
- package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -0
- package/dist/resolvers/UserFavoriteResolver.js +230 -0
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts +10 -0
- package/dist/resolvers/UserResolver.d.ts.map +1 -0
- package/dist/resolvers/UserResolver.js +71 -0
- package/dist/resolvers/UserResolver.js.map +1 -0
- package/dist/resolvers/UserViewResolver.d.ts +13 -0
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -0
- package/dist/resolvers/UserViewResolver.js +99 -0
- package/dist/resolvers/UserViewResolver.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +4 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +85 -0
- package/dist/util.js.map +1 -0
- package/package.json +25 -21
- package/CHANGELOG.json +0 -3389
- package/CHANGELOG.md +0 -739
- package/src/apolloServer/TransactionPlugin.ts +0 -57
- package/src/apolloServer/index.ts +0 -33
- package/src/auth/exampleNewUserSubClass.ts +0 -74
- package/src/auth/index.ts +0 -151
- package/src/auth/tokenExpiredError.ts +0 -12
- package/src/context.ts +0 -111
- package/src/directives/Public.ts +0 -42
- package/src/directives/index.ts +0 -1
- package/src/entitySubclasses/DuplicateRunEntity.server.ts +0 -29
- package/src/entitySubclasses/entityPermissions.server.ts +0 -111
- package/src/entitySubclasses/userViewEntity.server.ts +0 -187
- package/src/generated/generated.ts +0 -25369
- package/src/generic/DeleteOptionsInput.ts +0 -13
- package/src/generic/KeyInputOutputTypes.ts +0 -35
- package/src/generic/KeyValuePairInput.ts +0 -14
- package/src/generic/PushStatusResolver.ts +0 -40
- package/src/generic/ResolverBase.ts +0 -767
- package/src/generic/RunViewResolver.ts +0 -582
- package/src/index.ts +0 -161
- package/src/orm.ts +0 -36
- package/src/resolvers/AskSkipResolver.ts +0 -926
- package/src/resolvers/ColorResolver.ts +0 -61
- package/src/resolvers/DatasetResolver.ts +0 -115
- package/src/resolvers/EntityCommunicationsResolver.ts +0 -216
- package/src/resolvers/EntityRecordNameResolver.ts +0 -78
- package/src/resolvers/EntityResolver.ts +0 -37
- package/src/resolvers/FileCategoryResolver.ts +0 -62
- package/src/resolvers/FileResolver.ts +0 -147
- package/src/resolvers/MergeRecordsResolver.ts +0 -182
- package/src/resolvers/PotentialDuplicateRecordResolver.ts +0 -91
- package/src/resolvers/QueryResolver.ts +0 -42
- package/src/resolvers/ReportResolver.ts +0 -147
- package/src/resolvers/UserFavoriteResolver.ts +0 -166
- package/src/resolvers/UserResolver.ts +0 -33
- package/src/resolvers/UserViewResolver.ts +0 -64
- package/src/types.ts +0 -40
- package/src/util.ts +0 -106
- package/tsconfig.json +0 -30
- package/typedoc.json +0 -4
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
var AskSkipResolver_1;
|
|
14
|
+
import { Arg, Ctx, Field, Int, ObjectType, PubSub, PubSubEngine, Query, Resolver } from 'type-graphql';
|
|
15
|
+
import { LogError, LogStatus, Metadata, RunView, CompositeKey } from '@memberjunction/core';
|
|
16
|
+
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
17
|
+
import { DataContext } from '@memberjunction/data-context';
|
|
18
|
+
import { LoadDataContextItemsServer } from '@memberjunction/data-context-server';
|
|
19
|
+
LoadDataContextItemsServer();
|
|
20
|
+
import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver';
|
|
21
|
+
import { ___skipAPIOrgId, ___skipAPIurl, configInfo, mj_core_schema } from '../config';
|
|
22
|
+
import { registerEnumType } from "type-graphql";
|
|
23
|
+
import { MJGlobal, CopyScalarsAndArrays } from '@memberjunction/global';
|
|
24
|
+
import { sendPostRequest } from '../util';
|
|
25
|
+
import { GetAIAPIKey } from '@memberjunction/ai';
|
|
26
|
+
import { CompositeKeyInputType } from '../generic/KeyInputOutputTypes';
|
|
27
|
+
var SkipResponsePhase;
|
|
28
|
+
(function (SkipResponsePhase) {
|
|
29
|
+
SkipResponsePhase["ClarifyingQuestion"] = "clarifying_question";
|
|
30
|
+
SkipResponsePhase["DataRequest"] = "data_request";
|
|
31
|
+
SkipResponsePhase["AnalysisComplete"] = "analysis_complete";
|
|
32
|
+
})(SkipResponsePhase || (SkipResponsePhase = {}));
|
|
33
|
+
registerEnumType(SkipResponsePhase, {
|
|
34
|
+
name: "SkipResponsePhase",
|
|
35
|
+
description: "The phase of the respons: clarifying_question, data_request, or analysis_complete",
|
|
36
|
+
});
|
|
37
|
+
let AskSkipResultType = class AskSkipResultType {
|
|
38
|
+
Success;
|
|
39
|
+
Status;
|
|
40
|
+
ResponsePhase;
|
|
41
|
+
Result;
|
|
42
|
+
ConversationId;
|
|
43
|
+
UserMessageConversationDetailId;
|
|
44
|
+
AIMessageConversationDetailId;
|
|
45
|
+
};
|
|
46
|
+
__decorate([
|
|
47
|
+
Field(() => Boolean),
|
|
48
|
+
__metadata("design:type", Boolean)
|
|
49
|
+
], AskSkipResultType.prototype, "Success", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
Field(() => String),
|
|
52
|
+
__metadata("design:type", String)
|
|
53
|
+
], AskSkipResultType.prototype, "Status", void 0);
|
|
54
|
+
__decorate([
|
|
55
|
+
Field(() => SkipResponsePhase),
|
|
56
|
+
__metadata("design:type", String)
|
|
57
|
+
], AskSkipResultType.prototype, "ResponsePhase", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
Field(() => String),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], AskSkipResultType.prototype, "Result", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
Field(() => Int),
|
|
64
|
+
__metadata("design:type", String)
|
|
65
|
+
], AskSkipResultType.prototype, "ConversationId", void 0);
|
|
66
|
+
__decorate([
|
|
67
|
+
Field(() => Int),
|
|
68
|
+
__metadata("design:type", String)
|
|
69
|
+
], AskSkipResultType.prototype, "UserMessageConversationDetailId", void 0);
|
|
70
|
+
__decorate([
|
|
71
|
+
Field(() => Int),
|
|
72
|
+
__metadata("design:type", String)
|
|
73
|
+
], AskSkipResultType.prototype, "AIMessageConversationDetailId", void 0);
|
|
74
|
+
AskSkipResultType = __decorate([
|
|
75
|
+
ObjectType()
|
|
76
|
+
], AskSkipResultType);
|
|
77
|
+
export { AskSkipResultType };
|
|
78
|
+
let AskSkipResolver = class AskSkipResolver {
|
|
79
|
+
static { AskSkipResolver_1 = this; }
|
|
80
|
+
static _defaultNewChatName = 'New Chat';
|
|
81
|
+
static _maxHistoricalMessages = 20;
|
|
82
|
+
async ExecuteAskSkipRecordChat(UserQuestion, ConversationId, EntityName, compositeKey, { dataSource, userPayload }, pubSub) {
|
|
83
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email.trim().toLowerCase());
|
|
84
|
+
if (!user)
|
|
85
|
+
throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
86
|
+
const messages = await this.LoadConversationDetailsIntoSkipMessages(dataSource, ConversationId, AskSkipResolver_1._maxHistoricalMessages);
|
|
87
|
+
const md = new Metadata();
|
|
88
|
+
const { convoEntity, dataContextEntity, convoDetailEntity, dataContext } = await this.HandleSkipInitialObjectLoading(dataSource, ConversationId, UserQuestion, user, userPayload, md, null);
|
|
89
|
+
if (!ConversationId || ConversationId.length === 0) {
|
|
90
|
+
const dci = await md.GetEntityObject('Data Context Items', user);
|
|
91
|
+
dci.DataContextID = dataContext.ID;
|
|
92
|
+
dci.Type = 'single_record';
|
|
93
|
+
dci.EntityID = md.Entities.find((e) => e.Name === EntityName)?.ID;
|
|
94
|
+
const ck = new CompositeKey();
|
|
95
|
+
ck.KeyValuePairs = compositeKey.KeyValuePairs;
|
|
96
|
+
dci.RecordID = ck.Values();
|
|
97
|
+
let dciSaveResult = await dci.Save();
|
|
98
|
+
if (!dciSaveResult) {
|
|
99
|
+
LogError(`Error saving DataContextItemEntity for record chat: ${EntityName} ${ck.Values()}`, undefined, dci.LatestResult);
|
|
100
|
+
}
|
|
101
|
+
await dataContext.Load(dataContext.ID, dataSource, false, true, 10, user);
|
|
102
|
+
await dataContext.SaveItems(user, true);
|
|
103
|
+
convoEntity.LinkedEntityID = dci.EntityID;
|
|
104
|
+
convoEntity.LinkedRecordID = ck.Values();
|
|
105
|
+
convoEntity.DataContextID = dataContext.ID;
|
|
106
|
+
const convoEntitySaveResult = await convoEntity.Save();
|
|
107
|
+
if (!convoEntitySaveResult) {
|
|
108
|
+
LogError(`Error saving ConversationEntity for record chat: ${EntityName} ${ck.Values()}`, undefined, convoEntity.LatestResult);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const input = this.buildSkipAPIRequest(messages, ConversationId, dataContext, 'chat_with_a_record', false, false);
|
|
112
|
+
messages.push({
|
|
113
|
+
content: UserQuestion,
|
|
114
|
+
role: 'user'
|
|
115
|
+
});
|
|
116
|
+
return this.handleSimpleSkipPostRequest(input, convoEntity.ID, convoDetailEntity.ID, true, user);
|
|
117
|
+
}
|
|
118
|
+
async handleSimpleSkipPostRequest(input, conversationID = "", UserMessageConversationDetailId = "", createAIMessageConversationDetail = false, user = null) {
|
|
119
|
+
LogStatus(` >>> HandleSimpleSkipPostRequest Sending request to Skip API: ${___skipAPIurl}`);
|
|
120
|
+
const response = await sendPostRequest(___skipAPIurl, input, true, null);
|
|
121
|
+
if (response && response.length > 0) {
|
|
122
|
+
const apiResponse = response[response.length - 1].value;
|
|
123
|
+
const AIMessageConversationDetailID = createAIMessageConversationDetail ? await this.CreateAIMessageConversationDetail(apiResponse, conversationID, user) : "";
|
|
124
|
+
LogStatus(` Skip API response: ${apiResponse.responsePhase}`);
|
|
125
|
+
return {
|
|
126
|
+
Success: true,
|
|
127
|
+
Status: 'OK',
|
|
128
|
+
ResponsePhase: SkipResponsePhase.AnalysisComplete,
|
|
129
|
+
ConversationId: conversationID,
|
|
130
|
+
UserMessageConversationDetailId: UserMessageConversationDetailId,
|
|
131
|
+
AIMessageConversationDetailId: AIMessageConversationDetailID,
|
|
132
|
+
Result: JSON.stringify(apiResponse)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
return {
|
|
137
|
+
Success: false,
|
|
138
|
+
Status: 'Error',
|
|
139
|
+
Result: `Request failed`,
|
|
140
|
+
ResponsePhase: SkipResponsePhase.AnalysisComplete,
|
|
141
|
+
ConversationId: conversationID,
|
|
142
|
+
UserMessageConversationDetailId: UserMessageConversationDetailId,
|
|
143
|
+
AIMessageConversationDetailId: "",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async CreateAIMessageConversationDetail(apiResponse, conversationID, user) {
|
|
148
|
+
const md = new Metadata();
|
|
149
|
+
const convoDetailEntityAI = await md.GetEntityObject('Conversation Details', user);
|
|
150
|
+
convoDetailEntityAI.NewRecord();
|
|
151
|
+
convoDetailEntityAI.HiddenToUser = false;
|
|
152
|
+
convoDetailEntityAI.ConversationID = conversationID;
|
|
153
|
+
const systemMessages = apiResponse.messages.filter((m) => m.role === 'system');
|
|
154
|
+
const lastSystemMessage = systemMessages[systemMessages.length - 1];
|
|
155
|
+
convoDetailEntityAI.Message = lastSystemMessage?.content;
|
|
156
|
+
convoDetailEntityAI.Role = 'AI';
|
|
157
|
+
if (await convoDetailEntityAI.Save()) {
|
|
158
|
+
return convoDetailEntityAI.ID;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
LogError(`Error saving conversation detail entity for AI message: ${lastSystemMessage?.content}`, undefined, convoDetailEntityAI.LatestResult);
|
|
162
|
+
return "";
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
buildSkipAPIRequest(messages, conversationId, dataContext, requestPhase, includeEntities, includeQueries) {
|
|
166
|
+
const entities = includeEntities ? this.BuildSkipEntities() : [];
|
|
167
|
+
const queries = includeQueries ? this.BuildSkipQueries() : [];
|
|
168
|
+
const input = {
|
|
169
|
+
apiKeys: this.buildSkipAPIKeys(),
|
|
170
|
+
organizationInfo: configInfo?.askSkip?.organizationInfo,
|
|
171
|
+
messages: messages,
|
|
172
|
+
conversationID: conversationId.toString(),
|
|
173
|
+
dataContext: CopyScalarsAndArrays(dataContext),
|
|
174
|
+
organizationID: ___skipAPIOrgId,
|
|
175
|
+
requestPhase: requestPhase,
|
|
176
|
+
entities: entities,
|
|
177
|
+
queries: queries
|
|
178
|
+
};
|
|
179
|
+
return input;
|
|
180
|
+
}
|
|
181
|
+
async ExecuteAskSkipRunScript({ dataSource, userPayload }, pubSub, DataContextId, ScriptText) {
|
|
182
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email.trim().toLowerCase());
|
|
183
|
+
if (!user)
|
|
184
|
+
throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
185
|
+
const dataContext = new DataContext();
|
|
186
|
+
await dataContext.Load(DataContextId, dataSource, true, false, 0, user);
|
|
187
|
+
const input = this.buildSkipAPIRequest([], "", dataContext, 'run_existing_script', false, false);
|
|
188
|
+
return this.handleSimpleSkipPostRequest(input);
|
|
189
|
+
}
|
|
190
|
+
buildSkipAPIKeys() {
|
|
191
|
+
return [
|
|
192
|
+
{
|
|
193
|
+
vendorDriverName: 'OpenAILLM',
|
|
194
|
+
apiKey: GetAIAPIKey('OpenAILLM')
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
vendorDriverName: 'AnthropicLLM',
|
|
198
|
+
apiKey: GetAIAPIKey('AnthropicLLM')
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
vendorDriverName: 'GeminiLLM',
|
|
202
|
+
apiKey: GetAIAPIKey('GeminiLLM')
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
vendorDriverName: 'GroqLLM',
|
|
206
|
+
apiKey: GetAIAPIKey('GroqLLM')
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
vendorDriverName: 'MistralLLM',
|
|
210
|
+
apiKey: GetAIAPIKey('MistralLLM')
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
}
|
|
214
|
+
async ExecuteAskSkipAnalysisQuery(UserQuestion, ConversationId, { dataSource, userPayload }, pubSub, DataContextId) {
|
|
215
|
+
const md = new Metadata();
|
|
216
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email.trim().toLowerCase());
|
|
217
|
+
if (!user)
|
|
218
|
+
throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
219
|
+
const { convoEntity, dataContextEntity, convoDetailEntity, dataContext } = await this.HandleSkipInitialObjectLoading(dataSource, ConversationId, UserQuestion, user, userPayload, md, DataContextId);
|
|
220
|
+
const messages = await this.LoadConversationDetailsIntoSkipMessages(dataSource, convoEntity.ID, AskSkipResolver_1._maxHistoricalMessages);
|
|
221
|
+
const input = this.buildSkipAPIRequest(messages, ConversationId, dataContext, 'initial_request', true, true);
|
|
222
|
+
return this.HandleSkipRequest(input, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, md, convoEntity, convoDetailEntity, dataContext, dataContextEntity);
|
|
223
|
+
}
|
|
224
|
+
BuildSkipQueries() {
|
|
225
|
+
const md = new Metadata();
|
|
226
|
+
return md.Queries.map((q) => {
|
|
227
|
+
return {
|
|
228
|
+
id: q.ID,
|
|
229
|
+
name: q.Name,
|
|
230
|
+
description: q.Description,
|
|
231
|
+
category: q.Category,
|
|
232
|
+
sql: q.SQL,
|
|
233
|
+
originalSQL: q.OriginalSQL,
|
|
234
|
+
feedback: q.Feedback,
|
|
235
|
+
status: q.Status,
|
|
236
|
+
qualityRank: q.QualityRank,
|
|
237
|
+
createdAt: q.__mj_CreatedAt,
|
|
238
|
+
updatedAt: q.__mj_UpdatedAt,
|
|
239
|
+
categoryID: q.CategoryID,
|
|
240
|
+
fields: q.Fields.map((f) => {
|
|
241
|
+
return {
|
|
242
|
+
id: f.ID,
|
|
243
|
+
queryID: f.QueryID,
|
|
244
|
+
sequence: f.Sequence,
|
|
245
|
+
name: f.Name,
|
|
246
|
+
description: f.Description,
|
|
247
|
+
sqlBaseType: f.SQLBaseType,
|
|
248
|
+
sqlFullType: f.SQLFullType,
|
|
249
|
+
sourceEntityID: f.SourceEntityID,
|
|
250
|
+
sourceEntity: f.SourceEntity,
|
|
251
|
+
sourceFieldName: f.SourceFieldName,
|
|
252
|
+
isComputed: f.IsComputed,
|
|
253
|
+
computationDescription: f.ComputationDescription,
|
|
254
|
+
isSummary: f.IsSummary,
|
|
255
|
+
summaryDescription: f.SummaryDescription,
|
|
256
|
+
createdAt: f.__mj_CreatedAt,
|
|
257
|
+
updatedAt: f.__mj_UpdatedAt,
|
|
258
|
+
};
|
|
259
|
+
})
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
BuildSkipEntities() {
|
|
264
|
+
const md = new Metadata();
|
|
265
|
+
return md.Entities.filter(e => e.SchemaName !== mj_core_schema).map((e) => {
|
|
266
|
+
const ret = {
|
|
267
|
+
id: e.ID,
|
|
268
|
+
name: e.Name,
|
|
269
|
+
schemaName: e.SchemaName,
|
|
270
|
+
baseView: e.BaseView,
|
|
271
|
+
description: e.Description,
|
|
272
|
+
fields: e.Fields.map((f) => {
|
|
273
|
+
return {
|
|
274
|
+
id: f.ID,
|
|
275
|
+
entityID: f.EntityID,
|
|
276
|
+
sequence: f.Sequence,
|
|
277
|
+
name: f.Name,
|
|
278
|
+
displayName: f.DisplayName,
|
|
279
|
+
category: f.Category,
|
|
280
|
+
type: f.Type,
|
|
281
|
+
description: f.Description,
|
|
282
|
+
isPrimaryKey: f.IsPrimaryKey,
|
|
283
|
+
allowsNull: f.AllowsNull,
|
|
284
|
+
isUnique: f.IsUnique,
|
|
285
|
+
length: f.Length,
|
|
286
|
+
precision: f.Precision,
|
|
287
|
+
scale: f.Scale,
|
|
288
|
+
sqlFullType: f.SQLFullType,
|
|
289
|
+
defaultValue: f.DefaultValue,
|
|
290
|
+
autoIncrement: f.AutoIncrement,
|
|
291
|
+
valueListType: f.ValueListType,
|
|
292
|
+
extendedType: f.ExtendedType,
|
|
293
|
+
defaultInView: f.DefaultInView,
|
|
294
|
+
defaultColumnWidth: f.DefaultColumnWidth,
|
|
295
|
+
isVirtual: f.IsVirtual,
|
|
296
|
+
isNameField: f.IsNameField,
|
|
297
|
+
relatedEntityID: f.RelatedEntityID,
|
|
298
|
+
relatedEntityFieldName: f.RelatedEntityFieldName,
|
|
299
|
+
relatedEntity: f.RelatedEntity,
|
|
300
|
+
relatedEntitySchemaName: f.RelatedEntitySchemaName,
|
|
301
|
+
relatedEntityBaseView: f.RelatedEntityBaseView,
|
|
302
|
+
};
|
|
303
|
+
}),
|
|
304
|
+
relatedEntities: e.RelatedEntities.map((r) => {
|
|
305
|
+
return {
|
|
306
|
+
entityID: r.EntityID,
|
|
307
|
+
relatedEntityID: r.RelatedEntityID,
|
|
308
|
+
type: r.Type,
|
|
309
|
+
entityKeyField: r.EntityKeyField,
|
|
310
|
+
relatedEntityJoinField: r.RelatedEntityJoinField,
|
|
311
|
+
joinView: r.JoinView,
|
|
312
|
+
joinEntityJoinField: r.JoinEntityJoinField,
|
|
313
|
+
joinEntityInverseJoinField: r.JoinEntityInverseJoinField,
|
|
314
|
+
entity: r.Entity,
|
|
315
|
+
entityBaseView: r.EntityBaseView,
|
|
316
|
+
relatedEntity: r.RelatedEntity,
|
|
317
|
+
relatedEntityBaseView: r.RelatedEntityBaseView,
|
|
318
|
+
};
|
|
319
|
+
})
|
|
320
|
+
};
|
|
321
|
+
return ret;
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
async HandleSkipInitialObjectLoading(dataSource, ConversationId, UserQuestion, user, userPayload, md, DataContextId) {
|
|
325
|
+
const convoEntity = await md.GetEntityObject('Conversations', user);
|
|
326
|
+
let dataContextEntity;
|
|
327
|
+
if (!ConversationId || ConversationId.length === 0) {
|
|
328
|
+
convoEntity.NewRecord();
|
|
329
|
+
if (user) {
|
|
330
|
+
convoEntity.UserID = user.ID;
|
|
331
|
+
convoEntity.Name = AskSkipResolver_1._defaultNewChatName;
|
|
332
|
+
dataContextEntity = await md.GetEntityObject('Data Contexts', user);
|
|
333
|
+
if (!DataContextId || DataContextId.length === 0) {
|
|
334
|
+
dataContextEntity.NewRecord();
|
|
335
|
+
dataContextEntity.UserID = user.ID;
|
|
336
|
+
dataContextEntity.Name = 'Data Context for Skip Conversation';
|
|
337
|
+
if (!await dataContextEntity.Save()) {
|
|
338
|
+
LogError(`Creating a new data context failed`, undefined, dataContextEntity.LatestResult);
|
|
339
|
+
throw new Error(`Creating a new data context failed`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
const dcLoadResult = await dataContextEntity.Load(DataContextId);
|
|
344
|
+
if (!dcLoadResult) {
|
|
345
|
+
throw new Error(`Loading DataContextEntity for DataContextId ${DataContextId} failed`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
convoEntity.DataContextID = dataContextEntity.ID;
|
|
349
|
+
if (await convoEntity.Save()) {
|
|
350
|
+
ConversationId = convoEntity.ID;
|
|
351
|
+
if (!DataContextId || dataContextEntity.ID.length === 0) {
|
|
352
|
+
dataContextEntity.Name += ` ${ConversationId}`;
|
|
353
|
+
const dciSaveResult = await dataContextEntity.Save();
|
|
354
|
+
if (!dciSaveResult) {
|
|
355
|
+
LogError(`Error saving DataContextEntity for conversation: ${ConversationId}`, undefined, dataContextEntity.LatestResult);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
LogError(`Creating a new conversation failed`, undefined, convoEntity.LatestResult);
|
|
361
|
+
throw new Error(`Creating a new conversation failed`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
throw new Error(`User ${userPayload.email} not found in UserCache`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
await convoEntity.Load(ConversationId);
|
|
370
|
+
dataContextEntity = await md.GetEntityObject('Data Contexts', user);
|
|
371
|
+
if (DataContextId && DataContextId.length > 0 && DataContextId !== convoEntity.DataContextID) {
|
|
372
|
+
if (convoEntity.DataContextID === null) {
|
|
373
|
+
convoEntity.DataContextID = DataContextId;
|
|
374
|
+
const convoEntitySaveResult = await convoEntity.Save();
|
|
375
|
+
if (!convoEntitySaveResult) {
|
|
376
|
+
LogError(`Error saving conversation entity for conversation: ${ConversationId}`, undefined, convoEntity.LatestResult);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
else
|
|
380
|
+
console.warn(`AskSkipResolver: DataContextId ${DataContextId} was passed in but it was ignored because it was different than the DataContextID in the conversation ${convoEntity.DataContextID}`);
|
|
381
|
+
}
|
|
382
|
+
await dataContextEntity.Load(convoEntity.DataContextID);
|
|
383
|
+
}
|
|
384
|
+
const convoDetailEntity = await md.GetEntityObject('Conversation Details', user);
|
|
385
|
+
convoDetailEntity.NewRecord();
|
|
386
|
+
convoDetailEntity.ConversationID = ConversationId;
|
|
387
|
+
convoDetailEntity.Message = UserQuestion;
|
|
388
|
+
convoDetailEntity.Role = 'User';
|
|
389
|
+
convoDetailEntity.HiddenToUser = false;
|
|
390
|
+
convoDetailEntity.Set('Sequence', 1);
|
|
391
|
+
let convoDetailSaveResult = await convoDetailEntity.Save();
|
|
392
|
+
if (!convoDetailSaveResult) {
|
|
393
|
+
LogError(`Error saving conversation detail entity for user message: ${UserQuestion}`, undefined, convoDetailEntity.LatestResult);
|
|
394
|
+
}
|
|
395
|
+
const dataContext = MJGlobal.Instance.ClassFactory.CreateInstance(DataContext);
|
|
396
|
+
await dataContext.Load(dataContextEntity.ID, dataSource, false, false, 0, user);
|
|
397
|
+
return { dataContext, convoEntity, dataContextEntity, convoDetailEntity };
|
|
398
|
+
}
|
|
399
|
+
async LoadConversationDetailsIntoSkipMessages(dataSource, ConversationId, maxHistoricalMessages) {
|
|
400
|
+
try {
|
|
401
|
+
const md = new Metadata();
|
|
402
|
+
const e = md.Entities.find((e) => e.Name === 'Conversation Details');
|
|
403
|
+
const sql = `SELECT
|
|
404
|
+
${maxHistoricalMessages ? 'TOP ' + maxHistoricalMessages : ''} ID, Message, Role, __mj_CreatedAt
|
|
405
|
+
FROM
|
|
406
|
+
${e.SchemaName}.${e.BaseView}
|
|
407
|
+
WHERE
|
|
408
|
+
ConversationID = '${ConversationId}'
|
|
409
|
+
ORDER
|
|
410
|
+
BY __mj_CreatedAt DESC`;
|
|
411
|
+
const result = await dataSource.query(sql);
|
|
412
|
+
if (!result)
|
|
413
|
+
throw new Error(`Error running SQL: ${sql}`);
|
|
414
|
+
else {
|
|
415
|
+
const returnData = result.sort((a, b) => {
|
|
416
|
+
const aDate = new Date(a.__mj_CreatedAt);
|
|
417
|
+
const bDate = new Date(b.__mj_CreatedAt);
|
|
418
|
+
return aDate.getTime() - bDate.getTime();
|
|
419
|
+
});
|
|
420
|
+
return returnData.map((r) => {
|
|
421
|
+
const skipRole = this.MapDBRoleToSkipRole(r.Role);
|
|
422
|
+
let outputMessage;
|
|
423
|
+
if (skipRole === 'system') {
|
|
424
|
+
let detail;
|
|
425
|
+
try {
|
|
426
|
+
detail = JSON.parse(r.Message);
|
|
427
|
+
}
|
|
428
|
+
catch (e) {
|
|
429
|
+
detail = null;
|
|
430
|
+
outputMessage = r.Message;
|
|
431
|
+
}
|
|
432
|
+
if (detail?.responsePhase === SkipResponsePhase.AnalysisComplete) {
|
|
433
|
+
const analysisDetail = detail;
|
|
434
|
+
outputMessage = JSON.stringify({
|
|
435
|
+
responsePhase: SkipResponsePhase.AnalysisComplete,
|
|
436
|
+
techExplanation: analysisDetail.techExplanation,
|
|
437
|
+
userExplanation: analysisDetail.userExplanation,
|
|
438
|
+
scriptText: analysisDetail.scriptText,
|
|
439
|
+
tableDataColumns: analysisDetail.tableDataColumns
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
else if (detail?.responsePhase === SkipResponsePhase.ClarifyingQuestion) {
|
|
443
|
+
const clarifyingQuestionDetail = detail;
|
|
444
|
+
outputMessage = JSON.stringify({
|
|
445
|
+
responsePhase: SkipResponsePhase.ClarifyingQuestion,
|
|
446
|
+
clarifyingQuestion: clarifyingQuestionDetail.clarifyingQuestion
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
else if (detail) {
|
|
450
|
+
LogError(`Unknown response phase: ${detail.responsePhase}`);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const m = {
|
|
454
|
+
content: skipRole === 'system' ? outputMessage : r.Message,
|
|
455
|
+
role: skipRole,
|
|
456
|
+
};
|
|
457
|
+
return m;
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
catch (e) {
|
|
462
|
+
LogError(e);
|
|
463
|
+
throw e;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
MapDBRoleToSkipRole(role) {
|
|
467
|
+
switch (role.trim().toLowerCase()) {
|
|
468
|
+
case 'ai':
|
|
469
|
+
case 'system':
|
|
470
|
+
case 'assistant':
|
|
471
|
+
return 'system';
|
|
472
|
+
default:
|
|
473
|
+
return 'user';
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
async HandleSkipRequest(input, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, md, convoEntity, convoDetailEntity, dataContext, dataContextEntity) {
|
|
477
|
+
LogStatus(` >>> HandleSkipRequest: Sending request to Skip API: ${___skipAPIurl}`);
|
|
478
|
+
const response = await sendPostRequest(___skipAPIurl, input, true, null, (message) => {
|
|
479
|
+
LogStatus(JSON.stringify(message, null, 4));
|
|
480
|
+
if (message.type === 'status_update') {
|
|
481
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
482
|
+
message: JSON.stringify({
|
|
483
|
+
type: 'AskSkip',
|
|
484
|
+
status: 'OK',
|
|
485
|
+
conversationID: ConversationId,
|
|
486
|
+
ResponsePhase: message.value.responsePhase,
|
|
487
|
+
message: message.value.messages[0].content
|
|
488
|
+
}),
|
|
489
|
+
sessionId: userPayload.sessionId
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
if (response && response.length > 0) {
|
|
494
|
+
const apiResponse = response[response.length - 1].value;
|
|
495
|
+
LogStatus(` Skip API response: ${apiResponse.responsePhase}`);
|
|
496
|
+
this.PublishApiResponseUserUpdateMessage(apiResponse, userPayload, ConversationId, pubSub);
|
|
497
|
+
if (apiResponse.responsePhase === 'data_request') {
|
|
498
|
+
return await this.HandleDataRequestPhase(input, apiResponse, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, convoEntity, convoDetailEntity, dataContext, dataContextEntity);
|
|
499
|
+
}
|
|
500
|
+
else if (apiResponse.responsePhase === 'clarifying_question') {
|
|
501
|
+
return await this.HandleClarifyingQuestionPhase(input, apiResponse, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, convoEntity, convoDetailEntity);
|
|
502
|
+
}
|
|
503
|
+
else if (apiResponse.responsePhase === 'analysis_complete') {
|
|
504
|
+
return await this.HandleAnalysisComplete(input, apiResponse, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, convoEntity, convoDetailEntity, dataContext, dataContextEntity);
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
throw new Error(`Unknown Skip API response phase: ${apiResponse.responsePhase}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
512
|
+
message: JSON.stringify({
|
|
513
|
+
type: 'AskSkip',
|
|
514
|
+
status: 'Error',
|
|
515
|
+
conversationID: ConversationId,
|
|
516
|
+
message: 'Analysis failed to run, please try again later and if this continues, contact your support desk.',
|
|
517
|
+
}),
|
|
518
|
+
sessionId: userPayload.sessionId
|
|
519
|
+
});
|
|
520
|
+
return {
|
|
521
|
+
Success: false,
|
|
522
|
+
Status: 'Error',
|
|
523
|
+
Result: `User Question ${UserQuestion} didn't work!`,
|
|
524
|
+
ResponsePhase: SkipResponsePhase.AnalysisComplete,
|
|
525
|
+
ConversationId: ConversationId,
|
|
526
|
+
UserMessageConversationDetailId: "",
|
|
527
|
+
AIMessageConversationDetailId: "",
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
async PublishApiResponseUserUpdateMessage(apiResponse, userPayload, conversationID, pubSub) {
|
|
532
|
+
let sUserMessage = '';
|
|
533
|
+
switch (apiResponse.responsePhase) {
|
|
534
|
+
case 'data_request':
|
|
535
|
+
sUserMessage = 'We need to gather some more data, I will do that next and update you soon.';
|
|
536
|
+
break;
|
|
537
|
+
case 'analysis_complete':
|
|
538
|
+
sUserMessage = 'I have completed the analysis, the results will be available momentarily.';
|
|
539
|
+
break;
|
|
540
|
+
case 'clarifying_question':
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
544
|
+
message: JSON.stringify({
|
|
545
|
+
type: 'AskSkip',
|
|
546
|
+
status: 'OK',
|
|
547
|
+
conversationID,
|
|
548
|
+
message: sUserMessage,
|
|
549
|
+
}),
|
|
550
|
+
sessionId: userPayload.sessionId
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
async HandleAnalysisComplete(apiRequest, apiResponse, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, convoEntity, convoDetailEntity, dataContext, dataContextEntity) {
|
|
554
|
+
const md = new Metadata();
|
|
555
|
+
const { AIMessageConversationDetailID } = await this.FinishConversationAndNotifyUser(apiResponse, dataContext, dataContextEntity, md, user, convoEntity, pubSub, userPayload);
|
|
556
|
+
const response = {
|
|
557
|
+
Success: true,
|
|
558
|
+
Status: 'OK',
|
|
559
|
+
ResponsePhase: SkipResponsePhase.AnalysisComplete,
|
|
560
|
+
ConversationId: ConversationId,
|
|
561
|
+
UserMessageConversationDetailId: convoDetailEntity.ID,
|
|
562
|
+
AIMessageConversationDetailId: AIMessageConversationDetailID,
|
|
563
|
+
Result: JSON.stringify(apiResponse)
|
|
564
|
+
};
|
|
565
|
+
return response;
|
|
566
|
+
}
|
|
567
|
+
async HandleClarifyingQuestionPhase(apiRequest, apiResponse, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, convoEntity, convoDetailEntity) {
|
|
568
|
+
const md = new Metadata();
|
|
569
|
+
const convoDetailEntityAI = await md.GetEntityObject('Conversation Details', user);
|
|
570
|
+
convoDetailEntityAI.NewRecord();
|
|
571
|
+
convoDetailEntityAI.ConversationID = ConversationId;
|
|
572
|
+
convoDetailEntityAI.Message = JSON.stringify(apiResponse);
|
|
573
|
+
convoDetailEntityAI.Role = 'AI';
|
|
574
|
+
convoDetailEntityAI.HiddenToUser = false;
|
|
575
|
+
if (await convoDetailEntityAI.Save()) {
|
|
576
|
+
return {
|
|
577
|
+
Success: true,
|
|
578
|
+
Status: 'OK',
|
|
579
|
+
ResponsePhase: SkipResponsePhase.ClarifyingQuestion,
|
|
580
|
+
ConversationId: ConversationId,
|
|
581
|
+
UserMessageConversationDetailId: convoDetailEntity.ID,
|
|
582
|
+
AIMessageConversationDetailId: convoDetailEntityAI.ID,
|
|
583
|
+
Result: JSON.stringify(apiResponse)
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
LogError(`Error saving conversation detail entity for AI message: ${apiResponse.clarifyingQuestion}`, undefined, convoDetailEntityAI.LatestResult);
|
|
588
|
+
return {
|
|
589
|
+
Success: false,
|
|
590
|
+
Status: 'Error',
|
|
591
|
+
ResponsePhase: SkipResponsePhase.ClarifyingQuestion,
|
|
592
|
+
ConversationId: ConversationId,
|
|
593
|
+
UserMessageConversationDetailId: convoDetailEntity.ID,
|
|
594
|
+
AIMessageConversationDetailId: convoDetailEntityAI.ID,
|
|
595
|
+
Result: JSON.stringify(apiResponse)
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
async HandleDataRequestPhase(apiRequest, apiResponse, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, convoEntity, convoDetailEntity, dataContext, dataContextEntity) {
|
|
600
|
+
try {
|
|
601
|
+
if (!apiResponse.success) {
|
|
602
|
+
LogError(`Data request/gathering from Skip API failed: ${apiResponse.error}`);
|
|
603
|
+
return {
|
|
604
|
+
Success: false,
|
|
605
|
+
Status: `The Skip API Server data gathering phase returned a non-recoverable error. Try again later and Skip might be able to handle this request.\n${apiResponse.error}`,
|
|
606
|
+
ResponsePhase: SkipResponsePhase.DataRequest,
|
|
607
|
+
ConversationId: ConversationId,
|
|
608
|
+
UserMessageConversationDetailId: convoDetailEntity.ID,
|
|
609
|
+
AIMessageConversationDetailId: "",
|
|
610
|
+
Result: JSON.stringify(apiResponse)
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
const _maxDataGatheringRetries = 5;
|
|
614
|
+
const _dataGatheringFailureHeaderMessage = '***DATA GATHERING FAILURE***';
|
|
615
|
+
const md = new Metadata();
|
|
616
|
+
const executionErrors = [];
|
|
617
|
+
let dataRequest = apiResponse.dataRequest;
|
|
618
|
+
apiRequest.messages.push({
|
|
619
|
+
content: `Skip API Requested Data as shown below
|
|
620
|
+
${JSON.stringify(apiResponse.dataRequest)}`,
|
|
621
|
+
role: 'system'
|
|
622
|
+
});
|
|
623
|
+
if (!Array.isArray(dataRequest)) {
|
|
624
|
+
if (dataRequest) {
|
|
625
|
+
dataRequest = [dataRequest];
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
const errorMessage = `Data request from Skip API is not an array and not a single item.`;
|
|
629
|
+
LogError(errorMessage);
|
|
630
|
+
executionErrors.push({ dataRequest: apiResponse.dataRequest, errorMessage: errorMessage });
|
|
631
|
+
dataRequest = [];
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
for (const dr of dataRequest) {
|
|
635
|
+
try {
|
|
636
|
+
const item = dataContext.AddDataContextItem();
|
|
637
|
+
switch (dr.type) {
|
|
638
|
+
case "sql":
|
|
639
|
+
item.Type = 'sql';
|
|
640
|
+
item.SQL = dr.text;
|
|
641
|
+
item.AdditionalDescription = dr.description;
|
|
642
|
+
if (!await item.LoadData(dataSource, false, false, 0, user))
|
|
643
|
+
throw new Error(`SQL data request failed: ${item.DataLoadingError}`);
|
|
644
|
+
break;
|
|
645
|
+
case "stored_query":
|
|
646
|
+
const queryName = dr.text;
|
|
647
|
+
const query = md.Queries.find((q) => q.Name === queryName);
|
|
648
|
+
if (query) {
|
|
649
|
+
item.Type = 'query';
|
|
650
|
+
item.QueryID = query.ID;
|
|
651
|
+
item.RecordName = query.Name;
|
|
652
|
+
item.AdditionalDescription = dr.description;
|
|
653
|
+
if (!await item.LoadData(dataSource, false, false, 0, user))
|
|
654
|
+
throw new Error(`SQL data request failed: ${item.DataLoadingError}`);
|
|
655
|
+
}
|
|
656
|
+
else
|
|
657
|
+
throw new Error(`Query ${queryName} not found.`);
|
|
658
|
+
break;
|
|
659
|
+
default:
|
|
660
|
+
throw new Error(`Unknown data request type: ${dr.type}`);
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
catch (e) {
|
|
665
|
+
LogError(e);
|
|
666
|
+
executionErrors.push({ dataRequest: dr, errorMessage: e && e.message ? e.message : e.toString() });
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
if (executionErrors.length > 0) {
|
|
670
|
+
const dataGatheringFailedAttemptCount = apiRequest.messages.filter((m) => m.content.includes(_dataGatheringFailureHeaderMessage)).length + 1;
|
|
671
|
+
if (dataGatheringFailedAttemptCount > _maxDataGatheringRetries) {
|
|
672
|
+
LogStatus(`Execution errors for Skip data request occured, and we have exceeded the max retries${_maxDataGatheringRetries}, sending errors back to the user.`);
|
|
673
|
+
return {
|
|
674
|
+
Success: false,
|
|
675
|
+
Status: 'Error gathering data and we have exceedded the max retries. Try again later and Skip might be able to handle this request.',
|
|
676
|
+
ResponsePhase: SkipResponsePhase.DataRequest,
|
|
677
|
+
ConversationId: ConversationId,
|
|
678
|
+
UserMessageConversationDetailId: convoDetailEntity.ID,
|
|
679
|
+
AIMessageConversationDetailId: "",
|
|
680
|
+
Result: JSON.stringify(apiResponse)
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
LogStatus(`Execution errors for Skip data request occured, sending those errors back to the Skip API to get new instructions.`);
|
|
685
|
+
apiRequest.requestPhase = 'data_gathering_failure';
|
|
686
|
+
apiRequest.messages.push({
|
|
687
|
+
content: `${_dataGatheringFailureHeaderMessage} #${dataGatheringFailedAttemptCount} of ${_maxDataGatheringRetries} attempts to gather data failed. Errors:
|
|
688
|
+
${JSON.stringify(executionErrors)}
|
|
689
|
+
`,
|
|
690
|
+
role: 'user'
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
await dataContext.SaveItems(user, false);
|
|
696
|
+
apiRequest.dataContext = CopyScalarsAndArrays(dataContext);
|
|
697
|
+
apiRequest.requestPhase = 'data_gathering_response';
|
|
698
|
+
}
|
|
699
|
+
return this.HandleSkipRequest(apiRequest, UserQuestion, user, dataSource, ConversationId, userPayload, pubSub, md, convoEntity, convoDetailEntity, dataContext, dataContextEntity);
|
|
700
|
+
}
|
|
701
|
+
catch (e) {
|
|
702
|
+
LogError(e);
|
|
703
|
+
throw e;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
async FinishConversationAndNotifyUser(apiResponse, dataContext, dataContextEntity, md, user, convoEntity, pubSub, userPayload) {
|
|
707
|
+
const sTitle = apiResponse.reportTitle;
|
|
708
|
+
const sResult = JSON.stringify(apiResponse);
|
|
709
|
+
const convoDetailEntityAI = await md.GetEntityObject('Conversation Details', user);
|
|
710
|
+
convoDetailEntityAI.NewRecord();
|
|
711
|
+
convoDetailEntityAI.ConversationID = convoEntity.ID;
|
|
712
|
+
convoDetailEntityAI.Message = sResult;
|
|
713
|
+
convoDetailEntityAI.Role = 'AI';
|
|
714
|
+
convoDetailEntityAI.HiddenToUser = false;
|
|
715
|
+
convoDetailEntityAI.Set('Sequence', 2);
|
|
716
|
+
const convoDetailSaveResult = await convoDetailEntityAI.Save();
|
|
717
|
+
if (!convoDetailSaveResult) {
|
|
718
|
+
LogError(`Error saving conversation detail entity for AI message: ${sResult}`, undefined, convoDetailEntityAI.LatestResult);
|
|
719
|
+
}
|
|
720
|
+
if (convoEntity.Name === AskSkipResolver_1._defaultNewChatName && sTitle && sTitle !== AskSkipResolver_1._defaultNewChatName) {
|
|
721
|
+
convoEntity.Name = sTitle;
|
|
722
|
+
const convoEntitySaveResult = await convoEntity.Save();
|
|
723
|
+
if (!convoEntitySaveResult) {
|
|
724
|
+
LogError(`Error saving conversation entity for AI message: ${sResult}`, undefined, convoEntity.LatestResult);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
const userNotification = await md.GetEntityObject('User Notifications', user);
|
|
728
|
+
userNotification.NewRecord();
|
|
729
|
+
userNotification.UserID = user.ID;
|
|
730
|
+
userNotification.Title = 'Report Created: ' + sTitle;
|
|
731
|
+
userNotification.Message = `Good news! Skip finished creating a report for you, click on this notification to jump back into the conversation.`;
|
|
732
|
+
userNotification.Unread = true;
|
|
733
|
+
userNotification.ResourceConfiguration = JSON.stringify({
|
|
734
|
+
type: 'askskip',
|
|
735
|
+
conversationId: convoEntity.ID,
|
|
736
|
+
});
|
|
737
|
+
const userNotificationSaveResult = await userNotification.Save();
|
|
738
|
+
if (!userNotificationSaveResult) {
|
|
739
|
+
LogError(`Error saving user notification entity for AI message: ${sResult}`, undefined, userNotification.LatestResult);
|
|
740
|
+
}
|
|
741
|
+
dataContext.SaveItems(user, false);
|
|
742
|
+
pubSub.publish(PUSH_STATUS_UPDATES_TOPIC, {
|
|
743
|
+
message: JSON.stringify({
|
|
744
|
+
type: 'UserNotifications',
|
|
745
|
+
status: 'OK',
|
|
746
|
+
conversationID: convoEntity.ID,
|
|
747
|
+
details: {
|
|
748
|
+
action: 'create',
|
|
749
|
+
recordId: userNotification.ID,
|
|
750
|
+
}
|
|
751
|
+
}),
|
|
752
|
+
sessionId: userPayload.sessionId,
|
|
753
|
+
});
|
|
754
|
+
return {
|
|
755
|
+
AIMessageConversationDetailID: convoDetailEntityAI.ID
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
async getViewData(ViewId, user) {
|
|
759
|
+
const rv = new RunView();
|
|
760
|
+
const result = await rv.RunView({ ViewID: ViewId, IgnoreMaxRows: true }, user);
|
|
761
|
+
if (result && result.Success)
|
|
762
|
+
return result.Results;
|
|
763
|
+
else
|
|
764
|
+
throw new Error(`Error running view ${ViewId}`);
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
__decorate([
|
|
768
|
+
Query(() => AskSkipResultType),
|
|
769
|
+
__param(0, Arg('UserQuestion', () => String)),
|
|
770
|
+
__param(1, Arg('ConversationId', () => String)),
|
|
771
|
+
__param(2, Arg('EntityName', () => String)),
|
|
772
|
+
__param(3, Arg('CompositeKey', () => CompositeKeyInputType)),
|
|
773
|
+
__param(4, Ctx()),
|
|
774
|
+
__param(5, PubSub()),
|
|
775
|
+
__metadata("design:type", Function),
|
|
776
|
+
__metadata("design:paramtypes", [String, String, String, CompositeKeyInputType, Object, PubSubEngine]),
|
|
777
|
+
__metadata("design:returntype", Promise)
|
|
778
|
+
], AskSkipResolver.prototype, "ExecuteAskSkipRecordChat", null);
|
|
779
|
+
__decorate([
|
|
780
|
+
Query(() => AskSkipResultType),
|
|
781
|
+
__param(0, Ctx()),
|
|
782
|
+
__param(1, PubSub()),
|
|
783
|
+
__param(2, Arg('DataContextId', () => String)),
|
|
784
|
+
__param(3, Arg('ScriptText', () => String)),
|
|
785
|
+
__metadata("design:type", Function),
|
|
786
|
+
__metadata("design:paramtypes", [Object, PubSubEngine, String, String]),
|
|
787
|
+
__metadata("design:returntype", Promise)
|
|
788
|
+
], AskSkipResolver.prototype, "ExecuteAskSkipRunScript", null);
|
|
789
|
+
__decorate([
|
|
790
|
+
Query(() => AskSkipResultType),
|
|
791
|
+
__param(0, Arg('UserQuestion', () => String)),
|
|
792
|
+
__param(1, Arg('ConversationId', () => String)),
|
|
793
|
+
__param(2, Ctx()),
|
|
794
|
+
__param(3, PubSub()),
|
|
795
|
+
__param(4, Arg('DataContextId', () => String, { nullable: true })),
|
|
796
|
+
__metadata("design:type", Function),
|
|
797
|
+
__metadata("design:paramtypes", [String, String, Object, PubSubEngine, String]),
|
|
798
|
+
__metadata("design:returntype", Promise)
|
|
799
|
+
], AskSkipResolver.prototype, "ExecuteAskSkipAnalysisQuery", null);
|
|
800
|
+
AskSkipResolver = AskSkipResolver_1 = __decorate([
|
|
801
|
+
Resolver(AskSkipResultType)
|
|
802
|
+
], AskSkipResolver);
|
|
803
|
+
export { AskSkipResolver };
|
|
804
|
+
export default AskSkipResolver;
|
|
805
|
+
//# sourceMappingURL=AskSkipResolver.js.map
|