@memberjunction/server 2.102.0 → 2.104.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 +29 -0
- package/dist/agents/skip-agent.d.ts.map +1 -0
- package/dist/agents/skip-agent.js +143 -0
- package/dist/agents/skip-agent.js.map +1 -0
- package/dist/agents/skip-sdk.d.ts +47 -0
- package/dist/agents/skip-sdk.d.ts.map +1 -0
- package/dist/agents/skip-sdk.js +270 -0
- package/dist/agents/skip-sdk.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/generated/generated.d.ts +121 -16
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +829 -120
- package/dist/generated/generated.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +24 -9
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.d.ts +19 -0
- package/dist/resolvers/ComponentRegistryResolver.d.ts.map +1 -1
- package/dist/resolvers/ComponentRegistryResolver.js +140 -2
- package/dist/resolvers/ComponentRegistryResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +3 -3
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +16 -13
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/package.json +40 -40
- package/src/agents/skip-agent.ts +285 -0
- package/src/agents/skip-sdk.ts +543 -0
- package/src/config.ts +3 -2
- package/src/generated/generated.ts +544 -93
- package/src/resolvers/AskSkipResolver.ts +32 -10
- package/src/resolvers/ComponentRegistryResolver.ts +133 -4
- package/src/resolvers/RunAIAgentResolver.ts +16 -10
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skip TypeScript SDK
|
|
3
|
+
*
|
|
4
|
+
* A general-purpose SDK for calling the Skip SaaS API.
|
|
5
|
+
* This module provides a clean, reusable interface for integrating with Skip
|
|
6
|
+
* that can eventually be extracted into a standalone npm package.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
SkipAPIRequest,
|
|
11
|
+
SkipAPIResponse,
|
|
12
|
+
SkipMessage,
|
|
13
|
+
SkipAPIAnalysisCompleteResponse,
|
|
14
|
+
SkipAPIClarifyingQuestionResponse,
|
|
15
|
+
SkipRequestPhase,
|
|
16
|
+
SkipAPIRequestAPIKey,
|
|
17
|
+
SkipQueryInfo,
|
|
18
|
+
SkipEntityInfo,
|
|
19
|
+
SkipAPIAgentNote,
|
|
20
|
+
SkipAPIAgentNoteType,
|
|
21
|
+
SkipAPIArtifact
|
|
22
|
+
} from '@memberjunction/skip-types';
|
|
23
|
+
import { DataContext } from '@memberjunction/data-context';
|
|
24
|
+
import { UserInfo, LogStatus, LogError, Metadata, RunView } from '@memberjunction/core';
|
|
25
|
+
import { sendPostRequest } from '../util.js';
|
|
26
|
+
import { configInfo, baseUrl, publicUrl, graphqlPort, graphqlRootPath, apiKey as callbackAPIKey } from '../config.js';
|
|
27
|
+
import { GetAIAPIKey } from '@memberjunction/ai';
|
|
28
|
+
import { CopyScalarsAndArrays } from '@memberjunction/global';
|
|
29
|
+
import mssql from 'mssql';
|
|
30
|
+
import { registerAccessToken, GetDataAccessToken } from '../resolvers/GetDataResolver.js';
|
|
31
|
+
import { ConversationArtifactEntity, ConversationArtifactVersionEntity, ArtifactTypeEntity } from '@memberjunction/core-entities';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Configuration options for Skip SDK
|
|
35
|
+
*/
|
|
36
|
+
export interface SkipSDKConfig {
|
|
37
|
+
/**
|
|
38
|
+
* Skip API base URL (e.g., 'https://skip.memberjunction.com')
|
|
39
|
+
*/
|
|
40
|
+
apiUrl?: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Skip API key for authentication
|
|
44
|
+
*/
|
|
45
|
+
apiKey?: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Organization ID
|
|
49
|
+
*/
|
|
50
|
+
organizationId?: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Optional organization context information
|
|
54
|
+
*/
|
|
55
|
+
organizationInfo?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Options for making a Skip API call
|
|
60
|
+
*/
|
|
61
|
+
export interface SkipCallOptions {
|
|
62
|
+
/**
|
|
63
|
+
* Conversation messages (user/assistant)
|
|
64
|
+
*/
|
|
65
|
+
messages: SkipMessage[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Conversation ID for tracking
|
|
69
|
+
*/
|
|
70
|
+
conversationId: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Data context to provide to Skip
|
|
74
|
+
*/
|
|
75
|
+
dataContext?: DataContext;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Request phase (initial_request, clarify_question_response, etc.)
|
|
79
|
+
*/
|
|
80
|
+
requestPhase?: SkipRequestPhase;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Context user for permissions and metadata
|
|
84
|
+
*/
|
|
85
|
+
contextUser: UserInfo;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Database connection for metadata queries
|
|
89
|
+
*/
|
|
90
|
+
dataSource: mssql.ConnectionPool;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Include entity metadata in request
|
|
94
|
+
*/
|
|
95
|
+
includeEntities?: boolean;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Include saved queries in request
|
|
99
|
+
*/
|
|
100
|
+
includeQueries?: boolean;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Include agent notes in request
|
|
104
|
+
*/
|
|
105
|
+
includeNotes?: boolean;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Include agent requests in request
|
|
109
|
+
*/
|
|
110
|
+
includeRequests?: boolean;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Force refresh of entity metadata cache
|
|
114
|
+
*/
|
|
115
|
+
forceEntityRefresh?: boolean;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Include callback API key and access token for Skip to call back to MJ
|
|
119
|
+
*/
|
|
120
|
+
includeCallbackAuth?: boolean;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Callback for streaming status updates during execution
|
|
124
|
+
*/
|
|
125
|
+
onStatusUpdate?: (message: string, responsePhase?: string) => void;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Result from a Skip API call
|
|
130
|
+
*/
|
|
131
|
+
export interface SkipCallResult {
|
|
132
|
+
/**
|
|
133
|
+
* Whether the call was successful
|
|
134
|
+
*/
|
|
135
|
+
success: boolean;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The final Skip API response
|
|
139
|
+
*/
|
|
140
|
+
response?: SkipAPIResponse;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Response phase (analysis_complete, clarifying_question, status_update)
|
|
144
|
+
*/
|
|
145
|
+
responsePhase?: string;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Error message if failed
|
|
149
|
+
*/
|
|
150
|
+
error?: string;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* All streaming responses received (including intermediate status updates)
|
|
154
|
+
*/
|
|
155
|
+
allResponses?: any[];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Skip TypeScript SDK
|
|
160
|
+
* Provides a clean interface for calling the Skip SaaS API
|
|
161
|
+
*/
|
|
162
|
+
export class SkipSDK {
|
|
163
|
+
private config: SkipSDKConfig;
|
|
164
|
+
|
|
165
|
+
constructor(config?: SkipSDKConfig) {
|
|
166
|
+
// Use provided config or fall back to MJ server config
|
|
167
|
+
this.config = {
|
|
168
|
+
apiUrl: config?.apiUrl || configInfo.askSkip?.url,
|
|
169
|
+
apiKey: config?.apiKey || configInfo.askSkip?.apiKey,
|
|
170
|
+
organizationId: config?.organizationId || configInfo.askSkip?.orgID,
|
|
171
|
+
organizationInfo: config?.organizationInfo || configInfo.askSkip?.organizationInfo
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Call the Skip chat API
|
|
177
|
+
*/
|
|
178
|
+
async chat(options: SkipCallOptions): Promise<SkipCallResult> {
|
|
179
|
+
const chatURL = `${this.config.apiUrl}/chat`;
|
|
180
|
+
|
|
181
|
+
LogStatus(`[SkipSDK] Sending request to Skip API: ${chatURL}`);
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
// Build the Skip API request
|
|
185
|
+
const skipRequest = await this.buildSkipRequest(options);
|
|
186
|
+
|
|
187
|
+
// Call Skip API with streaming support
|
|
188
|
+
const responses = await sendPostRequest(
|
|
189
|
+
chatURL,
|
|
190
|
+
skipRequest,
|
|
191
|
+
true, // useCompression
|
|
192
|
+
this.buildHeaders(),
|
|
193
|
+
(streamMessage: any) => {
|
|
194
|
+
// Handle streaming status updates
|
|
195
|
+
if (streamMessage.type === 'status_update' && options.onStatusUpdate) {
|
|
196
|
+
const statusContent = streamMessage.value?.messages?.[0]?.content;
|
|
197
|
+
const responsePhase = streamMessage.value?.responsePhase;
|
|
198
|
+
if (statusContent) {
|
|
199
|
+
options.onStatusUpdate(statusContent, responsePhase);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// The last response is the final one
|
|
206
|
+
if (responses && responses.length > 0) {
|
|
207
|
+
const finalResponse = responses[responses.length - 1].value as SkipAPIResponse;
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
success: true,
|
|
211
|
+
response: finalResponse,
|
|
212
|
+
responsePhase: finalResponse.responsePhase,
|
|
213
|
+
allResponses: responses
|
|
214
|
+
};
|
|
215
|
+
} else {
|
|
216
|
+
return {
|
|
217
|
+
success: false,
|
|
218
|
+
error: 'No response received from Skip API'
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
} catch (error) {
|
|
223
|
+
LogError(`[SkipSDK] Error calling Skip API: ${error}`);
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
error: String(error)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Build the Skip API request object
|
|
233
|
+
*/
|
|
234
|
+
private async buildSkipRequest(options: SkipCallOptions): Promise<SkipAPIRequest> {
|
|
235
|
+
const {
|
|
236
|
+
messages,
|
|
237
|
+
conversationId,
|
|
238
|
+
dataContext,
|
|
239
|
+
requestPhase = 'initial_request',
|
|
240
|
+
contextUser,
|
|
241
|
+
dataSource,
|
|
242
|
+
includeEntities = true,
|
|
243
|
+
includeQueries = true,
|
|
244
|
+
includeNotes = true,
|
|
245
|
+
includeRequests = false,
|
|
246
|
+
forceEntityRefresh = false,
|
|
247
|
+
includeCallbackAuth = true
|
|
248
|
+
} = options;
|
|
249
|
+
|
|
250
|
+
// Build base request with metadata
|
|
251
|
+
const baseRequest = await this.buildBaseRequest(
|
|
252
|
+
contextUser,
|
|
253
|
+
dataSource,
|
|
254
|
+
includeEntities,
|
|
255
|
+
includeQueries,
|
|
256
|
+
includeNotes,
|
|
257
|
+
includeRequests,
|
|
258
|
+
forceEntityRefresh,
|
|
259
|
+
includeCallbackAuth,
|
|
260
|
+
{ conversationId, requestPhase }
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
// Build artifacts for this conversation
|
|
264
|
+
const artifacts = await this.buildArtifacts(contextUser, dataSource, conversationId);
|
|
265
|
+
|
|
266
|
+
// Construct the full Skip API request
|
|
267
|
+
const request: SkipAPIRequest = {
|
|
268
|
+
messages,
|
|
269
|
+
conversationID: conversationId,
|
|
270
|
+
dataContext: dataContext ? CopyScalarsAndArrays(dataContext) as DataContext : undefined,
|
|
271
|
+
requestPhase,
|
|
272
|
+
artifacts,
|
|
273
|
+
entities: baseRequest.entities || [],
|
|
274
|
+
queries: baseRequest.queries || [],
|
|
275
|
+
notes: baseRequest.notes,
|
|
276
|
+
noteTypes: baseRequest.noteTypes,
|
|
277
|
+
userEmail: baseRequest.userEmail,
|
|
278
|
+
organizationID: baseRequest.organizationID,
|
|
279
|
+
organizationInfo: baseRequest.organizationInfo,
|
|
280
|
+
apiKeys: baseRequest.apiKeys,
|
|
281
|
+
callingServerURL: baseRequest.callingServerURL,
|
|
282
|
+
callingServerAPIKey: baseRequest.callingServerAPIKey,
|
|
283
|
+
callingServerAccessToken: baseRequest.callingServerAccessToken
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
return request;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Build base request with metadata, API keys, and callback auth
|
|
291
|
+
*/
|
|
292
|
+
private async buildBaseRequest(
|
|
293
|
+
contextUser: UserInfo,
|
|
294
|
+
dataSource: mssql.ConnectionPool,
|
|
295
|
+
includeEntities: boolean,
|
|
296
|
+
includeQueries: boolean,
|
|
297
|
+
includeNotes: boolean,
|
|
298
|
+
includeRequests: boolean,
|
|
299
|
+
forceEntityRefresh: boolean,
|
|
300
|
+
includeCallbackAuth: boolean,
|
|
301
|
+
additionalTokenInfo: any = {}
|
|
302
|
+
): Promise<Partial<SkipAPIRequest>> {
|
|
303
|
+
const entities = includeEntities ? await this.buildEntities(dataSource, forceEntityRefresh) : [];
|
|
304
|
+
const queries = includeQueries ? this.buildQueries() : [];
|
|
305
|
+
const { notes, noteTypes } = includeNotes ? await this.buildAgentNotes(contextUser) : { notes: [], noteTypes: [] };
|
|
306
|
+
// Note: requests would be built here if includeRequests is true
|
|
307
|
+
|
|
308
|
+
// Setup access token for Skip callbacks if needed
|
|
309
|
+
let accessToken: GetDataAccessToken | undefined;
|
|
310
|
+
if (includeCallbackAuth) {
|
|
311
|
+
const tokenInfo = {
|
|
312
|
+
type: 'skip_api_request',
|
|
313
|
+
userEmail: contextUser.Email,
|
|
314
|
+
userName: contextUser.Name,
|
|
315
|
+
userID: contextUser.ID,
|
|
316
|
+
...additionalTokenInfo
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
accessToken = registerAccessToken(
|
|
320
|
+
undefined,
|
|
321
|
+
1000 * 60 * 10, // 10 minutes
|
|
322
|
+
tokenInfo
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
entities,
|
|
328
|
+
queries,
|
|
329
|
+
notes,
|
|
330
|
+
noteTypes,
|
|
331
|
+
userEmail: contextUser.Email,
|
|
332
|
+
organizationID: this.config.organizationId,
|
|
333
|
+
organizationInfo: this.config.organizationInfo,
|
|
334
|
+
apiKeys: this.buildAPIKeys(),
|
|
335
|
+
callingServerURL: accessToken ? (publicUrl || `${baseUrl}:${graphqlPort}${graphqlRootPath}`) : undefined,
|
|
336
|
+
callingServerAPIKey: accessToken ? callbackAPIKey : undefined,
|
|
337
|
+
callingServerAccessToken: accessToken ? accessToken.Token : undefined
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Build entity metadata for Skip
|
|
343
|
+
* This can be extracted from AskSkipResolver.BuildSkipEntities if needed
|
|
344
|
+
*/
|
|
345
|
+
private async buildEntities(dataSource: mssql.ConnectionPool, forceRefresh: boolean): Promise<SkipEntityInfo[]> {
|
|
346
|
+
// TODO: Implement entity metadata building
|
|
347
|
+
// This would typically query the metadata and convert to SkipEntityInfo format
|
|
348
|
+
// For now, returning empty array - can be populated later
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Build saved queries for Skip
|
|
354
|
+
*/
|
|
355
|
+
private buildQueries(status: "Pending" | "In-Review" | "Approved" | "Rejected" | "Obsolete" = 'Approved'): SkipQueryInfo[] {
|
|
356
|
+
const md = new Metadata();
|
|
357
|
+
const approvedQueries = md.Queries.filter((q) => q.Status === status);
|
|
358
|
+
|
|
359
|
+
return approvedQueries.map((q) => ({
|
|
360
|
+
id: q.ID,
|
|
361
|
+
name: q.Name,
|
|
362
|
+
description: q.Description,
|
|
363
|
+
category: q.Category,
|
|
364
|
+
categoryPath: this.buildQueryCategoryPath(md, q.CategoryID),
|
|
365
|
+
sql: q.SQL,
|
|
366
|
+
originalSQL: q.OriginalSQL,
|
|
367
|
+
feedback: q.Feedback,
|
|
368
|
+
status: q.Status,
|
|
369
|
+
qualityRank: q.QualityRank,
|
|
370
|
+
createdAt: q.__mj_CreatedAt,
|
|
371
|
+
updatedAt: q.__mj_UpdatedAt,
|
|
372
|
+
categoryID: q.CategoryID,
|
|
373
|
+
embeddingVector: q.EmbeddingVector,
|
|
374
|
+
embeddingModelID: q.EmbeddingModelID,
|
|
375
|
+
embeddingModelName: q.EmbeddingModel,
|
|
376
|
+
fields: q.Fields.map((f) => ({
|
|
377
|
+
id: f.ID,
|
|
378
|
+
queryID: f.QueryID,
|
|
379
|
+
sequence: f.Sequence,
|
|
380
|
+
name: f.Name,
|
|
381
|
+
description: f.Description,
|
|
382
|
+
sqlBaseType: f.SQLBaseType,
|
|
383
|
+
sqlFullType: f.SQLFullType,
|
|
384
|
+
sourceEntityID: f.SourceEntityID,
|
|
385
|
+
sourceEntity: f.SourceEntity,
|
|
386
|
+
sourceFieldName: f.SourceFieldName,
|
|
387
|
+
isComputed: f.IsComputed,
|
|
388
|
+
computationDescription: f.ComputationDescription,
|
|
389
|
+
isSummary: f.IsSummary,
|
|
390
|
+
summaryDescription: f.SummaryDescription,
|
|
391
|
+
createdAt: f.__mj_CreatedAt,
|
|
392
|
+
updatedAt: f.__mj_UpdatedAt
|
|
393
|
+
})),
|
|
394
|
+
params: q.Parameters.map((p) => ({
|
|
395
|
+
id: p.ID,
|
|
396
|
+
queryID: p.QueryID,
|
|
397
|
+
name: p.Name,
|
|
398
|
+
description: p.Description,
|
|
399
|
+
type: p.Type,
|
|
400
|
+
isRequired: p.IsRequired,
|
|
401
|
+
// LinkedParameterName and LinkedParameterType may not exist on QueryParameterInfo
|
|
402
|
+
defaultValue: p.DefaultValue,
|
|
403
|
+
createdAt: p.__mj_CreatedAt,
|
|
404
|
+
updatedAt: p.__mj_UpdatedAt
|
|
405
|
+
}))
|
|
406
|
+
}));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Recursively build category path for a query
|
|
411
|
+
*/
|
|
412
|
+
private buildQueryCategoryPath(md: Metadata, categoryID: string): string {
|
|
413
|
+
const cat = md.QueryCategories.find((c) => c.ID === categoryID);
|
|
414
|
+
if (!cat) return '';
|
|
415
|
+
if (!cat.ParentID) return cat.Name;
|
|
416
|
+
const parentPath = this.buildQueryCategoryPath(md, cat.ParentID);
|
|
417
|
+
return parentPath ? `${parentPath}/${cat.Name}` : cat.Name;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Build agent notes for Skip
|
|
422
|
+
*/
|
|
423
|
+
private async buildAgentNotes(contextUser: UserInfo): Promise<{ notes: SkipAPIAgentNote[], noteTypes: SkipAPIAgentNoteType[] }> {
|
|
424
|
+
// TODO: Implement agent notes building
|
|
425
|
+
// This would query AIAgentNote entities and convert to SkipAPIAgentNote format
|
|
426
|
+
// For now, returning empty arrays
|
|
427
|
+
return { notes: [], noteTypes: [] };
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Build artifacts for a conversation
|
|
432
|
+
*/
|
|
433
|
+
private async buildArtifacts(contextUser: UserInfo, dataSource: mssql.ConnectionPool, conversationId: string): Promise<SkipAPIArtifact[]> {
|
|
434
|
+
const md = new Metadata();
|
|
435
|
+
const ei = md.EntityByName('MJ: Conversation Artifacts');
|
|
436
|
+
const rv = new RunView();
|
|
437
|
+
|
|
438
|
+
const results = await rv.RunViews([
|
|
439
|
+
{
|
|
440
|
+
EntityName: "MJ: Conversation Artifacts",
|
|
441
|
+
ExtraFilter: `ConversationID='${conversationId}'`,
|
|
442
|
+
OrderBy: "__mj_CreatedAt"
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
EntityName: "MJ: Artifact Types",
|
|
446
|
+
OrderBy: "Name"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
EntityName: "MJ: Conversation Artifact Versions",
|
|
450
|
+
ExtraFilter: `ConversationArtifactID IN (SELECT ID FROM [${ei.SchemaName}].[${ei.BaseView}] WHERE ConversationID='${conversationId}')`,
|
|
451
|
+
OrderBy: 'ConversationArtifactID, __mj_CreatedAt'
|
|
452
|
+
}
|
|
453
|
+
], contextUser);
|
|
454
|
+
|
|
455
|
+
if (!results || results.length === 0 || !results.every(r => r.Success)) {
|
|
456
|
+
return [];
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const types = results[1].Results.map((a: ArtifactTypeEntity) => ({
|
|
460
|
+
id: a.ID,
|
|
461
|
+
name: a.Name,
|
|
462
|
+
description: a.Description,
|
|
463
|
+
contentType: a.ContentType,
|
|
464
|
+
enabled: a.IsEnabled,
|
|
465
|
+
createdAt: a.__mj_CreatedAt,
|
|
466
|
+
updatedAt: a.__mj_UpdatedAt
|
|
467
|
+
}));
|
|
468
|
+
|
|
469
|
+
const artifacts = results[0].Results.map((a: ConversationArtifactEntity) => {
|
|
470
|
+
const rawVersions: ConversationArtifactVersionEntity[] = results[2].Results as ConversationArtifactVersionEntity[];
|
|
471
|
+
const thisArtifactsVersions = rawVersions.filter(rv => rv.ConversationArtifactID === a.ID);
|
|
472
|
+
|
|
473
|
+
const versions = thisArtifactsVersions.map((v: ConversationArtifactVersionEntity) => ({
|
|
474
|
+
id: v.ID,
|
|
475
|
+
artifactId: v.ConversationArtifactID,
|
|
476
|
+
version: v.Version,
|
|
477
|
+
configuration: v.Configuration,
|
|
478
|
+
content: v.Content,
|
|
479
|
+
comments: v.Comments,
|
|
480
|
+
createdAt: v.__mj_CreatedAt,
|
|
481
|
+
updatedAt: v.__mj_UpdatedAt
|
|
482
|
+
}));
|
|
483
|
+
|
|
484
|
+
return {
|
|
485
|
+
id: a.ID,
|
|
486
|
+
conversationId: a.ConversationID,
|
|
487
|
+
name: a.Name,
|
|
488
|
+
description: a.Description,
|
|
489
|
+
artifactType: types.find(t => t.id === a.ArtifactTypeID),
|
|
490
|
+
sharingScope: a.SharingScope,
|
|
491
|
+
currentVersion: versions.length > 0 ? Math.max(...versions.map(v => v.version)) : 1,
|
|
492
|
+
versions,
|
|
493
|
+
comments: '', // Default empty comments since it's required
|
|
494
|
+
createdAt: a.__mj_CreatedAt,
|
|
495
|
+
updatedAt: a.__mj_UpdatedAt
|
|
496
|
+
};
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
return artifacts;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Build API keys for AI services
|
|
504
|
+
*/
|
|
505
|
+
private buildAPIKeys(): SkipAPIRequestAPIKey[] {
|
|
506
|
+
return [
|
|
507
|
+
{
|
|
508
|
+
vendorDriverName: 'OpenAILLM',
|
|
509
|
+
apiKey: GetAIAPIKey('OpenAILLM')
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
vendorDriverName: 'AnthropicLLM',
|
|
513
|
+
apiKey: GetAIAPIKey('AnthropicLLM')
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
vendorDriverName: 'GeminiLLM',
|
|
517
|
+
apiKey: GetAIAPIKey('GeminiLLM')
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
vendorDriverName: 'GroqLLM',
|
|
521
|
+
apiKey: GetAIAPIKey('GroqLLM')
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
vendorDriverName: 'MistralLLM',
|
|
525
|
+
apiKey: GetAIAPIKey('MistralLLM')
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
vendorDriverName: 'CerebrasLLM',
|
|
529
|
+
apiKey: GetAIAPIKey('CerebrasLLM')
|
|
530
|
+
}
|
|
531
|
+
];
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Build HTTP headers for Skip API requests
|
|
536
|
+
*/
|
|
537
|
+
private buildHeaders(): Record<string, string> {
|
|
538
|
+
return {
|
|
539
|
+
'x-api-key': this.config.apiKey || '',
|
|
540
|
+
'Content-Type': 'application/json'
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -68,6 +68,7 @@ const zodBooleanWithTransforms = () => {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const askSkipInfoSchema = z.object({
|
|
71
|
+
url: z.string().optional(), // Base URL for Skip API
|
|
71
72
|
apiKey: z.string().optional(),
|
|
72
73
|
orgID: z.string().optional(),
|
|
73
74
|
organizationInfo: z.string().optional(),
|
|
@@ -78,8 +79,8 @@ const askSkipInfoSchema = z.object({
|
|
|
78
79
|
})
|
|
79
80
|
.optional(),
|
|
80
81
|
chatURL: z.string().optional(),
|
|
81
|
-
learningCycleRunUponStartup: zodBooleanWithTransforms(),
|
|
82
|
-
learningCycleEnabled: zodBooleanWithTransforms(),
|
|
82
|
+
learningCycleRunUponStartup: zodBooleanWithTransforms(),
|
|
83
|
+
learningCycleEnabled: zodBooleanWithTransforms(),
|
|
83
84
|
learningCycleURL: z.string().optional(),
|
|
84
85
|
learningCycleIntervalInMinutes: z.coerce.number().optional(),
|
|
85
86
|
});
|