@memberjunction/server 2.103.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 +76 -16
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +527 -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 +38 -38
- 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 +351 -93
- package/src/resolvers/AskSkipResolver.ts +32 -10
- package/src/resolvers/ComponentRegistryResolver.ts +133 -4
- package/src/resolvers/RunAIAgentResolver.ts +16 -10
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Arg, Ctx, Field, Mutation, ObjectType, PubSub, PubSubEngine, Query, Resolver } from 'type-graphql';
|
|
1
|
+
import { Arg, Ctx, Field, InputType, Mutation, ObjectType, PubSub, PubSubEngine, Query, Resolver } from 'type-graphql';
|
|
2
2
|
import { LogError, LogStatus, Metadata, RunView, UserInfo, CompositeKey, EntityFieldInfo, EntityInfo, EntityRelationshipInfo, EntitySaveOptions, EntityDeleteOptions, IMetadataProvider } from '@memberjunction/core';
|
|
3
3
|
import { AppContext, UserPayload, MJ_SERVER_EVENT_CODE } from '../types.js';
|
|
4
4
|
import { BehaviorSubject } from 'rxjs';
|
|
@@ -66,6 +66,18 @@ import { AIEngine } from '@memberjunction/aiengine';
|
|
|
66
66
|
import { deleteAccessToken, GetDataAccessToken, registerAccessToken, tokenExists } from './GetDataResolver.js';
|
|
67
67
|
import e from 'express';
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Skip API Endpoints Configuration
|
|
71
|
+
* Defines all available endpoints for the Skip API
|
|
72
|
+
*/
|
|
73
|
+
const SKIP_API_ENDPOINTS = {
|
|
74
|
+
CHAT: '/chat',
|
|
75
|
+
LEARNING: '/learning',
|
|
76
|
+
FEEDBACK_COMPONENT: '/feedback/component',
|
|
77
|
+
REGISTRY: '/registry',
|
|
78
|
+
// Add more endpoints as needed
|
|
79
|
+
} as const;
|
|
80
|
+
|
|
69
81
|
/**
|
|
70
82
|
* Store for active conversation streams
|
|
71
83
|
* Maps conversationID to the last status message received
|
|
@@ -368,7 +380,9 @@ function initializeSkipLearningCycleScheduler() {
|
|
|
368
380
|
}
|
|
369
381
|
|
|
370
382
|
// Check if we have a valid endpoint when cycles are enabled
|
|
371
|
-
|
|
383
|
+
const hasLearningEndpoint = (skipConfigInfo.url && skipConfigInfo.url.trim().length > 0) ||
|
|
384
|
+
(skipConfigInfo.learningCycleURL && skipConfigInfo.learningCycleURL.trim().length > 0);
|
|
385
|
+
if (!hasLearningEndpoint) {
|
|
372
386
|
LogError('Skip AI Learning cycle scheduler not started: Learning cycles are enabled but no Learning Cycle API endpoint is configured');
|
|
373
387
|
return;
|
|
374
388
|
}
|
|
@@ -577,7 +591,9 @@ export class AskSkipResolver {
|
|
|
577
591
|
}
|
|
578
592
|
|
|
579
593
|
// Check if we have a valid endpoint when cycles are enabled
|
|
580
|
-
|
|
594
|
+
const hasLearningEndpoint = (skipConfigInfo.url && skipConfigInfo.url.trim().length > 0) ||
|
|
595
|
+
(skipConfigInfo.learningCycleURL && skipConfigInfo.learningCycleURL.trim().length > 0);
|
|
596
|
+
if (!hasLearningEndpoint) {
|
|
581
597
|
return {
|
|
582
598
|
success: false,
|
|
583
599
|
error: 'Learning cycle API endpoint is not configured',
|
|
@@ -729,9 +745,10 @@ export class AskSkipResolver {
|
|
|
729
745
|
userPayload: UserPayload
|
|
730
746
|
): Promise<SkipAPILearningCycleResponse> {
|
|
731
747
|
const skipConfigInfo = configInfo.askSkip;
|
|
732
|
-
|
|
748
|
+
const learningURL = skipConfigInfo.url ? `${skipConfigInfo.url}${SKIP_API_ENDPOINTS.LEARNING}` : skipConfigInfo.learningCycleURL;
|
|
749
|
+
LogStatus(` >>> HandleSimpleSkipLearningPostRequest Sending request to Skip API: ${learningURL}`);
|
|
733
750
|
|
|
734
|
-
const response = await sendPostRequest(
|
|
751
|
+
const response = await sendPostRequest(learningURL, input, true, this.buildSkipPostHeaders());
|
|
735
752
|
|
|
736
753
|
if (response && response.length > 0) {
|
|
737
754
|
// the last object in the response array is the final response from the Skip API
|
|
@@ -789,10 +806,11 @@ export class AskSkipResolver {
|
|
|
789
806
|
userPayload: UserPayload = null
|
|
790
807
|
): Promise<AskSkipResultType> {
|
|
791
808
|
const skipConfigInfo = configInfo.askSkip;
|
|
792
|
-
|
|
809
|
+
const chatURL = skipConfigInfo.url ? `${skipConfigInfo.url}${SKIP_API_ENDPOINTS.CHAT}` : skipConfigInfo.chatURL;
|
|
810
|
+
LogStatus(` >>> HandleSimpleSkipChatPostRequest Sending request to Skip API: ${chatURL}`);
|
|
793
811
|
|
|
794
812
|
try {
|
|
795
|
-
const response = await sendPostRequest(
|
|
813
|
+
const response = await sendPostRequest(chatURL, input, true, this.buildSkipPostHeaders());
|
|
796
814
|
|
|
797
815
|
if (response && response.length > 0) {
|
|
798
816
|
// the last object in the response array is the final response from the Skip API
|
|
@@ -2428,7 +2446,8 @@ cycle.`);
|
|
|
2428
2446
|
startTime: Date
|
|
2429
2447
|
): Promise<AskSkipResultType> {
|
|
2430
2448
|
const skipConfigInfo = configInfo.askSkip;
|
|
2431
|
-
|
|
2449
|
+
const chatURL = skipConfigInfo.url ? `${skipConfigInfo.url}${SKIP_API_ENDPOINTS.CHAT}` : skipConfigInfo.chatURL;
|
|
2450
|
+
LogStatus(` >>> HandleSkipRequest: Sending request to Skip API: ${chatURL}`);
|
|
2432
2451
|
|
|
2433
2452
|
if (conversationDetailCount > 10) {
|
|
2434
2453
|
// Set status of conversation to Available since we still want to allow the user to ask questions
|
|
@@ -2459,7 +2478,7 @@ cycle.`);
|
|
|
2459
2478
|
let response;
|
|
2460
2479
|
try {
|
|
2461
2480
|
response = await sendPostRequest(
|
|
2462
|
-
|
|
2481
|
+
chatURL,
|
|
2463
2482
|
input,
|
|
2464
2483
|
true,
|
|
2465
2484
|
this.buildSkipPostHeaders(),
|
|
@@ -3259,7 +3278,9 @@ cycle.`);
|
|
|
3259
3278
|
}
|
|
3260
3279
|
|
|
3261
3280
|
// Check if we have a valid endpoint when cycles are enabled
|
|
3262
|
-
|
|
3281
|
+
const hasLearningEndpoint = (skipConfigInfo.url && skipConfigInfo.url.trim().length > 0) ||
|
|
3282
|
+
(skipConfigInfo.learningCycleURL && skipConfigInfo.learningCycleURL.trim().length > 0);
|
|
3283
|
+
if (!hasLearningEndpoint) {
|
|
3263
3284
|
return {
|
|
3264
3285
|
Success: false,
|
|
3265
3286
|
Message: 'Learning cycle API endpoint is not configured'
|
|
@@ -3394,6 +3415,7 @@ cycle.`);
|
|
|
3394
3415
|
};
|
|
3395
3416
|
}
|
|
3396
3417
|
}
|
|
3418
|
+
|
|
3397
3419
|
}
|
|
3398
3420
|
|
|
3399
3421
|
export default AskSkipResolver;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { Arg, Ctx, Field, InputType, ObjectType, Query, Resolver } from 'type-graphql';
|
|
1
|
+
import { Arg, Ctx, Field, InputType, ObjectType, Query, Mutation, Resolver } from 'type-graphql';
|
|
2
2
|
import { UserInfo, Metadata, LogError, LogStatus } from '@memberjunction/core';
|
|
3
3
|
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
4
4
|
import { ComponentEntity, ComponentRegistryEntity, ComponentMetadataEngine } from '@memberjunction/core-entities';
|
|
5
5
|
import { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
7
|
ComponentRegistryClient,
|
|
8
8
|
ComponentResponse,
|
|
9
9
|
ComponentSearchResult,
|
|
10
10
|
DependencyTree,
|
|
11
11
|
RegistryError,
|
|
12
|
-
RegistryErrorCode
|
|
12
|
+
RegistryErrorCode,
|
|
13
|
+
ComponentFeedbackParams as SDKComponentFeedbackParams,
|
|
14
|
+
ComponentFeedbackResponse as SDKComponentFeedbackResponse
|
|
13
15
|
} from '@memberjunction/component-registry-client-sdk';
|
|
14
16
|
import { AppContext } from '../types.js';
|
|
15
17
|
import { configInfo } from '../config.js';
|
|
@@ -96,6 +98,61 @@ class ComponentDependencyTreeType {
|
|
|
96
98
|
dependencies?: ComponentDependencyTreeType[];
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Input type for submitting component feedback
|
|
103
|
+
* Registry-agnostic feedback collection for any component from any registry
|
|
104
|
+
*/
|
|
105
|
+
@InputType()
|
|
106
|
+
class ComponentFeedbackInput {
|
|
107
|
+
@Field()
|
|
108
|
+
componentName: string;
|
|
109
|
+
|
|
110
|
+
@Field()
|
|
111
|
+
componentNamespace: string;
|
|
112
|
+
|
|
113
|
+
@Field({ nullable: true })
|
|
114
|
+
componentVersion?: string;
|
|
115
|
+
|
|
116
|
+
@Field({ nullable: true })
|
|
117
|
+
registryName?: string;
|
|
118
|
+
|
|
119
|
+
@Field()
|
|
120
|
+
rating: number;
|
|
121
|
+
|
|
122
|
+
@Field({ nullable: true })
|
|
123
|
+
feedbackType?: string;
|
|
124
|
+
|
|
125
|
+
@Field({ nullable: true })
|
|
126
|
+
comments?: string;
|
|
127
|
+
|
|
128
|
+
@Field({ nullable: true })
|
|
129
|
+
conversationID?: string;
|
|
130
|
+
|
|
131
|
+
@Field({ nullable: true })
|
|
132
|
+
conversationDetailID?: string;
|
|
133
|
+
|
|
134
|
+
@Field({ nullable: true })
|
|
135
|
+
reportID?: string;
|
|
136
|
+
|
|
137
|
+
@Field({ nullable: true })
|
|
138
|
+
dashboardID?: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Response type for component feedback submission
|
|
143
|
+
*/
|
|
144
|
+
@ObjectType()
|
|
145
|
+
class ComponentFeedbackResponse {
|
|
146
|
+
@Field()
|
|
147
|
+
success: boolean;
|
|
148
|
+
|
|
149
|
+
@Field({ nullable: true })
|
|
150
|
+
feedbackID?: string;
|
|
151
|
+
|
|
152
|
+
@Field({ nullable: true })
|
|
153
|
+
error?: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
99
156
|
/**
|
|
100
157
|
* Resolver for Component Registry operations
|
|
101
158
|
*
|
|
@@ -153,7 +210,8 @@ export class ComponentRegistryExtendedResolver {
|
|
|
153
210
|
namespace,
|
|
154
211
|
name,
|
|
155
212
|
version: version || 'latest',
|
|
156
|
-
hash: hash
|
|
213
|
+
hash: hash,
|
|
214
|
+
userEmail: user.Email
|
|
157
215
|
});
|
|
158
216
|
|
|
159
217
|
// If not modified (304), return response with notModified flag
|
|
@@ -532,4 +590,75 @@ export class ComponentRegistryExtendedResolver {
|
|
|
532
590
|
limit: result.limit
|
|
533
591
|
};
|
|
534
592
|
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Send feedback for a component from any registry
|
|
596
|
+
* This is a registry-agnostic mutation that allows feedback collection
|
|
597
|
+
* for components from any source registry (Skip, MJ Central, etc.)
|
|
598
|
+
*/
|
|
599
|
+
@Mutation(() => ComponentFeedbackResponse)
|
|
600
|
+
async SendComponentFeedback(
|
|
601
|
+
@Arg('feedback') feedback: ComponentFeedbackInput,
|
|
602
|
+
@Ctx() { userPayload }: AppContext
|
|
603
|
+
): Promise<ComponentFeedbackResponse> {
|
|
604
|
+
try {
|
|
605
|
+
// Get user from cache
|
|
606
|
+
const user = UserCache.Instance.Users.find((u) => u.Email.trim().toLowerCase() === userPayload.email?.trim().toLowerCase());
|
|
607
|
+
if (!user) {
|
|
608
|
+
return {
|
|
609
|
+
success: false,
|
|
610
|
+
error: `User ${userPayload.email} not found in UserCache`
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Registry name is required for feedback submission
|
|
615
|
+
if (!feedback.registryName) {
|
|
616
|
+
return {
|
|
617
|
+
success: false,
|
|
618
|
+
error: 'Registry name is required for feedback submission'
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Get registry configuration
|
|
623
|
+
const registry = await this.getRegistryByName(feedback.registryName, user);
|
|
624
|
+
if (!registry) {
|
|
625
|
+
return {
|
|
626
|
+
success: false,
|
|
627
|
+
error: `Registry not found: ${feedback.registryName}`
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Check user permissions
|
|
632
|
+
await this.checkUserAccess(user, registry.ID);
|
|
633
|
+
|
|
634
|
+
// Create client using the same pattern as GetRegistryComponent
|
|
635
|
+
// This respects REGISTRY_URI_OVERRIDE_* and REGISTRY_API_KEY_* environment variables
|
|
636
|
+
const registryClient = this.createClientForRegistry(registry);
|
|
637
|
+
|
|
638
|
+
const sdkParams: SDKComponentFeedbackParams = {
|
|
639
|
+
componentName: feedback.componentName,
|
|
640
|
+
componentNamespace: feedback.componentNamespace,
|
|
641
|
+
componentVersion: feedback.componentVersion,
|
|
642
|
+
registryName: feedback.registryName,
|
|
643
|
+
rating: feedback.rating,
|
|
644
|
+
feedbackType: feedback.feedbackType,
|
|
645
|
+
comments: feedback.comments,
|
|
646
|
+
conversationID: feedback.conversationID,
|
|
647
|
+
conversationDetailID: feedback.conversationDetailID,
|
|
648
|
+
reportID: feedback.reportID,
|
|
649
|
+
dashboardID: feedback.dashboardID,
|
|
650
|
+
userEmail: user.Email // Pass the authenticated user's email to the registry
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
const result = await registryClient.submitFeedback(sdkParams);
|
|
654
|
+
|
|
655
|
+
return result;
|
|
656
|
+
} catch (error) {
|
|
657
|
+
LogError(error);
|
|
658
|
+
return {
|
|
659
|
+
success: false,
|
|
660
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
}
|
|
535
664
|
}
|
|
@@ -22,7 +22,7 @@ export class AIAgentRunResult {
|
|
|
22
22
|
executionTimeMs?: number;
|
|
23
23
|
|
|
24
24
|
@Field()
|
|
25
|
-
|
|
25
|
+
result: string; // JSON serialized ExecuteAgentResult with scalars only
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
@ObjectType()
|
|
@@ -315,7 +315,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
315
315
|
templateData?: string,
|
|
316
316
|
lastRunId?: string,
|
|
317
317
|
autoPopulateLastRunPayload?: boolean,
|
|
318
|
-
configurationId?: string
|
|
318
|
+
configurationId?: string,
|
|
319
|
+
conversationDetailId?: string
|
|
319
320
|
): Promise<AIAgentRunResult> {
|
|
320
321
|
const startTime = Date.now();
|
|
321
322
|
|
|
@@ -361,7 +362,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
361
362
|
lastRunId: lastRunId,
|
|
362
363
|
autoPopulateLastRunPayload: autoPopulateLastRunPayload,
|
|
363
364
|
configurationId: configurationId,
|
|
364
|
-
data: parsedData
|
|
365
|
+
data: parsedData,
|
|
366
|
+
conversationDetailId: conversationDetailId,
|
|
365
367
|
});
|
|
366
368
|
|
|
367
369
|
// Update agent run ref once available
|
|
@@ -376,7 +378,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
376
378
|
|
|
377
379
|
// Create sanitized payload for JSON serialization
|
|
378
380
|
const sanitizedResult = this.sanitizeAgentResult(result);
|
|
379
|
-
const
|
|
381
|
+
const returnResult = JSON.stringify(sanitizedResult);
|
|
380
382
|
|
|
381
383
|
// Log completion
|
|
382
384
|
if (result.success) {
|
|
@@ -389,7 +391,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
389
391
|
success: result.success,
|
|
390
392
|
errorMessage: result.agentRun?.ErrorMessage || undefined,
|
|
391
393
|
executionTimeMs: executionTime,
|
|
392
|
-
|
|
394
|
+
result: returnResult
|
|
393
395
|
};
|
|
394
396
|
|
|
395
397
|
} catch (error) {
|
|
@@ -407,7 +409,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
407
409
|
success: false,
|
|
408
410
|
errorMessage: errorResult.errorMessage,
|
|
409
411
|
executionTimeMs: executionTime,
|
|
410
|
-
|
|
412
|
+
result: JSON.stringify(errorResult)
|
|
411
413
|
};
|
|
412
414
|
}
|
|
413
415
|
}
|
|
@@ -465,7 +467,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
465
467
|
@Arg('templateData', { nullable: true }) templateData?: string,
|
|
466
468
|
@Arg('lastRunId', { nullable: true }) lastRunId?: string,
|
|
467
469
|
@Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
|
|
468
|
-
@Arg('configurationId', { nullable: true }) configurationId?: string
|
|
470
|
+
@Arg('configurationId', { nullable: true }) configurationId?: string,
|
|
471
|
+
@Arg('conversationDetailId', { nullable: true }) conversationDetailId?: string
|
|
469
472
|
): Promise<AIAgentRunResult> {
|
|
470
473
|
const p = GetReadWriteProvider(providers);
|
|
471
474
|
return this.executeAIAgent(
|
|
@@ -479,7 +482,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
479
482
|
templateData,
|
|
480
483
|
lastRunId,
|
|
481
484
|
autoPopulateLastRunPayload,
|
|
482
|
-
configurationId
|
|
485
|
+
configurationId,
|
|
486
|
+
conversationDetailId
|
|
483
487
|
);
|
|
484
488
|
}
|
|
485
489
|
|
|
@@ -499,7 +503,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
499
503
|
@Arg('templateData', { nullable: true }) templateData?: string,
|
|
500
504
|
@Arg('lastRunId', { nullable: true }) lastRunId?: string,
|
|
501
505
|
@Arg('autoPopulateLastRunPayload', { nullable: true }) autoPopulateLastRunPayload?: boolean,
|
|
502
|
-
@Arg('configurationId', { nullable: true }) configurationId?: string
|
|
506
|
+
@Arg('configurationId', { nullable: true }) configurationId?: string,
|
|
507
|
+
@Arg('conversationDetailId', { nullable: true }) conversationDetailId?: string
|
|
503
508
|
): Promise<AIAgentRunResult> {
|
|
504
509
|
const p = GetReadWriteProvider(providers);
|
|
505
510
|
return this.executeAIAgent(
|
|
@@ -513,7 +518,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
513
518
|
templateData,
|
|
514
519
|
lastRunId,
|
|
515
520
|
autoPopulateLastRunPayload,
|
|
516
|
-
configurationId
|
|
521
|
+
configurationId,
|
|
522
|
+
conversationDetailId
|
|
517
523
|
);
|
|
518
524
|
}
|
|
519
525
|
|