@memberjunction/ai-prompts 2.47.0 → 2.49.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 +565 -29
- package/dist/AIPromptCategoryExtended.d.ts.map +1 -1
- package/dist/AIPromptCategoryExtended.js +2 -2
- package/dist/AIPromptCategoryExtended.js.map +1 -1
- package/dist/AIPromptRunner.d.ts +4 -85
- package/dist/AIPromptRunner.d.ts.map +1 -1
- package/dist/AIPromptRunner.js +235 -103
- package/dist/AIPromptRunner.js.map +1 -1
- package/dist/ParallelExecutionCoordinator.d.ts +1 -1
- package/dist/ParallelExecutionCoordinator.d.ts.map +1 -1
- package/dist/ParallelExecutionCoordinator.js +14 -11
- package/dist/ParallelExecutionCoordinator.js.map +1 -1
- package/dist/SystemPlaceholders.d.ts +18 -0
- package/dist/SystemPlaceholders.d.ts.map +1 -0
- package/dist/SystemPlaceholders.js +239 -0
- package/dist/SystemPlaceholders.js.map +1 -0
- 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/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/package.json +10 -7
package/dist/AIPromptRunner.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.LoadAIPromptRunner = exports.AIPromptRunner = exports.
|
|
6
|
+
exports.LoadAIPromptRunner = exports.AIPromptRunner = exports.AIPromptParams = void 0;
|
|
7
7
|
const ai_1 = require("@memberjunction/ai");
|
|
8
8
|
const core_1 = require("@memberjunction/core");
|
|
9
9
|
const global_1 = require("@memberjunction/global");
|
|
@@ -12,12 +12,9 @@ const ExecutionPlanner_1 = require("./ExecutionPlanner");
|
|
|
12
12
|
const ParallelExecutionCoordinator_1 = require("./ParallelExecutionCoordinator");
|
|
13
13
|
const aiengine_1 = require("@memberjunction/aiengine");
|
|
14
14
|
const ajv_1 = __importDefault(require("ajv"));
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
exports
|
|
18
|
-
class AIPromptRunResult {
|
|
19
|
-
}
|
|
20
|
-
exports.AIPromptRunResult = AIPromptRunResult;
|
|
15
|
+
const SystemPlaceholders_1 = require("./SystemPlaceholders");
|
|
16
|
+
var types_1 = require("./types");
|
|
17
|
+
Object.defineProperty(exports, "AIPromptParams", { enumerable: true, get: function () { return types_1.AIPromptParams; } });
|
|
21
18
|
class AIPromptRunner {
|
|
22
19
|
constructor() {
|
|
23
20
|
this._metadata = new core_1.Metadata();
|
|
@@ -43,7 +40,7 @@ class AIPromptRunner {
|
|
|
43
40
|
const startTime = new Date();
|
|
44
41
|
const promptRun = null;
|
|
45
42
|
if (params.cancellationToken?.aborted) {
|
|
46
|
-
|
|
43
|
+
const result = {
|
|
47
44
|
success: false,
|
|
48
45
|
status: 'cancelled',
|
|
49
46
|
cancelled: true,
|
|
@@ -51,7 +48,10 @@ class AIPromptRunner {
|
|
|
51
48
|
errorMessage: 'Prompt execution was cancelled before starting',
|
|
52
49
|
executionTimeMS: 0,
|
|
53
50
|
chatResult: { success: false, errorMessage: 'Prompt execution was cancelled before starting' },
|
|
51
|
+
tokensUsed: 0,
|
|
52
|
+
combinedTokensUsed: 0
|
|
54
53
|
};
|
|
54
|
+
return result;
|
|
55
55
|
}
|
|
56
56
|
try {
|
|
57
57
|
const prompt = params.prompt;
|
|
@@ -62,13 +62,28 @@ class AIPromptRunner {
|
|
|
62
62
|
throw new Error(`Prompt ${prompt.Name} is not active (Status: ${prompt.Status})`);
|
|
63
63
|
}
|
|
64
64
|
let renderedPromptText = '';
|
|
65
|
-
|
|
65
|
+
let parentPromptRun;
|
|
66
|
+
let selectedModel;
|
|
67
|
+
let childTemplateRenderingResult;
|
|
68
|
+
if (params.childPrompts && params.childPrompts.length > 0) {
|
|
69
|
+
(0, core_1.LogStatus)(`🌳 Composing prompt with ${params.childPrompts.length} child templates in hierarchical mode`);
|
|
70
|
+
selectedModel = await this.selectModel(prompt, params.modelId, params.contextUser, params.configurationId, params.vendorId);
|
|
71
|
+
if (!selectedModel) {
|
|
72
|
+
throw new Error(`No suitable model found for prompt ${prompt.Name}`);
|
|
73
|
+
}
|
|
74
|
+
parentPromptRun = await this.createPromptRun(prompt, selectedModel, params, startTime, params.vendorId);
|
|
75
|
+
(0, core_1.LogStatus)(`📝 Created prompt run ${parentPromptRun.ID} for hierarchical template composition`);
|
|
76
|
+
childTemplateRenderingResult = await this.renderChildPromptTemplates(params.childPrompts, params, params.cancellationToken);
|
|
77
|
+
renderedPromptText = await this.renderPromptWithChildTemplates(prompt, params, childTemplateRenderingResult.renderedTemplates);
|
|
78
|
+
(0, core_1.LogStatus)(`✅ Hierarchical template composition completed with ${Object.keys(childTemplateRenderingResult.renderedTemplates).length} child templates embedded`);
|
|
79
|
+
}
|
|
80
|
+
else if (prompt.TemplateID && (!params.conversationMessages || params.templateMessageRole !== 'none')) {
|
|
66
81
|
await this._templateEngine.Config(false, params.contextUser);
|
|
67
82
|
const template = await this.loadTemplate(prompt.TemplateID, params.contextUser);
|
|
68
83
|
if (!template) {
|
|
69
84
|
throw new Error(`Template with ID ${prompt.TemplateID} not found for prompt ${prompt.Name}`);
|
|
70
85
|
}
|
|
71
|
-
const renderedPrompt = await this.renderPromptTemplate(template, params
|
|
86
|
+
const renderedPrompt = await this.renderPromptTemplate(template, params);
|
|
72
87
|
if (!renderedPrompt.Success) {
|
|
73
88
|
throw new Error(`Failed to render template for prompt ${prompt.Name}: ${renderedPrompt.Message}`);
|
|
74
89
|
}
|
|
@@ -78,12 +93,14 @@ class AIPromptRunner {
|
|
|
78
93
|
throw new Error('Prompt execution was cancelled during template rendering');
|
|
79
94
|
}
|
|
80
95
|
const shouldUseParallelExecution = prompt.ParallelizationMode && prompt.ParallelizationMode !== 'None';
|
|
96
|
+
let result;
|
|
81
97
|
if (shouldUseParallelExecution) {
|
|
82
|
-
|
|
98
|
+
result = await this.executePromptInParallel(prompt, renderedPromptText, params, startTime, parentPromptRun);
|
|
83
99
|
}
|
|
84
100
|
else {
|
|
85
|
-
|
|
101
|
+
result = await this.executeSinglePrompt(prompt, renderedPromptText, params, startTime, parentPromptRun, selectedModel);
|
|
86
102
|
}
|
|
103
|
+
return result;
|
|
87
104
|
}
|
|
88
105
|
catch (error) {
|
|
89
106
|
(0, core_1.LogError)(error);
|
|
@@ -98,27 +115,30 @@ class AIPromptRunner {
|
|
|
98
115
|
(0, core_1.LogError)(`Failed to save error to AIPromptRun: ${promptRun.LatestResult?.Message || 'Unknown error'}`);
|
|
99
116
|
}
|
|
100
117
|
}
|
|
101
|
-
|
|
118
|
+
const errorResult = {
|
|
102
119
|
success: false,
|
|
103
120
|
errorMessage: error.message,
|
|
104
121
|
promptRun,
|
|
105
122
|
executionTimeMS,
|
|
106
123
|
chatResult: { success: false, errorMessage: error.message },
|
|
124
|
+
tokensUsed: 0,
|
|
125
|
+
combinedTokensUsed: 0
|
|
107
126
|
};
|
|
127
|
+
return errorResult;
|
|
108
128
|
}
|
|
109
129
|
}
|
|
110
|
-
async executeSinglePrompt(prompt, renderedPromptText, params, startTime) {
|
|
130
|
+
async executeSinglePrompt(prompt, renderedPromptText, params, startTime, existingPromptRun, existingModel) {
|
|
111
131
|
if (params.cancellationToken?.aborted) {
|
|
112
132
|
throw new Error('Prompt execution was cancelled before model selection');
|
|
113
133
|
}
|
|
114
|
-
const selectedModel = await this.selectModel(prompt, params.modelId, params.contextUser, params.configurationId, params.vendorId);
|
|
134
|
+
const selectedModel = existingModel || await this.selectModel(prompt, params.modelId, params.contextUser, params.configurationId, params.vendorId);
|
|
115
135
|
if (!selectedModel) {
|
|
116
136
|
throw new Error(`No suitable model found for prompt ${prompt.Name}`);
|
|
117
137
|
}
|
|
118
138
|
if (params.cancellationToken?.aborted) {
|
|
119
139
|
throw new Error('Prompt execution was cancelled after model selection');
|
|
120
140
|
}
|
|
121
|
-
const promptRun = await this.createPromptRun(prompt, selectedModel, params, startTime, params.vendorId);
|
|
141
|
+
const promptRun = existingPromptRun || await this.createPromptRun(prompt, selectedModel, params, startTime, params.vendorId);
|
|
122
142
|
if (params.cancellationToken?.aborted) {
|
|
123
143
|
throw new Error('Prompt execution was cancelled before model execution');
|
|
124
144
|
}
|
|
@@ -127,6 +147,7 @@ class AIPromptRunner {
|
|
|
127
147
|
const executionTimeMS = endTime.getTime() - startTime.getTime();
|
|
128
148
|
await this.updatePromptRun(promptRun, modelResult, parsedResult, endTime, executionTimeMS, validationAttempts);
|
|
129
149
|
const chatResult = modelResult;
|
|
150
|
+
const usage = chatResult.data?.usage;
|
|
130
151
|
return {
|
|
131
152
|
success: true,
|
|
132
153
|
rawResult: chatResult.data?.choices?.[0]?.message?.content,
|
|
@@ -134,12 +155,17 @@ class AIPromptRunner {
|
|
|
134
155
|
chatResult,
|
|
135
156
|
promptRun,
|
|
136
157
|
executionTimeMS,
|
|
137
|
-
|
|
158
|
+
promptTokens: usage?.promptTokens,
|
|
159
|
+
completionTokens: usage?.completionTokens,
|
|
160
|
+
tokensUsed: (usage?.promptTokens || 0) + (usage?.completionTokens || 0),
|
|
161
|
+
cost: usage?.cost,
|
|
162
|
+
costCurrency: usage?.costCurrency,
|
|
138
163
|
validationResult: parsedResult.validationResult,
|
|
139
164
|
validationAttempts,
|
|
165
|
+
combinedTokensUsed: (usage?.promptTokens || 0) + (usage?.completionTokens || 0)
|
|
140
166
|
};
|
|
141
167
|
}
|
|
142
|
-
async executePromptInParallel(prompt, renderedPromptText, params, startTime) {
|
|
168
|
+
async executePromptInParallel(prompt, renderedPromptText, params, startTime, existingPromptRun) {
|
|
143
169
|
if (params.cancellationToken?.aborted) {
|
|
144
170
|
throw new Error('Parallel execution was cancelled before starting');
|
|
145
171
|
}
|
|
@@ -154,7 +180,7 @@ class AIPromptRunner {
|
|
|
154
180
|
if (params.cancellationToken?.aborted) {
|
|
155
181
|
throw new Error('Parallel execution was cancelled before task execution');
|
|
156
182
|
}
|
|
157
|
-
const parallelResult = await this._parallelCoordinator.executeTasksInParallel(executionTasks, undefined, undefined, params.cancellationToken);
|
|
183
|
+
const parallelResult = await this._parallelCoordinator.executeTasksInParallel(executionTasks, undefined, undefined, params.cancellationToken, undefined, params.agentRunId);
|
|
158
184
|
if (!parallelResult.success) {
|
|
159
185
|
throw new Error(`Parallel execution failed: ${parallelResult.errors.join(', ')}`);
|
|
160
186
|
}
|
|
@@ -173,12 +199,38 @@ class AIPromptRunner {
|
|
|
173
199
|
selectedResult = aiSelectedResult;
|
|
174
200
|
}
|
|
175
201
|
}
|
|
176
|
-
|
|
202
|
+
let totalPromptTokens = 0;
|
|
203
|
+
let totalCompletionTokens = 0;
|
|
204
|
+
let totalCost = 0;
|
|
205
|
+
let hasCost = false;
|
|
206
|
+
for (const result of successfulResults) {
|
|
207
|
+
const usage = result.modelResult?.data?.usage;
|
|
208
|
+
if (usage) {
|
|
209
|
+
totalPromptTokens += usage.promptTokens || 0;
|
|
210
|
+
totalCompletionTokens += usage.completionTokens || 0;
|
|
211
|
+
if (usage.cost !== undefined) {
|
|
212
|
+
totalCost += usage.cost;
|
|
213
|
+
hasCost = true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const consolidatedPromptRun = existingPromptRun || await this.createPromptRun(prompt, selectedResult.task.model, params, startTime, params.vendorId);
|
|
177
218
|
const endTime = new Date();
|
|
178
219
|
consolidatedPromptRun.CompletedAt = endTime;
|
|
179
220
|
consolidatedPromptRun.ExecutionTimeMS = parallelResult.totalExecutionTimeMS;
|
|
180
221
|
consolidatedPromptRun.Result = selectedResult.rawResult || '';
|
|
181
222
|
consolidatedPromptRun.TokensUsed = parallelResult.totalTokensUsed;
|
|
223
|
+
const selectedResultUsage = selectedResult.modelResult?.data?.usage;
|
|
224
|
+
if (selectedResultUsage) {
|
|
225
|
+
consolidatedPromptRun.TokensPrompt = selectedResultUsage.promptTokens;
|
|
226
|
+
consolidatedPromptRun.TokensCompletion = selectedResultUsage.completionTokens;
|
|
227
|
+
if (selectedResultUsage.cost !== undefined) {
|
|
228
|
+
consolidatedPromptRun.Cost = selectedResultUsage.cost;
|
|
229
|
+
}
|
|
230
|
+
if (selectedResultUsage.costCurrency !== undefined) {
|
|
231
|
+
consolidatedPromptRun.CostCurrency = selectedResultUsage.costCurrency;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
182
234
|
const parallelMetadata = {
|
|
183
235
|
parallelizationMode: prompt.ParallelizationMode,
|
|
184
236
|
totalTasks: executionTasks.length,
|
|
@@ -194,6 +246,12 @@ class AIPromptRunner {
|
|
|
194
246
|
parallelExecution: parallelMetadata,
|
|
195
247
|
});
|
|
196
248
|
}
|
|
249
|
+
consolidatedPromptRun.TokensPromptRollup = totalPromptTokens;
|
|
250
|
+
consolidatedPromptRun.TokensCompletionRollup = totalCompletionTokens;
|
|
251
|
+
consolidatedPromptRun.TokensUsedRollup = totalPromptTokens + totalCompletionTokens;
|
|
252
|
+
if (hasCost) {
|
|
253
|
+
consolidatedPromptRun.TotalCost = totalCost;
|
|
254
|
+
}
|
|
197
255
|
const saveResult = await consolidatedPromptRun.Save();
|
|
198
256
|
if (!saveResult) {
|
|
199
257
|
(0, core_1.LogError)(`Failed to save consolidated AIPromptRun: ${consolidatedPromptRun.LatestResult?.Message || 'Unknown error'}`);
|
|
@@ -209,13 +267,18 @@ class AIPromptRunner {
|
|
|
209
267
|
if (result.task.taskId !== selectedResult.task.taskId) {
|
|
210
268
|
const { result: parsedResultData, validationResult, validationErrors } = await this.parseAndValidateResultEnhanced(result.modelResult, prompt, params.skipValidation);
|
|
211
269
|
const parsedResult = { result: parsedResultData, validationResult };
|
|
270
|
+
const resultUsage = result.modelResult?.data?.usage;
|
|
212
271
|
additionalResults.push({
|
|
213
272
|
success: result.success,
|
|
214
273
|
rawResult: result.rawResult,
|
|
215
274
|
result: parsedResult.result,
|
|
216
275
|
chatResult: result.modelResult,
|
|
217
276
|
executionTimeMS: result.executionTimeMS,
|
|
218
|
-
|
|
277
|
+
promptTokens: resultUsage?.promptTokens,
|
|
278
|
+
completionTokens: resultUsage?.completionTokens,
|
|
279
|
+
tokensUsed: (resultUsage?.promptTokens || 0) + (resultUsage?.completionTokens || 0),
|
|
280
|
+
cost: resultUsage?.cost,
|
|
281
|
+
costCurrency: resultUsage?.costCurrency,
|
|
219
282
|
validationResult: parsedResult.validationResult,
|
|
220
283
|
ranking: result.ranking,
|
|
221
284
|
judgeRationale: result.judgeRationale,
|
|
@@ -225,11 +288,13 @@ class AIPromptRunner {
|
|
|
225
288
|
vendorId: undefined,
|
|
226
289
|
vendorName: result.task.model.Vendor,
|
|
227
290
|
},
|
|
291
|
+
combinedTokensUsed: (resultUsage?.promptTokens || 0) + (resultUsage?.completionTokens || 0)
|
|
228
292
|
});
|
|
229
293
|
}
|
|
230
294
|
}
|
|
231
295
|
const { result: selectedResultData, validationResult: selectedValidationResult } = await this.parseAndValidateResultEnhanced(selectedResult.modelResult, prompt, params.skipValidation);
|
|
232
296
|
const selectedParsedResult = { result: selectedResultData, validationResult: selectedValidationResult };
|
|
297
|
+
const selectedUsage = selectedResult.modelResult?.data?.usage;
|
|
233
298
|
return {
|
|
234
299
|
success: true,
|
|
235
300
|
rawResult: selectedResult.rawResult,
|
|
@@ -237,7 +302,15 @@ class AIPromptRunner {
|
|
|
237
302
|
chatResult: selectedResult.modelResult,
|
|
238
303
|
promptRun: consolidatedPromptRun,
|
|
239
304
|
executionTimeMS: parallelResult.totalExecutionTimeMS,
|
|
240
|
-
|
|
305
|
+
promptTokens: selectedUsage?.promptTokens,
|
|
306
|
+
completionTokens: selectedUsage?.completionTokens,
|
|
307
|
+
tokensUsed: (selectedUsage?.promptTokens || 0) + (selectedUsage?.completionTokens || 0),
|
|
308
|
+
cost: selectedUsage?.cost,
|
|
309
|
+
costCurrency: selectedUsage?.costCurrency,
|
|
310
|
+
combinedPromptTokens: totalPromptTokens,
|
|
311
|
+
combinedCompletionTokens: totalCompletionTokens,
|
|
312
|
+
combinedTokensUsed: totalPromptTokens + totalCompletionTokens,
|
|
313
|
+
combinedCost: hasCost ? totalCost : undefined,
|
|
241
314
|
validationResult: selectedParsedResult.validationResult,
|
|
242
315
|
additionalResults: additionalResults.length > 0 ? additionalResults : undefined,
|
|
243
316
|
ranking: selectedResult.ranking || 1,
|
|
@@ -261,6 +334,115 @@ class AIPromptRunner {
|
|
|
261
334
|
return null;
|
|
262
335
|
}
|
|
263
336
|
}
|
|
337
|
+
async renderChildPromptTemplates(childPrompts, params, cancellationToken) {
|
|
338
|
+
if (!childPrompts || childPrompts.length === 0) {
|
|
339
|
+
return {
|
|
340
|
+
renderedTemplates: {}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
if (cancellationToken?.aborted) {
|
|
344
|
+
throw new Error('Child prompt execution was cancelled');
|
|
345
|
+
}
|
|
346
|
+
(0, core_1.LogStatus)(`🔄 Rendering ${childPrompts.length} child prompt templates in parallel`);
|
|
347
|
+
const childRenderingPromises = childPrompts.map(async (childParam) => {
|
|
348
|
+
try {
|
|
349
|
+
if (cancellationToken?.aborted) {
|
|
350
|
+
throw new Error('Child prompt template rendering was cancelled');
|
|
351
|
+
}
|
|
352
|
+
let childData = { ...childParam.childPrompt.data };
|
|
353
|
+
if (childParam.childPrompt.childPrompts && childParam.childPrompt.childPrompts.length > 0) {
|
|
354
|
+
const grandchildResults = await this.renderChildPromptTemplates(childParam.childPrompt.childPrompts, params, cancellationToken);
|
|
355
|
+
childData = { ...childData, ...grandchildResults.renderedTemplates };
|
|
356
|
+
}
|
|
357
|
+
(0, core_1.LogStatus)(` 🔹 Rendering child prompt template: ${childParam.childPrompt.prompt.Name} -> ${childParam.parentPlaceholder}`);
|
|
358
|
+
const childPrompt = childParam.childPrompt.prompt;
|
|
359
|
+
let renderedChildTemplate = '';
|
|
360
|
+
if (childPrompt.TemplateID) {
|
|
361
|
+
await this._templateEngine.Config(false, params.contextUser);
|
|
362
|
+
const template = await this.loadTemplate(childPrompt.TemplateID, params.contextUser);
|
|
363
|
+
if (!template) {
|
|
364
|
+
throw new Error(`Template with ID ${childPrompt.TemplateID} not found for child prompt ${childPrompt.Name}`);
|
|
365
|
+
}
|
|
366
|
+
const mergedChildData = {
|
|
367
|
+
...params.data,
|
|
368
|
+
...childData,
|
|
369
|
+
...childParam.childPrompt.templateData
|
|
370
|
+
};
|
|
371
|
+
const childRenderResult = await this.renderPromptTemplate(template, {
|
|
372
|
+
...params,
|
|
373
|
+
data: mergedChildData,
|
|
374
|
+
templateData: childParam.childPrompt.templateData
|
|
375
|
+
});
|
|
376
|
+
if (!childRenderResult.Success) {
|
|
377
|
+
throw new Error(`Failed to render child template for prompt ${childPrompt.Name}: ${childRenderResult.Message}`);
|
|
378
|
+
}
|
|
379
|
+
renderedChildTemplate = childRenderResult.Output;
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
renderedChildTemplate = '';
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
placeholder: childParam.parentPlaceholder,
|
|
386
|
+
renderedTemplate: renderedChildTemplate,
|
|
387
|
+
success: true
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
(0, core_1.LogError)(`Error rendering child prompt template for placeholder ${childParam.parentPlaceholder}: ${error.message}`);
|
|
392
|
+
return {
|
|
393
|
+
placeholder: childParam.parentPlaceholder,
|
|
394
|
+
renderedTemplate: `ERROR: ${error.message}`,
|
|
395
|
+
success: false
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
const childResults = await Promise.all(childRenderingPromises);
|
|
400
|
+
const failedChildren = childResults.filter(r => !r.success);
|
|
401
|
+
if (failedChildren.length > 0) {
|
|
402
|
+
(0, core_1.LogError)(`${failedChildren.length} out of ${childResults.length} child prompt templates failed to render`);
|
|
403
|
+
}
|
|
404
|
+
const renderedTemplatesMap = {};
|
|
405
|
+
for (const childResult of childResults) {
|
|
406
|
+
renderedTemplatesMap[childResult.placeholder] = childResult.renderedTemplate;
|
|
407
|
+
}
|
|
408
|
+
(0, core_1.LogStatus)(`✅ Completed rendering of ${childResults.length} child prompt templates`);
|
|
409
|
+
return {
|
|
410
|
+
renderedTemplates: renderedTemplatesMap
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
async renderPromptWithChildTemplates(prompt, params, childTemplates) {
|
|
414
|
+
if (!prompt.TemplateID) {
|
|
415
|
+
return '';
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
await this._templateEngine.Config(false, params.contextUser);
|
|
419
|
+
const template = await this.loadTemplate(prompt.TemplateID, params.contextUser);
|
|
420
|
+
if (!template) {
|
|
421
|
+
throw new Error(`Template with ID ${prompt.TemplateID} not found for prompt ${prompt.Name}`);
|
|
422
|
+
}
|
|
423
|
+
const systemPlaceholders = await SystemPlaceholders_1.SystemPlaceholderManager.resolveAllPlaceholders(params);
|
|
424
|
+
const mergedData = {
|
|
425
|
+
...systemPlaceholders,
|
|
426
|
+
...params.data,
|
|
427
|
+
...childTemplates,
|
|
428
|
+
...params.templateData
|
|
429
|
+
};
|
|
430
|
+
(0, core_1.LogStatus)(`🔧 Rendering prompt template with ${Object.keys(childTemplates).length} child templates and ${Object.keys(systemPlaceholders).length} system placeholders`);
|
|
431
|
+
for (const [placeholder, template] of Object.entries(childTemplates)) {
|
|
432
|
+
const truncatedTemplate = template.length > 100 ? template.substring(0, 100) + '...' : template;
|
|
433
|
+
(0, core_1.LogStatus)(` 📝 ${placeholder} -> ${truncatedTemplate}`);
|
|
434
|
+
}
|
|
435
|
+
const renderedPrompt = await this._templateEngine.RenderTemplate(template, template.GetHighestPriorityContent(), mergedData);
|
|
436
|
+
if (!renderedPrompt.Success) {
|
|
437
|
+
throw new Error(`Failed to render template for prompt ${prompt.Name}: ${renderedPrompt.Message}`);
|
|
438
|
+
}
|
|
439
|
+
return renderedPrompt.Output;
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
(0, core_1.LogError)(`Error rendering prompt with child templates: ${error.message}`);
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
264
446
|
async selectModel(prompt, explicitModelId, contextUser, configurationId, vendorId) {
|
|
265
447
|
try {
|
|
266
448
|
await aiengine_1.AIEngine.Instance.Config(false, contextUser);
|
|
@@ -336,8 +518,8 @@ class AIPromptRunner {
|
|
|
336
518
|
}
|
|
337
519
|
}
|
|
338
520
|
async createPromptRun(prompt, model, params, startTime, vendorId) {
|
|
521
|
+
const promptRun = await this._metadata.GetEntityObject('MJ: AI Prompt Runs', params.contextUser);
|
|
339
522
|
try {
|
|
340
|
-
const promptRun = await this._metadata.GetEntityObject('MJ: AI Prompt Runs', params.contextUser);
|
|
341
523
|
promptRun.NewRecord();
|
|
342
524
|
promptRun.PromptID = prompt.ID;
|
|
343
525
|
promptRun.ModelID = model.ID;
|
|
@@ -353,6 +535,12 @@ class AIPromptRunner {
|
|
|
353
535
|
}
|
|
354
536
|
promptRun.ConfigurationID = params.configurationId;
|
|
355
537
|
promptRun.RunAt = startTime;
|
|
538
|
+
if (params.agentRunId) {
|
|
539
|
+
promptRun.AgentRunID = params.agentRunId;
|
|
540
|
+
}
|
|
541
|
+
if (params.parentPromptRunId) {
|
|
542
|
+
promptRun.ParentID = params.parentPromptRunId;
|
|
543
|
+
}
|
|
356
544
|
if (params.data || params.templateData) {
|
|
357
545
|
promptRun.Messages = JSON.stringify({
|
|
358
546
|
data: params.data,
|
|
@@ -368,17 +556,24 @@ class AIPromptRunner {
|
|
|
368
556
|
return promptRun;
|
|
369
557
|
}
|
|
370
558
|
catch (error) {
|
|
371
|
-
|
|
372
|
-
|
|
559
|
+
const msg = `Error creating prompt run record: ${error.message} - ${promptRun?.LatestResult?.Message} - ${promptRun?.LatestResult?.Errors[0]?.Message}`;
|
|
560
|
+
(0, core_1.LogError)(msg);
|
|
561
|
+
throw new Error(msg);
|
|
373
562
|
}
|
|
374
563
|
}
|
|
375
|
-
async renderPromptTemplate(template,
|
|
564
|
+
async renderPromptTemplate(template, params) {
|
|
376
565
|
try {
|
|
377
566
|
const templateContent = template.GetHighestPriorityContent();
|
|
378
567
|
if (!templateContent) {
|
|
379
568
|
throw new Error(`No content found for template ${template.Name}`);
|
|
380
569
|
}
|
|
381
|
-
const
|
|
570
|
+
const systemPlaceholders = await SystemPlaceholders_1.SystemPlaceholderManager.resolveAllPlaceholders(params);
|
|
571
|
+
const mergedData = {
|
|
572
|
+
...systemPlaceholders,
|
|
573
|
+
...params.data,
|
|
574
|
+
...params.templateData
|
|
575
|
+
};
|
|
576
|
+
(0, core_1.LogStatus)(`🔧 Rendering template '${template.Name}' with ${Object.keys(systemPlaceholders).length} system placeholders`);
|
|
382
577
|
return await this._templateEngine.RenderTemplate(template, templateContent, mergedData);
|
|
383
578
|
}
|
|
384
579
|
catch (error) {
|
|
@@ -474,7 +669,6 @@ class AIPromptRunner {
|
|
|
474
669
|
validationAttempts.push(validationAttempt);
|
|
475
670
|
await this.updatePromptRunWithValidationAttempt(promptRun, validationAttempt, attempt + 1, maxRetries + 1);
|
|
476
671
|
if (validationResult?.Success !== false) {
|
|
477
|
-
(0, core_1.LogStatus)(`✅ Validation succeeded on attempt ${attempt + 1}/${maxRetries + 1}`);
|
|
478
672
|
return {
|
|
479
673
|
modelResult,
|
|
480
674
|
parsedResult: { result, validationResult },
|
|
@@ -683,7 +877,7 @@ class AIPromptRunner {
|
|
|
683
877
|
}
|
|
684
878
|
case 'object':
|
|
685
879
|
try {
|
|
686
|
-
parsedResult = JSON.parse(rawOutput);
|
|
880
|
+
parsedResult = JSON.parse((0, global_1.CleanJSON)(rawOutput));
|
|
687
881
|
}
|
|
688
882
|
catch (jsonError) {
|
|
689
883
|
const error = new core_1.ValidationErrorInfo('output', `Expected JSON object but got invalid JSON: ${rawOutput}`, rawOutput, core_1.ValidationErrorType.Failure);
|
|
@@ -788,80 +982,6 @@ class AIPromptRunner {
|
|
|
788
982
|
}
|
|
789
983
|
return validationErrors;
|
|
790
984
|
}
|
|
791
|
-
async parseAndValidateResult(modelResult, prompt, skipValidation = false) {
|
|
792
|
-
try {
|
|
793
|
-
if (!modelResult.success) {
|
|
794
|
-
throw new Error(`Model execution failed: ${modelResult.errorMessage}`);
|
|
795
|
-
}
|
|
796
|
-
const rawOutput = modelResult.data?.choices?.[0]?.message?.content;
|
|
797
|
-
if (!rawOutput) {
|
|
798
|
-
throw new Error('No output received from model');
|
|
799
|
-
}
|
|
800
|
-
let parsedResult = rawOutput;
|
|
801
|
-
switch (prompt.OutputType) {
|
|
802
|
-
case 'string':
|
|
803
|
-
parsedResult = rawOutput.toString();
|
|
804
|
-
break;
|
|
805
|
-
case 'number': {
|
|
806
|
-
const numberResult = parseFloat(rawOutput);
|
|
807
|
-
if (isNaN(numberResult)) {
|
|
808
|
-
throw new Error(`Expected number output but got: ${rawOutput}`);
|
|
809
|
-
}
|
|
810
|
-
parsedResult = numberResult;
|
|
811
|
-
break;
|
|
812
|
-
}
|
|
813
|
-
case 'boolean': {
|
|
814
|
-
const lowerOutput = rawOutput.toLowerCase().trim();
|
|
815
|
-
if (['true', 'yes', '1'].includes(lowerOutput)) {
|
|
816
|
-
parsedResult = true;
|
|
817
|
-
}
|
|
818
|
-
else if (['false', 'no', '0'].includes(lowerOutput)) {
|
|
819
|
-
parsedResult = false;
|
|
820
|
-
}
|
|
821
|
-
else {
|
|
822
|
-
throw new Error(`Expected boolean output but got: ${rawOutput}`);
|
|
823
|
-
}
|
|
824
|
-
break;
|
|
825
|
-
}
|
|
826
|
-
case 'date': {
|
|
827
|
-
const dateResult = new Date(rawOutput);
|
|
828
|
-
if (isNaN(dateResult.getTime())) {
|
|
829
|
-
throw new Error(`Expected date output but got: ${rawOutput}`);
|
|
830
|
-
}
|
|
831
|
-
parsedResult = dateResult;
|
|
832
|
-
break;
|
|
833
|
-
}
|
|
834
|
-
case 'object':
|
|
835
|
-
try {
|
|
836
|
-
parsedResult = JSON.parse(rawOutput);
|
|
837
|
-
}
|
|
838
|
-
catch (jsonError) {
|
|
839
|
-
throw new Error(`Expected JSON object but got invalid JSON: ${rawOutput}`);
|
|
840
|
-
}
|
|
841
|
-
break;
|
|
842
|
-
default:
|
|
843
|
-
parsedResult = rawOutput;
|
|
844
|
-
}
|
|
845
|
-
const validationResult = new core_1.ValidationResult();
|
|
846
|
-
validationResult.Success = true;
|
|
847
|
-
if (!skipValidation && prompt.OutputExample && prompt.OutputType === 'object') {
|
|
848
|
-
}
|
|
849
|
-
return { result: parsedResult, validationResult };
|
|
850
|
-
}
|
|
851
|
-
catch (error) {
|
|
852
|
-
(0, core_1.LogError)(`Error parsing/validating result: ${error.message}`);
|
|
853
|
-
switch (prompt.ValidationBehavior) {
|
|
854
|
-
case 'Strict':
|
|
855
|
-
throw error;
|
|
856
|
-
case 'Warn':
|
|
857
|
-
(0, core_1.LogError)(`Validation warning for prompt ${prompt.Name}: ${error.message}`);
|
|
858
|
-
return { result: modelResult.data?.choices?.[0]?.message?.content };
|
|
859
|
-
case 'None':
|
|
860
|
-
default:
|
|
861
|
-
return { result: modelResult.data?.choices?.[0]?.message?.content };
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
985
|
async updatePromptRun(promptRun, modelResult, parsedResult, endTime, executionTimeMS, validationAttempts) {
|
|
866
986
|
try {
|
|
867
987
|
promptRun.CompletedAt = endTime;
|
|
@@ -871,6 +991,12 @@ class AIPromptRunner {
|
|
|
871
991
|
promptRun.TokensUsed = modelResult.data.usage.totalTokens;
|
|
872
992
|
promptRun.TokensPrompt = modelResult.data.usage.promptTokens;
|
|
873
993
|
promptRun.TokensCompletion = modelResult.data.usage.completionTokens;
|
|
994
|
+
if (modelResult.data.usage.cost !== undefined) {
|
|
995
|
+
promptRun.Cost = modelResult.data.usage.cost;
|
|
996
|
+
}
|
|
997
|
+
if (modelResult.data.usage.costCurrency !== undefined) {
|
|
998
|
+
promptRun.CostCurrency = modelResult.data.usage.costCurrency;
|
|
999
|
+
}
|
|
874
1000
|
}
|
|
875
1001
|
if (validationAttempts && validationAttempts.length > 0) {
|
|
876
1002
|
try {
|
|
@@ -901,6 +1027,12 @@ class AIPromptRunner {
|
|
|
901
1027
|
}
|
|
902
1028
|
}
|
|
903
1029
|
promptRun.Success = modelResult.success && (parsedResult.validationResult?.Success !== false);
|
|
1030
|
+
promptRun.TokensPromptRollup = promptRun.TokensPrompt;
|
|
1031
|
+
promptRun.TokensCompletionRollup = promptRun.TokensCompletion;
|
|
1032
|
+
promptRun.TokensUsedRollup = promptRun.TokensUsed;
|
|
1033
|
+
if (promptRun.Cost !== undefined) {
|
|
1034
|
+
promptRun.TotalCost = promptRun.Cost;
|
|
1035
|
+
}
|
|
904
1036
|
const saveResult = await promptRun.Save();
|
|
905
1037
|
if (!saveResult) {
|
|
906
1038
|
(0, core_1.LogError)(`Failed to update AIPromptRun with results: ${promptRun.LatestResult?.Message || 'Unknown error'}`);
|