@memberjunction/ai-prompts 2.48.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.
@@ -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.AIPromptRunResult = exports.AIPromptParams = exports.ChildPromptParam = void 0;
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,19 +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
- class ChildPromptParam {
16
- constructor(childPrompt, parentPlaceholder) {
17
- this.childPrompt = childPrompt;
18
- this.parentPlaceholder = parentPlaceholder;
19
- }
20
- }
21
- exports.ChildPromptParam = ChildPromptParam;
22
- class AIPromptParams {
23
- }
24
- exports.AIPromptParams = AIPromptParams;
25
- class AIPromptRunResult {
26
- }
27
- 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; } });
28
18
  class AIPromptRunner {
29
19
  constructor() {
30
20
  this._metadata = new core_1.Metadata();
@@ -50,7 +40,7 @@ class AIPromptRunner {
50
40
  const startTime = new Date();
51
41
  const promptRun = null;
52
42
  if (params.cancellationToken?.aborted) {
53
- return {
43
+ const result = {
54
44
  success: false,
55
45
  status: 'cancelled',
56
46
  cancelled: true,
@@ -58,7 +48,10 @@ class AIPromptRunner {
58
48
  errorMessage: 'Prompt execution was cancelled before starting',
59
49
  executionTimeMS: 0,
60
50
  chatResult: { success: false, errorMessage: 'Prompt execution was cancelled before starting' },
51
+ tokensUsed: 0,
52
+ combinedTokensUsed: 0
61
53
  };
54
+ return result;
62
55
  }
63
56
  try {
64
57
  const prompt = params.prompt;
@@ -69,11 +62,20 @@ class AIPromptRunner {
69
62
  throw new Error(`Prompt ${prompt.Name} is not active (Status: ${prompt.Status})`);
70
63
  }
71
64
  let renderedPromptText = '';
65
+ let parentPromptRun;
66
+ let selectedModel;
67
+ let childTemplateRenderingResult;
72
68
  if (params.childPrompts && params.childPrompts.length > 0) {
73
- (0, core_1.LogStatus)(`🌳 Executing prompt with ${params.childPrompts.length} child prompts in hierarchical mode`);
74
- const childResults = await this.executeChildPrompts(params.childPrompts, params.cancellationToken);
75
- renderedPromptText = await this.renderPromptWithChildResults(prompt, params, childResults);
76
- (0, core_1.LogStatus)(`✅ Hierarchical prompt execution completed with ${Object.keys(childResults).length} child results embedded`);
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`);
77
79
  }
78
80
  else if (prompt.TemplateID && (!params.conversationMessages || params.templateMessageRole !== 'none')) {
79
81
  await this._templateEngine.Config(false, params.contextUser);
@@ -81,7 +83,7 @@ class AIPromptRunner {
81
83
  if (!template) {
82
84
  throw new Error(`Template with ID ${prompt.TemplateID} not found for prompt ${prompt.Name}`);
83
85
  }
84
- const renderedPrompt = await this.renderPromptTemplate(template, params.data, params.templateData);
86
+ const renderedPrompt = await this.renderPromptTemplate(template, params);
85
87
  if (!renderedPrompt.Success) {
86
88
  throw new Error(`Failed to render template for prompt ${prompt.Name}: ${renderedPrompt.Message}`);
87
89
  }
@@ -91,12 +93,14 @@ class AIPromptRunner {
91
93
  throw new Error('Prompt execution was cancelled during template rendering');
92
94
  }
93
95
  const shouldUseParallelExecution = prompt.ParallelizationMode && prompt.ParallelizationMode !== 'None';
96
+ let result;
94
97
  if (shouldUseParallelExecution) {
95
- return await this.executePromptInParallel(prompt, renderedPromptText, params, startTime);
98
+ result = await this.executePromptInParallel(prompt, renderedPromptText, params, startTime, parentPromptRun);
96
99
  }
97
100
  else {
98
- return await this.executeSinglePrompt(prompt, renderedPromptText, params, startTime);
101
+ result = await this.executeSinglePrompt(prompt, renderedPromptText, params, startTime, parentPromptRun, selectedModel);
99
102
  }
103
+ return result;
100
104
  }
101
105
  catch (error) {
102
106
  (0, core_1.LogError)(error);
@@ -111,27 +115,30 @@ class AIPromptRunner {
111
115
  (0, core_1.LogError)(`Failed to save error to AIPromptRun: ${promptRun.LatestResult?.Message || 'Unknown error'}`);
112
116
  }
113
117
  }
114
- return {
118
+ const errorResult = {
115
119
  success: false,
116
120
  errorMessage: error.message,
117
121
  promptRun,
118
122
  executionTimeMS,
119
123
  chatResult: { success: false, errorMessage: error.message },
124
+ tokensUsed: 0,
125
+ combinedTokensUsed: 0
120
126
  };
127
+ return errorResult;
121
128
  }
122
129
  }
123
- async executeSinglePrompt(prompt, renderedPromptText, params, startTime) {
130
+ async executeSinglePrompt(prompt, renderedPromptText, params, startTime, existingPromptRun, existingModel) {
124
131
  if (params.cancellationToken?.aborted) {
125
132
  throw new Error('Prompt execution was cancelled before model selection');
126
133
  }
127
- 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);
128
135
  if (!selectedModel) {
129
136
  throw new Error(`No suitable model found for prompt ${prompt.Name}`);
130
137
  }
131
138
  if (params.cancellationToken?.aborted) {
132
139
  throw new Error('Prompt execution was cancelled after model selection');
133
140
  }
134
- const promptRun = await this.createPromptRun(prompt, selectedModel, params, startTime, params.vendorId);
141
+ const promptRun = existingPromptRun || await this.createPromptRun(prompt, selectedModel, params, startTime, params.vendorId);
135
142
  if (params.cancellationToken?.aborted) {
136
143
  throw new Error('Prompt execution was cancelled before model execution');
137
144
  }
@@ -140,6 +147,7 @@ class AIPromptRunner {
140
147
  const executionTimeMS = endTime.getTime() - startTime.getTime();
141
148
  await this.updatePromptRun(promptRun, modelResult, parsedResult, endTime, executionTimeMS, validationAttempts);
142
149
  const chatResult = modelResult;
150
+ const usage = chatResult.data?.usage;
143
151
  return {
144
152
  success: true,
145
153
  rawResult: chatResult.data?.choices?.[0]?.message?.content,
@@ -147,12 +155,17 @@ class AIPromptRunner {
147
155
  chatResult,
148
156
  promptRun,
149
157
  executionTimeMS,
150
- tokensUsed: chatResult.data?.usage?.totalTokens,
158
+ promptTokens: usage?.promptTokens,
159
+ completionTokens: usage?.completionTokens,
160
+ tokensUsed: (usage?.promptTokens || 0) + (usage?.completionTokens || 0),
161
+ cost: usage?.cost,
162
+ costCurrency: usage?.costCurrency,
151
163
  validationResult: parsedResult.validationResult,
152
164
  validationAttempts,
165
+ combinedTokensUsed: (usage?.promptTokens || 0) + (usage?.completionTokens || 0)
153
166
  };
154
167
  }
155
- async executePromptInParallel(prompt, renderedPromptText, params, startTime) {
168
+ async executePromptInParallel(prompt, renderedPromptText, params, startTime, existingPromptRun) {
156
169
  if (params.cancellationToken?.aborted) {
157
170
  throw new Error('Parallel execution was cancelled before starting');
158
171
  }
@@ -186,12 +199,38 @@ class AIPromptRunner {
186
199
  selectedResult = aiSelectedResult;
187
200
  }
188
201
  }
189
- const consolidatedPromptRun = await this.createPromptRun(prompt, selectedResult.task.model, params, startTime, params.vendorId);
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);
190
218
  const endTime = new Date();
191
219
  consolidatedPromptRun.CompletedAt = endTime;
192
220
  consolidatedPromptRun.ExecutionTimeMS = parallelResult.totalExecutionTimeMS;
193
221
  consolidatedPromptRun.Result = selectedResult.rawResult || '';
194
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
+ }
195
234
  const parallelMetadata = {
196
235
  parallelizationMode: prompt.ParallelizationMode,
197
236
  totalTasks: executionTasks.length,
@@ -207,6 +246,12 @@ class AIPromptRunner {
207
246
  parallelExecution: parallelMetadata,
208
247
  });
209
248
  }
249
+ consolidatedPromptRun.TokensPromptRollup = totalPromptTokens;
250
+ consolidatedPromptRun.TokensCompletionRollup = totalCompletionTokens;
251
+ consolidatedPromptRun.TokensUsedRollup = totalPromptTokens + totalCompletionTokens;
252
+ if (hasCost) {
253
+ consolidatedPromptRun.TotalCost = totalCost;
254
+ }
210
255
  const saveResult = await consolidatedPromptRun.Save();
211
256
  if (!saveResult) {
212
257
  (0, core_1.LogError)(`Failed to save consolidated AIPromptRun: ${consolidatedPromptRun.LatestResult?.Message || 'Unknown error'}`);
@@ -222,13 +267,18 @@ class AIPromptRunner {
222
267
  if (result.task.taskId !== selectedResult.task.taskId) {
223
268
  const { result: parsedResultData, validationResult, validationErrors } = await this.parseAndValidateResultEnhanced(result.modelResult, prompt, params.skipValidation);
224
269
  const parsedResult = { result: parsedResultData, validationResult };
270
+ const resultUsage = result.modelResult?.data?.usage;
225
271
  additionalResults.push({
226
272
  success: result.success,
227
273
  rawResult: result.rawResult,
228
274
  result: parsedResult.result,
229
275
  chatResult: result.modelResult,
230
276
  executionTimeMS: result.executionTimeMS,
231
- tokensUsed: result.tokensUsed,
277
+ promptTokens: resultUsage?.promptTokens,
278
+ completionTokens: resultUsage?.completionTokens,
279
+ tokensUsed: (resultUsage?.promptTokens || 0) + (resultUsage?.completionTokens || 0),
280
+ cost: resultUsage?.cost,
281
+ costCurrency: resultUsage?.costCurrency,
232
282
  validationResult: parsedResult.validationResult,
233
283
  ranking: result.ranking,
234
284
  judgeRationale: result.judgeRationale,
@@ -238,11 +288,13 @@ class AIPromptRunner {
238
288
  vendorId: undefined,
239
289
  vendorName: result.task.model.Vendor,
240
290
  },
291
+ combinedTokensUsed: (resultUsage?.promptTokens || 0) + (resultUsage?.completionTokens || 0)
241
292
  });
242
293
  }
243
294
  }
244
295
  const { result: selectedResultData, validationResult: selectedValidationResult } = await this.parseAndValidateResultEnhanced(selectedResult.modelResult, prompt, params.skipValidation);
245
296
  const selectedParsedResult = { result: selectedResultData, validationResult: selectedValidationResult };
297
+ const selectedUsage = selectedResult.modelResult?.data?.usage;
246
298
  return {
247
299
  success: true,
248
300
  rawResult: selectedResult.rawResult,
@@ -250,7 +302,15 @@ class AIPromptRunner {
250
302
  chatResult: selectedResult.modelResult,
251
303
  promptRun: consolidatedPromptRun,
252
304
  executionTimeMS: parallelResult.totalExecutionTimeMS,
253
- tokensUsed: parallelResult.totalTokensUsed,
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,
254
314
  validationResult: selectedParsedResult.validationResult,
255
315
  additionalResults: additionalResults.length > 0 ? additionalResults : undefined,
256
316
  ranking: selectedResult.ranking || 1,
@@ -274,61 +334,83 @@ class AIPromptRunner {
274
334
  return null;
275
335
  }
276
336
  }
277
- async executeChildPrompts(childPrompts, cancellationToken) {
337
+ async renderChildPromptTemplates(childPrompts, params, cancellationToken) {
278
338
  if (!childPrompts || childPrompts.length === 0) {
279
- return {};
339
+ return {
340
+ renderedTemplates: {}
341
+ };
280
342
  }
281
343
  if (cancellationToken?.aborted) {
282
344
  throw new Error('Child prompt execution was cancelled');
283
345
  }
284
- (0, core_1.LogStatus)(`🔄 Executing ${childPrompts.length} child prompts in parallel`);
285
- const childExecutionPromises = childPrompts.map(async (childParam) => {
346
+ (0, core_1.LogStatus)(`🔄 Rendering ${childPrompts.length} child prompt templates in parallel`);
347
+ const childRenderingPromises = childPrompts.map(async (childParam) => {
286
348
  try {
287
349
  if (cancellationToken?.aborted) {
288
- throw new Error('Child prompt execution was cancelled');
350
+ throw new Error('Child prompt template rendering was cancelled');
289
351
  }
290
352
  let childData = { ...childParam.childPrompt.data };
291
353
  if (childParam.childPrompt.childPrompts && childParam.childPrompt.childPrompts.length > 0) {
292
- const grandchildResults = await this.executeChildPrompts(childParam.childPrompt.childPrompts, cancellationToken);
293
- childData = { ...childData, ...grandchildResults };
294
- }
295
- const childExecutionParams = new AIPromptParams();
296
- Object.assign(childExecutionParams, childParam.childPrompt);
297
- childExecutionParams.data = childData;
298
- childExecutionParams.cancellationToken = cancellationToken;
299
- (0, core_1.LogStatus)(` 🔹 Executing child prompt: ${childParam.childPrompt.prompt.Name} -> ${childParam.parentPlaceholder}`);
300
- const childResult = await this.ExecutePrompt(childExecutionParams);
301
- if (!childResult.success) {
302
- throw new Error(`Child prompt execution failed: ${childResult.errorMessage}`);
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 = '';
303
383
  }
304
384
  return {
305
385
  placeholder: childParam.parentPlaceholder,
306
- result: childResult.rawResult || JSON.stringify(childResult.result),
386
+ renderedTemplate: renderedChildTemplate,
307
387
  success: true
308
388
  };
309
389
  }
310
390
  catch (error) {
311
- (0, core_1.LogError)(`Error executing child prompt for placeholder ${childParam.parentPlaceholder}: ${error.message}`);
391
+ (0, core_1.LogError)(`Error rendering child prompt template for placeholder ${childParam.parentPlaceholder}: ${error.message}`);
312
392
  return {
313
393
  placeholder: childParam.parentPlaceholder,
314
- result: `ERROR: ${error.message}`,
394
+ renderedTemplate: `ERROR: ${error.message}`,
315
395
  success: false
316
396
  };
317
397
  }
318
398
  });
319
- const childResults = await Promise.all(childExecutionPromises);
399
+ const childResults = await Promise.all(childRenderingPromises);
320
400
  const failedChildren = childResults.filter(r => !r.success);
321
401
  if (failedChildren.length > 0) {
322
- (0, core_1.LogError)(`${failedChildren.length} out of ${childResults.length} child prompts failed`);
402
+ (0, core_1.LogError)(`${failedChildren.length} out of ${childResults.length} child prompt templates failed to render`);
323
403
  }
324
- const resultMap = {};
404
+ const renderedTemplatesMap = {};
325
405
  for (const childResult of childResults) {
326
- resultMap[childResult.placeholder] = childResult.result;
406
+ renderedTemplatesMap[childResult.placeholder] = childResult.renderedTemplate;
327
407
  }
328
- (0, core_1.LogStatus)(`✅ Completed execution of ${childResults.length} child prompts`);
329
- return resultMap;
408
+ (0, core_1.LogStatus)(`✅ Completed rendering of ${childResults.length} child prompt templates`);
409
+ return {
410
+ renderedTemplates: renderedTemplatesMap
411
+ };
330
412
  }
331
- async renderPromptWithChildResults(prompt, params, childResults) {
413
+ async renderPromptWithChildTemplates(prompt, params, childTemplates) {
332
414
  if (!prompt.TemplateID) {
333
415
  return '';
334
416
  }
@@ -338,24 +420,26 @@ class AIPromptRunner {
338
420
  if (!template) {
339
421
  throw new Error(`Template with ID ${prompt.TemplateID} not found for prompt ${prompt.Name}`);
340
422
  }
423
+ const systemPlaceholders = await SystemPlaceholders_1.SystemPlaceholderManager.resolveAllPlaceholders(params);
341
424
  const mergedData = {
425
+ ...systemPlaceholders,
342
426
  ...params.data,
343
- ...childResults,
427
+ ...childTemplates,
344
428
  ...params.templateData
345
429
  };
346
- (0, core_1.LogStatus)(`🔧 Rendering prompt template with ${Object.keys(childResults).length} child results embedded`);
347
- for (const [placeholder, result] of Object.entries(childResults)) {
348
- const truncatedResult = result.length > 100 ? result.substring(0, 100) + '...' : result;
349
- (0, core_1.LogStatus)(` 📝 ${placeholder} -> ${truncatedResult}`);
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}`);
350
434
  }
351
- const renderedPrompt = await this.renderPromptTemplate(template, mergedData);
435
+ const renderedPrompt = await this._templateEngine.RenderTemplate(template, template.GetHighestPriorityContent(), mergedData);
352
436
  if (!renderedPrompt.Success) {
353
437
  throw new Error(`Failed to render template for prompt ${prompt.Name}: ${renderedPrompt.Message}`);
354
438
  }
355
439
  return renderedPrompt.Output;
356
440
  }
357
441
  catch (error) {
358
- (0, core_1.LogError)(`Error rendering prompt with child results: ${error.message}`);
442
+ (0, core_1.LogError)(`Error rendering prompt with child templates: ${error.message}`);
359
443
  throw error;
360
444
  }
361
445
  }
@@ -434,8 +518,8 @@ class AIPromptRunner {
434
518
  }
435
519
  }
436
520
  async createPromptRun(prompt, model, params, startTime, vendorId) {
521
+ const promptRun = await this._metadata.GetEntityObject('MJ: AI Prompt Runs', params.contextUser);
437
522
  try {
438
- const promptRun = await this._metadata.GetEntityObject('MJ: AI Prompt Runs', params.contextUser);
439
523
  promptRun.NewRecord();
440
524
  promptRun.PromptID = prompt.ID;
441
525
  promptRun.ModelID = model.ID;
@@ -454,6 +538,9 @@ class AIPromptRunner {
454
538
  if (params.agentRunId) {
455
539
  promptRun.AgentRunID = params.agentRunId;
456
540
  }
541
+ if (params.parentPromptRunId) {
542
+ promptRun.ParentID = params.parentPromptRunId;
543
+ }
457
544
  if (params.data || params.templateData) {
458
545
  promptRun.Messages = JSON.stringify({
459
546
  data: params.data,
@@ -469,17 +556,24 @@ class AIPromptRunner {
469
556
  return promptRun;
470
557
  }
471
558
  catch (error) {
472
- (0, core_1.LogError)(`Error creating prompt run record: ${error.message}`);
473
- throw error;
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);
474
562
  }
475
563
  }
476
- async renderPromptTemplate(template, data, templateData) {
564
+ async renderPromptTemplate(template, params) {
477
565
  try {
478
566
  const templateContent = template.GetHighestPriorityContent();
479
567
  if (!templateContent) {
480
568
  throw new Error(`No content found for template ${template.Name}`);
481
569
  }
482
- const mergedData = { ...data, ...templateData };
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`);
483
577
  return await this._templateEngine.RenderTemplate(template, templateContent, mergedData);
484
578
  }
485
579
  catch (error) {
@@ -888,80 +982,6 @@ class AIPromptRunner {
888
982
  }
889
983
  return validationErrors;
890
984
  }
891
- async parseAndValidateResult(modelResult, prompt, skipValidation = false) {
892
- try {
893
- if (!modelResult.success) {
894
- throw new Error(`Model execution failed: ${modelResult.errorMessage}`);
895
- }
896
- const rawOutput = modelResult.data?.choices?.[0]?.message?.content;
897
- if (!rawOutput) {
898
- throw new Error('No output received from model');
899
- }
900
- let parsedResult = rawOutput;
901
- switch (prompt.OutputType) {
902
- case 'string':
903
- parsedResult = rawOutput.toString();
904
- break;
905
- case 'number': {
906
- const numberResult = parseFloat(rawOutput);
907
- if (isNaN(numberResult)) {
908
- throw new Error(`Expected number output but got: ${rawOutput}`);
909
- }
910
- parsedResult = numberResult;
911
- break;
912
- }
913
- case 'boolean': {
914
- const lowerOutput = rawOutput.toLowerCase().trim();
915
- if (['true', 'yes', '1'].includes(lowerOutput)) {
916
- parsedResult = true;
917
- }
918
- else if (['false', 'no', '0'].includes(lowerOutput)) {
919
- parsedResult = false;
920
- }
921
- else {
922
- throw new Error(`Expected boolean output but got: ${rawOutput}`);
923
- }
924
- break;
925
- }
926
- case 'date': {
927
- const dateResult = new Date(rawOutput);
928
- if (isNaN(dateResult.getTime())) {
929
- throw new Error(`Expected date output but got: ${rawOutput}`);
930
- }
931
- parsedResult = dateResult;
932
- break;
933
- }
934
- case 'object':
935
- try {
936
- parsedResult = JSON.parse(rawOutput);
937
- }
938
- catch (jsonError) {
939
- throw new Error(`Expected JSON object but got invalid JSON: ${rawOutput}`);
940
- }
941
- break;
942
- default:
943
- parsedResult = rawOutput;
944
- }
945
- const validationResult = new core_1.ValidationResult();
946
- validationResult.Success = true;
947
- if (!skipValidation && prompt.OutputExample && prompt.OutputType === 'object') {
948
- }
949
- return { result: parsedResult, validationResult };
950
- }
951
- catch (error) {
952
- (0, core_1.LogError)(`Error parsing/validating result: ${error.message}`);
953
- switch (prompt.ValidationBehavior) {
954
- case 'Strict':
955
- throw error;
956
- case 'Warn':
957
- (0, core_1.LogError)(`Validation warning for prompt ${prompt.Name}: ${error.message}`);
958
- return { result: modelResult.data?.choices?.[0]?.message?.content };
959
- case 'None':
960
- default:
961
- return { result: modelResult.data?.choices?.[0]?.message?.content };
962
- }
963
- }
964
- }
965
985
  async updatePromptRun(promptRun, modelResult, parsedResult, endTime, executionTimeMS, validationAttempts) {
966
986
  try {
967
987
  promptRun.CompletedAt = endTime;
@@ -971,6 +991,12 @@ class AIPromptRunner {
971
991
  promptRun.TokensUsed = modelResult.data.usage.totalTokens;
972
992
  promptRun.TokensPrompt = modelResult.data.usage.promptTokens;
973
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
+ }
974
1000
  }
975
1001
  if (validationAttempts && validationAttempts.length > 0) {
976
1002
  try {
@@ -1001,6 +1027,12 @@ class AIPromptRunner {
1001
1027
  }
1002
1028
  }
1003
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
+ }
1004
1036
  const saveResult = await promptRun.Save();
1005
1037
  if (!saveResult) {
1006
1038
  (0, core_1.LogError)(`Failed to update AIPromptRun with results: ${promptRun.LatestResult?.Message || 'Unknown error'}`);