@memberjunction/server 2.43.0 → 2.44.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/README.md +228 -2
- package/dist/generated/generated.d.ts +5 -5
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +29 -29
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +75 -45
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/RunAIPromptResolver.d.ts +19 -0
- package/dist/resolvers/RunAIPromptResolver.d.ts.map +1 -0
- package/dist/resolvers/RunAIPromptResolver.js +188 -0
- package/dist/resolvers/RunAIPromptResolver.js.map +1 -0
- package/dist/resolvers/RunTemplateResolver.d.ts +14 -0
- package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -0
- package/dist/resolvers/RunTemplateResolver.js +138 -0
- package/dist/resolvers/RunTemplateResolver.js.map +1 -0
- package/package.json +23 -22
- package/src/generated/generated.ts +20 -20
- package/src/generic/ResolverBase.ts +2 -1
- package/src/index.ts +2 -0
- package/src/resolvers/AskSkipResolver.ts +115 -73
- package/src/resolvers/RunAIPromptResolver.ts +169 -0
- package/src/resolvers/RunTemplateResolver.ts +130 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
2
|
+
import { UserPayload } from '../types.js';
|
|
3
|
+
import { LogError, LogStatus, Metadata } from '@memberjunction/core';
|
|
4
|
+
import { AIPromptEntity } from '@memberjunction/core-entities';
|
|
5
|
+
import { AIPromptRunner, AIPromptParams } from '@memberjunction/ai-prompts';
|
|
6
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
7
|
+
|
|
8
|
+
@ObjectType()
|
|
9
|
+
export class AIPromptRunResult {
|
|
10
|
+
@Field()
|
|
11
|
+
success: boolean;
|
|
12
|
+
|
|
13
|
+
@Field({ nullable: true })
|
|
14
|
+
output?: string;
|
|
15
|
+
|
|
16
|
+
@Field({ nullable: true })
|
|
17
|
+
parsedResult?: string;
|
|
18
|
+
|
|
19
|
+
@Field({ nullable: true })
|
|
20
|
+
error?: string;
|
|
21
|
+
|
|
22
|
+
@Field({ nullable: true })
|
|
23
|
+
executionTimeMs?: number;
|
|
24
|
+
|
|
25
|
+
@Field({ nullable: true })
|
|
26
|
+
tokensUsed?: number;
|
|
27
|
+
|
|
28
|
+
@Field({ nullable: true })
|
|
29
|
+
promptRunId?: string;
|
|
30
|
+
|
|
31
|
+
@Field({ nullable: true })
|
|
32
|
+
rawResult?: string;
|
|
33
|
+
|
|
34
|
+
@Field({ nullable: true })
|
|
35
|
+
validationResult?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Resolver()
|
|
39
|
+
export class RunAIPromptResolver extends ResolverBase {
|
|
40
|
+
@Mutation(() => AIPromptRunResult)
|
|
41
|
+
async RunAIPrompt(
|
|
42
|
+
@Arg('promptId') promptId: string,
|
|
43
|
+
@Ctx() { userPayload }: { userPayload: UserPayload },
|
|
44
|
+
@Arg('data', { nullable: true }) data?: string,
|
|
45
|
+
@Arg('modelId', { nullable: true }) modelId?: string,
|
|
46
|
+
@Arg('vendorId', { nullable: true }) vendorId?: string,
|
|
47
|
+
@Arg('configurationId', { nullable: true }) configurationId?: string,
|
|
48
|
+
@Arg('skipValidation', { nullable: true }) skipValidation?: boolean,
|
|
49
|
+
@Arg('templateData', { nullable: true }) templateData?: string
|
|
50
|
+
): Promise<AIPromptRunResult> {
|
|
51
|
+
const startTime = Date.now();
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
LogStatus(`=== RUNNING AI PROMPT FOR ID: ${promptId} ===`);
|
|
55
|
+
|
|
56
|
+
// Parse data contexts (JSON strings)
|
|
57
|
+
let parsedData = {};
|
|
58
|
+
let parsedTemplateData = {};
|
|
59
|
+
|
|
60
|
+
if (data) {
|
|
61
|
+
try {
|
|
62
|
+
parsedData = JSON.parse(data);
|
|
63
|
+
} catch (parseError) {
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: `Invalid JSON in data: ${(parseError as Error).message}`,
|
|
67
|
+
executionTimeMs: Date.now() - startTime
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (templateData) {
|
|
73
|
+
try {
|
|
74
|
+
parsedTemplateData = JSON.parse(templateData);
|
|
75
|
+
} catch (parseError) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
error: `Invalid JSON in template data: ${(parseError as Error).message}`,
|
|
79
|
+
executionTimeMs: Date.now() - startTime
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get current user from payload
|
|
85
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
86
|
+
if (!currentUser) {
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
error: 'Unable to determine current user',
|
|
90
|
+
executionTimeMs: Date.now() - startTime
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const md = new Metadata();
|
|
95
|
+
|
|
96
|
+
// Load the AI prompt entity
|
|
97
|
+
const promptEntity = await md.GetEntityObject<AIPromptEntity>('AI Prompts', currentUser);
|
|
98
|
+
await promptEntity.Load(promptId);
|
|
99
|
+
|
|
100
|
+
if (!promptEntity.IsSaved) {
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
error: `AI Prompt with ID ${promptId} not found`,
|
|
104
|
+
executionTimeMs: Date.now() - startTime
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check if prompt is active
|
|
109
|
+
if (promptEntity.Status !== 'Active') {
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
error: `AI Prompt "${promptEntity.Name}" is not active (Status: ${promptEntity.Status})`,
|
|
113
|
+
executionTimeMs: Date.now() - startTime
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Create AI prompt runner and execute
|
|
118
|
+
const promptRunner = new AIPromptRunner();
|
|
119
|
+
|
|
120
|
+
// Build execution parameters
|
|
121
|
+
const promptParams = new AIPromptParams();
|
|
122
|
+
promptParams.prompt = promptEntity;
|
|
123
|
+
promptParams.data = parsedData;
|
|
124
|
+
promptParams.templateData = parsedTemplateData;
|
|
125
|
+
promptParams.modelId = modelId;
|
|
126
|
+
promptParams.vendorId = vendorId;
|
|
127
|
+
promptParams.configurationId = configurationId;
|
|
128
|
+
promptParams.contextUser = currentUser;
|
|
129
|
+
promptParams.skipValidation = skipValidation || false;
|
|
130
|
+
|
|
131
|
+
// Execute the prompt
|
|
132
|
+
const result = await promptRunner.ExecutePrompt(promptParams);
|
|
133
|
+
|
|
134
|
+
const executionTime = Date.now() - startTime;
|
|
135
|
+
|
|
136
|
+
if (result.success) {
|
|
137
|
+
LogStatus(`=== AI PROMPT RUN COMPLETED FOR: ${promptEntity.Name} (${executionTime}ms) ===`);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
success: true,
|
|
141
|
+
output: result.rawResult,
|
|
142
|
+
parsedResult: typeof result.result === 'string' ? result.result : JSON.stringify(result.result),
|
|
143
|
+
rawResult: result.rawResult,
|
|
144
|
+
executionTimeMs: executionTime,
|
|
145
|
+
tokensUsed: result.tokensUsed,
|
|
146
|
+
promptRunId: result.promptRun?.ID,
|
|
147
|
+
validationResult: result.validationResult ? JSON.stringify(result.validationResult) : undefined
|
|
148
|
+
};
|
|
149
|
+
} else {
|
|
150
|
+
LogError(`AI Prompt run failed for ${promptEntity.Name}: ${result.errorMessage}`);
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
error: result.errorMessage,
|
|
154
|
+
executionTimeMs: executionTime,
|
|
155
|
+
promptRunId: result.promptRun?.ID
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
} catch (error) {
|
|
160
|
+
const executionTime = Date.now() - startTime;
|
|
161
|
+
LogError(`AI Prompt run failed:`, undefined, error);
|
|
162
|
+
return {
|
|
163
|
+
success: false,
|
|
164
|
+
error: (error as Error).message || 'Unknown error occurred',
|
|
165
|
+
executionTimeMs: executionTime
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
2
|
+
import { UserPayload } from '../types.js';
|
|
3
|
+
import { LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
|
|
4
|
+
import { TemplateContentEntity } from '@memberjunction/core-entities';
|
|
5
|
+
import { TemplateEngineServer } from '@memberjunction/templates';
|
|
6
|
+
import { TemplateEntityExtended } from '@memberjunction/templates-base-types';
|
|
7
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
8
|
+
|
|
9
|
+
@ObjectType()
|
|
10
|
+
export class TemplateRunResult {
|
|
11
|
+
@Field()
|
|
12
|
+
success: boolean;
|
|
13
|
+
|
|
14
|
+
@Field({ nullable: true })
|
|
15
|
+
output?: string;
|
|
16
|
+
|
|
17
|
+
@Field({ nullable: true })
|
|
18
|
+
error?: string;
|
|
19
|
+
|
|
20
|
+
@Field({ nullable: true })
|
|
21
|
+
executionTimeMs?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Resolver()
|
|
25
|
+
export class RunTemplateResolver extends ResolverBase {
|
|
26
|
+
@Mutation(() => TemplateRunResult)
|
|
27
|
+
async RunTemplate(
|
|
28
|
+
@Arg('templateId') templateId: string,
|
|
29
|
+
@Ctx() { userPayload }: { userPayload: UserPayload },
|
|
30
|
+
@Arg('contextData', { nullable: true }) contextData?: string
|
|
31
|
+
): Promise<TemplateRunResult> {
|
|
32
|
+
const startTime = Date.now();
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
LogStatus(`=== RUNNING TEMPLATE FOR ID: ${templateId} ===`);
|
|
36
|
+
|
|
37
|
+
// Parse context data (JSON string)
|
|
38
|
+
let data = {};
|
|
39
|
+
if (contextData) {
|
|
40
|
+
try {
|
|
41
|
+
data = JSON.parse(contextData);
|
|
42
|
+
} catch (parseError) {
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
error: `Invalid JSON in context data: ${(parseError as Error).message}`,
|
|
46
|
+
executionTimeMs: Date.now() - startTime
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Get current user from payload
|
|
52
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
53
|
+
if (!currentUser) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: 'Unable to determine current user',
|
|
57
|
+
executionTimeMs: Date.now() - startTime
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const md = new Metadata();
|
|
62
|
+
|
|
63
|
+
// Load the template entity
|
|
64
|
+
const templateEntity = await md.GetEntityObject<TemplateEntityExtended>('Templates', currentUser);
|
|
65
|
+
await templateEntity.Load(templateId);
|
|
66
|
+
|
|
67
|
+
if (!templateEntity.IsSaved) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
error: `Template with ID ${templateId} not found`,
|
|
71
|
+
executionTimeMs: Date.now() - startTime
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Load template content (get the first/highest priority content)
|
|
76
|
+
const rv = new RunView();
|
|
77
|
+
const templateContentResult = await rv.RunView<TemplateContentEntity>({
|
|
78
|
+
EntityName: 'Template Contents',
|
|
79
|
+
ExtraFilter: `TemplateID = '${templateId}'`,
|
|
80
|
+
OrderBy: 'Priority ASC',
|
|
81
|
+
MaxRows: 1,
|
|
82
|
+
ResultType: 'entity_object'
|
|
83
|
+
}, currentUser);
|
|
84
|
+
|
|
85
|
+
if (!templateContentResult.Results || templateContentResult.Results.length === 0) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: `No template content found for template ${templateEntity.Name}`,
|
|
89
|
+
executionTimeMs: Date.now() - startTime
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Configure and render the template
|
|
94
|
+
await TemplateEngineServer.Instance.Config(true /*always refresh to get latest templates*/, currentUser);
|
|
95
|
+
const result = await TemplateEngineServer.Instance.RenderTemplate(
|
|
96
|
+
templateEntity,
|
|
97
|
+
templateContentResult.Results[0],
|
|
98
|
+
data,
|
|
99
|
+
true // skip validation for execution
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const executionTime = Date.now() - startTime;
|
|
103
|
+
|
|
104
|
+
if (result.Success) {
|
|
105
|
+
LogStatus(`=== TEMPLATE RUN COMPLETED FOR: ${templateEntity.Name} (${executionTime}ms) ===`);
|
|
106
|
+
return {
|
|
107
|
+
success: true,
|
|
108
|
+
output: result.Output,
|
|
109
|
+
executionTimeMs: executionTime
|
|
110
|
+
};
|
|
111
|
+
} else {
|
|
112
|
+
LogError(`Template run failed for ${templateEntity.Name}: ${result.Message}`);
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
error: result.Message,
|
|
116
|
+
executionTimeMs: executionTime
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
} catch (error) {
|
|
121
|
+
const executionTime = Date.now() - startTime;
|
|
122
|
+
LogError(`Template run failed:`, undefined, error);
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
error: (error as Error).message || 'Unknown error occurred',
|
|
126
|
+
executionTimeMs: executionTime
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|