@promptbook/wizard 0.98.0-5 โ†’ 0.98.0-9

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/umd/index.umd.js CHANGED
@@ -49,7 +49,7 @@
49
49
  * @generated
50
50
  * @see https://github.com/webgptorg/promptbook
51
51
  */
52
- const PROMPTBOOK_ENGINE_VERSION = '0.98.0-5';
52
+ const PROMPTBOOK_ENGINE_VERSION = '0.98.0-9';
53
53
  /**
54
54
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
55
55
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
@@ -243,7 +243,7 @@
243
243
  *
244
244
  * @public exported from `@promptbook/core`
245
245
  */
246
- const DEFAULT_MAX_EXECUTION_ATTEMPTS = 3; // <- TODO: [๐Ÿคนโ€โ™‚๏ธ]
246
+ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [๐Ÿคนโ€โ™‚๏ธ]
247
247
  // <- TODO: [๐Ÿ]
248
248
  /**
249
249
  * Where to store your books
@@ -4356,7 +4356,7 @@
4356
4356
  */
4357
4357
 
4358
4358
  /**
4359
- * Execution Tools for calling OpenAI API or other OpeenAI compatible provider
4359
+ * Execution Tools for calling OpenAI API or other OpenAI compatible provider
4360
4360
  *
4361
4361
  * @public exported from `@promptbook/openai`
4362
4362
  */
@@ -4926,6 +4926,7 @@
4926
4926
  baseURL: DEFAULT_OLLAMA_BASE_URL,
4927
4927
  ...ollamaOptions,
4928
4928
  apiKey: 'ollama',
4929
+ isProxied: false, // <- Note: Ollama is always local
4929
4930
  };
4930
4931
  super(openAiCompatibleOptions);
4931
4932
  }
@@ -5112,7 +5113,7 @@
5112
5113
  title: 'Open AI Compatible',
5113
5114
  packageName: '@promptbook/openai',
5114
5115
  className: 'OpenAiCompatibleExecutionTools',
5115
- envVariables: ['OPENAI_API_KEY'],
5116
+ envVariables: ['OPENAI_API_KEY', 'OPENAI_BASE_URL'],
5116
5117
  trustLevel: 'CLOSED',
5117
5118
  order: MODEL_ORDERS.TOP_TIER,
5118
5119
  getBoilerplateConfiguration() {
@@ -5122,6 +5123,9 @@
5122
5123
  className: 'OpenAiCompatibleExecutionTools',
5123
5124
  options: {
5124
5125
  apiKey: 'sk-',
5126
+ baseURL: 'https://api.openai.com/v1',
5127
+ isProxied: false,
5128
+ remoteServerUrl: DEFAULT_REMOTE_SERVER_URL,
5125
5129
  maxRequestsPerMinute: DEFAULT_MAX_REQUESTS_PER_MINUTE,
5126
5130
  },
5127
5131
  };
@@ -5179,7 +5183,7 @@
5179
5183
  * Default model for chat variant.
5180
5184
  */
5181
5185
  getDefaultChatModel() {
5182
- return this.getDefaultModel('gpt-4o');
5186
+ return this.getDefaultModel('gpt-4-turbo');
5183
5187
  }
5184
5188
  /**
5185
5189
  * Default model for completion variant.
@@ -5209,6 +5213,9 @@
5209
5213
  * @param options which are relevant are directly passed to the OpenAI client
5210
5214
  */
5211
5215
  constructor(options) {
5216
+ if (options.isProxied) {
5217
+ throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI assistants`);
5218
+ }
5212
5219
  super(options);
5213
5220
  this.assistantId = options.assistantId;
5214
5221
  // TODO: [๐Ÿ‘ฑ] Make limiter same as in `OpenAiExecutionTools`
@@ -5390,14 +5397,97 @@
5390
5397
  * @public exported from `@promptbook/openai`
5391
5398
  */
5392
5399
  const createOpenAiCompatibleExecutionTools = Object.assign((options) => {
5400
+ if (options.isProxied) {
5401
+ return new RemoteLlmExecutionTools({
5402
+ ...options,
5403
+ identification: {
5404
+ isAnonymous: true,
5405
+ llmToolsConfiguration: [
5406
+ {
5407
+ title: 'OpenAI Compatible (proxied)',
5408
+ packageName: '@promptbook/openai',
5409
+ className: 'OpenAiCompatibleExecutionTools',
5410
+ options: {
5411
+ ...options,
5412
+ isProxied: false,
5413
+ },
5414
+ },
5415
+ ],
5416
+ },
5417
+ });
5418
+ }
5393
5419
  if (($isRunningInBrowser() || $isRunningInWebWorker()) && !options.dangerouslyAllowBrowser) {
5394
5420
  options = { ...options, dangerouslyAllowBrowser: true };
5395
5421
  }
5396
- return new OpenAiExecutionTools(options);
5422
+ return new HardcodedOpenAiCompatibleExecutionTools(options.defaultModelName, options);
5397
5423
  }, {
5398
5424
  packageName: '@promptbook/openai',
5399
5425
  className: 'OpenAiCompatibleExecutionTools',
5400
5426
  });
5427
+ /**
5428
+ * Execution Tools for calling ONE SPECIFIC PRECONFIGURED OpenAI compatible provider
5429
+ *
5430
+ * @private for `createOpenAiCompatibleExecutionTools`
5431
+ */
5432
+ class HardcodedOpenAiCompatibleExecutionTools extends OpenAiCompatibleExecutionTools {
5433
+ /**
5434
+ * Creates OpenAI compatible Execution Tools.
5435
+ *
5436
+ * @param options which are relevant are directly passed to the OpenAI compatible client
5437
+ */
5438
+ constructor(defaultModelName, options) {
5439
+ super(options);
5440
+ this.defaultModelName = defaultModelName;
5441
+ this.options = options;
5442
+ }
5443
+ get title() {
5444
+ return `${this.defaultModelName} on ${this.options.baseURL}`;
5445
+ }
5446
+ get description() {
5447
+ return `OpenAI compatible connected to "${this.options.baseURL}" model "${this.defaultModelName}"`;
5448
+ }
5449
+ /**
5450
+ * List all available models (non dynamically)
5451
+ *
5452
+ * Note: Purpose of this is to provide more information about models than standard listing from API
5453
+ */
5454
+ get HARDCODED_MODELS() {
5455
+ return [
5456
+ {
5457
+ modelName: this.defaultModelName,
5458
+ modelVariant: 'CHAT',
5459
+ modelDescription: '', // <- TODO: What is the best value here, maybe `this.description`?
5460
+ },
5461
+ ];
5462
+ }
5463
+ /**
5464
+ * Computes the usage
5465
+ */
5466
+ computeUsage(...args) {
5467
+ return {
5468
+ ...computeOpenAiUsage(...args),
5469
+ price: UNCERTAIN_ZERO_VALUE, // <- TODO: Maybe in future pass this counting mechanism, but for now, we dont know
5470
+ };
5471
+ }
5472
+ /**
5473
+ * Default model for chat variant.
5474
+ */
5475
+ getDefaultChatModel() {
5476
+ return this.getDefaultModel(this.defaultModelName);
5477
+ }
5478
+ /**
5479
+ * Default model for completion variant.
5480
+ */
5481
+ getDefaultCompletionModel() {
5482
+ throw new PipelineExecutionError(`${this.title} does not support COMPLETION model variant`);
5483
+ }
5484
+ /**
5485
+ * Default model for completion variant.
5486
+ */
5487
+ getDefaultEmbeddingModel() {
5488
+ throw new PipelineExecutionError(`${this.title} does not support EMBEDDING model variant`);
5489
+ }
5490
+ }
5401
5491
  /**
5402
5492
  * TODO: [๐Ÿฆบ] Is there some way how to put `packageName` and `className` on top and function definition on bottom?
5403
5493
  * TODO: [๐ŸŽถ] Naming "constructor" vs "creator" vs "factory"
@@ -5414,6 +5504,9 @@
5414
5504
  if (($isRunningInBrowser() || $isRunningInWebWorker()) && !options.dangerouslyAllowBrowser) {
5415
5505
  options = { ...options, dangerouslyAllowBrowser: true };
5416
5506
  }
5507
+ if (options.isProxied) {
5508
+ throw new NotYetImplementedError(`Proxy mode is not yet implemented in createOpenAiExecutionTools`);
5509
+ }
5417
5510
  return new OpenAiExecutionTools(options);
5418
5511
  }, {
5419
5512
  packageName: '@promptbook/openai',
@@ -6793,7 +6886,7 @@
6793
6886
  throw new Error(spaceTrim__default["default"]((block) => `
6794
6887
  ${block(error.message)}
6795
6888
 
6796
- The JSON text:
6889
+ The expected JSON text:
6797
6890
  ${block(value)}
6798
6891
  `));
6799
6892
  }
@@ -8702,6 +8795,68 @@
8702
8795
  * Note: [๐Ÿ’] and [๐Ÿค ] are interconnected together
8703
8796
  */
8704
8797
 
8798
+ /**
8799
+ * Validates a prompt result against expectations and format requirements.
8800
+ * This function provides a common abstraction for result validation that can be used
8801
+ * by both execution logic and caching logic to ensure consistency.
8802
+ *
8803
+ * @param options - The validation options including result string, expectations, and format
8804
+ * @returns Validation result with processed string and validity status
8805
+ * @private internal function of `createPipelineExecutor` and `cacheLlmTools`
8806
+ */
8807
+ function validatePromptResult(options) {
8808
+ const { resultString, expectations, format } = options;
8809
+ let processedResultString = resultString;
8810
+ let validationError;
8811
+ try {
8812
+ // TODO: [๐Ÿ’] Unite object for expecting amount and format
8813
+ if (format) {
8814
+ if (format === 'JSON') {
8815
+ if (!isValidJsonString(processedResultString)) {
8816
+ // TODO: [๐Ÿข] Do more universally via `FormatParser`
8817
+ try {
8818
+ processedResultString = extractJsonBlock(processedResultString);
8819
+ }
8820
+ catch (error) {
8821
+ keepUnused(error);
8822
+ throw new ExpectError(spaceTrim.spaceTrim((block) => `
8823
+ Expected valid JSON string
8824
+
8825
+ The expected JSON text:
8826
+ ${block(processedResultString)}
8827
+ `));
8828
+ }
8829
+ }
8830
+ }
8831
+ else {
8832
+ throw new UnexpectedError(`Unknown format "${format}"`);
8833
+ }
8834
+ }
8835
+ // TODO: [๐Ÿ’] Unite object for expecting amount and format
8836
+ if (expectations) {
8837
+ checkExpectations(expectations, processedResultString);
8838
+ }
8839
+ return {
8840
+ isValid: true,
8841
+ processedResultString,
8842
+ };
8843
+ }
8844
+ catch (error) {
8845
+ if (error instanceof ExpectError) {
8846
+ validationError = error;
8847
+ }
8848
+ else {
8849
+ // Re-throw non-ExpectError errors (like UnexpectedError)
8850
+ throw error;
8851
+ }
8852
+ return {
8853
+ isValid: false,
8854
+ processedResultString,
8855
+ error: validationError,
8856
+ };
8857
+ }
8858
+ }
8859
+
8705
8860
  /**
8706
8861
  * Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
8707
8862
  * (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
@@ -8724,13 +8879,13 @@
8724
8879
  // TODO: [๐Ÿš] Make arrayable LLMs -> single LLM DRY
8725
8880
  const _llms = arrayableToArray(tools.llm);
8726
8881
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
8727
- attempts: for (let attempt = -jokerParameterNames.length; attempt < maxAttempts; attempt++) {
8728
- const isJokerAttempt = attempt < 0;
8729
- const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
8882
+ attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
8883
+ const isJokerAttempt = attemptIndex < 0;
8884
+ const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
8730
8885
  // TODO: [๐Ÿง ][๐Ÿญ] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
8731
8886
  if (isJokerAttempt && !jokerParameterName) {
8732
8887
  throw new UnexpectedError(spaceTrim.spaceTrim((block) => `
8733
- Joker not found in attempt ${attempt}
8888
+ Joker not found in attempt ${attemptIndex}
8734
8889
 
8735
8890
  ${block(pipelineIdentification)}
8736
8891
  `));
@@ -8928,35 +9083,18 @@
8928
9083
  }
8929
9084
  }
8930
9085
  // TODO: [๐Ÿ’] Unite object for expecting amount and format
8931
- if (task.format) {
8932
- if (task.format === 'JSON') {
8933
- if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
8934
- // TODO: [๐Ÿข] Do more universally via `FormatParser`
8935
- try {
8936
- $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
8937
- }
8938
- catch (error) {
8939
- keepUnused(error);
8940
- throw new ExpectError(spaceTrim.spaceTrim((block) => `
8941
- Expected valid JSON string
8942
-
8943
- ${block(
8944
- /*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
8945
- `));
8946
- }
8947
- }
8948
- }
8949
- else {
8950
- throw new UnexpectedError(spaceTrim.spaceTrim((block) => `
8951
- Unknown format "${task.format}"
8952
-
8953
- ${block(pipelineIdentification)}
8954
- `));
9086
+ // Use the common validation function for both format and expectations
9087
+ if (task.format || task.expectations) {
9088
+ const validationResult = validatePromptResult({
9089
+ resultString: $ongoingTaskResult.$resultString || '',
9090
+ expectations: task.expectations,
9091
+ format: task.format,
9092
+ });
9093
+ if (!validationResult.isValid) {
9094
+ throw validationResult.error;
8955
9095
  }
8956
- }
8957
- // TODO: [๐Ÿ’] Unite object for expecting amount and format
8958
- if (task.expectations) {
8959
- checkExpectations(task.expectations, $ongoingTaskResult.$resultString || '');
9096
+ // Update the result string in case format processing modified it (e.g., JSON extraction)
9097
+ $ongoingTaskResult.$resultString = validationResult.processedResultString;
8960
9098
  }
8961
9099
  break attempts;
8962
9100
  }
@@ -8970,6 +9108,7 @@
8970
9108
  $ongoingTaskResult.$failedResults = [];
8971
9109
  }
8972
9110
  $ongoingTaskResult.$failedResults.push({
9111
+ attemptIndex,
8973
9112
  result: $ongoingTaskResult.$resultString,
8974
9113
  error: error,
8975
9114
  });
@@ -8994,19 +9133,13 @@
8994
9133
  });
8995
9134
  }
8996
9135
  }
8997
- if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
8998
- // Store the current failure before throwing
8999
- $ongoingTaskResult.$failedResults = $ongoingTaskResult.$failedResults || [];
9000
- $ongoingTaskResult.$failedResults.push({
9001
- result: $ongoingTaskResult.$resultString,
9002
- error: $ongoingTaskResult.$expectError,
9003
- });
9004
- // Create a summary of all failures
9136
+ if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
9137
+ // Note: Create a summary of all failures
9005
9138
  const failuresSummary = $ongoingTaskResult.$failedResults
9006
- .map((failure, index) => spaceTrim.spaceTrim((block) => {
9139
+ .map((failure) => spaceTrim.spaceTrim((block) => {
9007
9140
  var _a, _b;
9008
9141
  return `
9009
- Attempt ${index + 1}:
9142
+ Attempt ${failure.attemptIndex + 1}:
9010
9143
  Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
9011
9144
  ${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
9012
9145
 
@@ -11813,6 +11946,7 @@
11813
11946
  },
11814
11947
  };
11815
11948
  const callCommonModel = async (prompt) => {
11949
+ var _a;
11816
11950
  const { parameters, content, modelRequirements } = prompt;
11817
11951
  // <- Note: These are relevant things from the prompt that the cache key should depend on.
11818
11952
  // TODO: Maybe some standalone function for normalization of content for cache
@@ -11868,11 +12002,42 @@
11868
12002
  // 1. It has a content property that is null or undefined
11869
12003
  // 2. It has an error property that is truthy
11870
12004
  // 3. It has a success property that is explicitly false
11871
- const isFailedResult = promptResult.content === null ||
12005
+ // 4. It doesn't meet the prompt's expectations or format requirements
12006
+ const isBasicFailedResult = promptResult.content === null ||
11872
12007
  promptResult.content === undefined ||
11873
12008
  promptResult.error ||
11874
12009
  promptResult.success === false;
11875
- if (!isFailedResult) {
12010
+ let shouldCache = !isBasicFailedResult;
12011
+ // If the basic result is valid, check against expectations and format
12012
+ if (shouldCache && promptResult.content) {
12013
+ try {
12014
+ const validationResult = validatePromptResult({
12015
+ resultString: promptResult.content,
12016
+ expectations: prompt.expectations,
12017
+ format: prompt.format,
12018
+ });
12019
+ shouldCache = validationResult.isValid;
12020
+ if (!shouldCache && isVerbose) {
12021
+ console.info('Not caching result that fails expectations/format validation for key:', key, {
12022
+ content: promptResult.content,
12023
+ expectations: prompt.expectations,
12024
+ format: prompt.format,
12025
+ validationError: (_a = validationResult.error) === null || _a === void 0 ? void 0 : _a.message,
12026
+ });
12027
+ }
12028
+ }
12029
+ catch (error) {
12030
+ // If validation throws an unexpected error, don't cache
12031
+ shouldCache = false;
12032
+ if (isVerbose) {
12033
+ console.info('Not caching result due to validation error for key:', key, {
12034
+ content: promptResult.content,
12035
+ validationError: error instanceof Error ? error.message : String(error),
12036
+ });
12037
+ }
12038
+ }
12039
+ }
12040
+ if (shouldCache) {
11876
12041
  await storage.setItem(key, {
11877
12042
  date: $getCurrentDate(),
11878
12043
  promptbookVersion: PROMPTBOOK_ENGINE_VERSION,
@@ -11889,7 +12054,7 @@
11889
12054
  promptResult,
11890
12055
  });
11891
12056
  }
11892
- else if (isVerbose) {
12057
+ else if (isVerbose && isBasicFailedResult) {
11893
12058
  console.info('Not caching failed result for key:', key, {
11894
12059
  content: promptResult.content,
11895
12060
  error: promptResult.error,
@@ -11976,6 +12141,7 @@
11976
12141
  .list()
11977
12142
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
11978
12143
  if (registeredItem === undefined) {
12144
+ console.log('!!! $llmToolsRegister.list()', $llmToolsRegister.list());
11979
12145
  throw new Error(spaceTrim__default["default"]((block) => `
11980
12146
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
11981
12147