@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.
@@ -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 = 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,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
- class AIPromptParams {
16
- }
17
- exports.AIPromptParams = AIPromptParams;
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
- return {
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
- if (prompt.TemplateID && (!params.conversationMessages || params.templateMessageRole !== 'none')) {
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.data, params.templateData);
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
- return await this.executePromptInParallel(prompt, renderedPromptText, params, startTime);
98
+ result = await this.executePromptInParallel(prompt, renderedPromptText, params, startTime, parentPromptRun);
83
99
  }
84
100
  else {
85
- return await this.executeSinglePrompt(prompt, renderedPromptText, params, startTime);
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
- return {
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
- 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,
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
- 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);
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
- 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,
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
- 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,
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
- (0, core_1.LogError)(`Error creating prompt run record: ${error.message}`);
372
- 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);
373
562
  }
374
563
  }
375
- async renderPromptTemplate(template, data, templateData) {
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 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`);
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'}`);