@promptbook/legacy-documents 0.92.0-5 → 0.92.0-6

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
@@ -26,7 +26,7 @@
26
26
  * @generated
27
27
  * @see https://github.com/webgptorg/promptbook
28
28
  */
29
- const PROMPTBOOK_ENGINE_VERSION = '0.92.0-5';
29
+ const PROMPTBOOK_ENGINE_VERSION = '0.92.0-6';
30
30
  /**
31
31
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
32
32
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -2296,6 +2296,45 @@
2296
2296
  * - [♨] Are tasks prepared
2297
2297
  */
2298
2298
 
2299
+ /**
2300
+ * Converts a JavaScript Object Notation (JSON) string into an object.
2301
+ *
2302
+ * Note: This is wrapper around `JSON.parse()` with better error and type handling
2303
+ *
2304
+ * @public exported from `@promptbook/utils`
2305
+ */
2306
+ function jsonParse(value) {
2307
+ if (value === undefined) {
2308
+ throw new Error(`Can not parse JSON from undefined value.`);
2309
+ }
2310
+ else if (typeof value !== 'string') {
2311
+ console.error('Can not parse JSON from non-string value.', { text: value });
2312
+ throw new Error(spaceTrim__default["default"](`
2313
+ Can not parse JSON from non-string value.
2314
+
2315
+ The value type: ${typeof value}
2316
+ See more in console.
2317
+ `));
2318
+ }
2319
+ try {
2320
+ return JSON.parse(value);
2321
+ }
2322
+ catch (error) {
2323
+ if (!(error instanceof Error)) {
2324
+ throw error;
2325
+ }
2326
+ throw new Error(spaceTrim__default["default"]((block) => `
2327
+ ${block(error.message)}
2328
+
2329
+ The JSON text:
2330
+ ${block(value)}
2331
+ `));
2332
+ }
2333
+ }
2334
+ /**
2335
+ * TODO: !!!! Use in Promptbook.studio
2336
+ */
2337
+
2299
2338
  /**
2300
2339
  * Recursively converts JSON strings to JSON objects
2301
2340
 
@@ -2314,7 +2353,7 @@
2314
2353
  const newObject = { ...object };
2315
2354
  for (const [key, value] of Object.entries(object)) {
2316
2355
  if (typeof value === 'string' && isValidJsonString(value)) {
2317
- newObject[key] = JSON.parse(value);
2356
+ newObject[key] = jsonParse(value);
2318
2357
  }
2319
2358
  else {
2320
2359
  newObject[key] = jsonStringsToJsons(value);
@@ -3161,7 +3200,7 @@
3161
3200
  }).asPromise();
3162
3201
  const { outputParameters } = result;
3163
3202
  const { modelsRequirements: modelsRequirementsJson } = outputParameters;
3164
- const modelsRequirementsUnchecked = JSON.parse(modelsRequirementsJson);
3203
+ const modelsRequirementsUnchecked = jsonParse(modelsRequirementsJson);
3165
3204
  if (isVerbose) {
3166
3205
  console.info(`PERSONA ${personaDescription}`, modelsRequirementsUnchecked);
3167
3206
  }
@@ -3607,7 +3646,7 @@
3607
3646
  > },
3608
3647
  */
3609
3648
  async asJson() {
3610
- return JSON.parse(await tools.fs.readFile(filename, 'utf-8'));
3649
+ return jsonParse(await tools.fs.readFile(filename, 'utf-8'));
3611
3650
  },
3612
3651
  async asText() {
3613
3652
  return await tools.fs.readFile(filename, 'utf-8');
@@ -5294,13 +5333,79 @@
5294
5333
  /**
5295
5334
  * @@@
5296
5335
  *
5336
+ * Here is the place where RAG (retrieval-augmented generation) happens
5337
+ *
5297
5338
  * @private internal utility of `createPipelineExecutor`
5298
5339
  */
5299
5340
  async function getKnowledgeForTask(options) {
5300
- const { preparedPipeline, task } = options;
5301
- return preparedPipeline.knowledgePieces.map(({ content }) => `- ${content}`).join('\n');
5341
+ const { tools, preparedPipeline, task } = options;
5342
+ const firstKnowlegePiece = preparedPipeline.knowledgePieces[0];
5343
+ const firstKnowlegeIndex = firstKnowlegePiece === null || firstKnowlegePiece === void 0 ? void 0 : firstKnowlegePiece.index[0];
5344
+ // <- TODO: Do not use just first knowledge piece and first index to determine embedding model, use also keyword search
5345
+ if (firstKnowlegePiece === undefined || firstKnowlegeIndex === undefined) {
5346
+ return 'No knowledge pieces found';
5347
+ }
5348
+ // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
5349
+ const _llms = arrayableToArray(tools.llm);
5350
+ const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
5351
+ const taskEmbeddingPrompt = {
5352
+ title: 'Knowledge Search',
5353
+ modelRequirements: {
5354
+ modelVariant: 'EMBEDDING',
5355
+ modelName: firstKnowlegeIndex.modelName,
5356
+ },
5357
+ content: task.content,
5358
+ parameters: {
5359
+ /* !!!!!!!! */
5360
+ },
5361
+ };
5362
+ const taskEmbeddingResult = await llmTools.callEmbeddingModel(taskEmbeddingPrompt);
5363
+ const knowledgePiecesWithRelevance = preparedPipeline.knowledgePieces.map((knowledgePiece) => {
5364
+ const { index } = knowledgePiece;
5365
+ const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowlegeIndex.modelName);
5366
+ // <- TODO: Do not use just first knowledge piece and first index to determine embedding model
5367
+ if (knowledgePieceIndex === undefined) {
5368
+ return {
5369
+ content: knowledgePiece.content,
5370
+ relevance: 0,
5371
+ };
5372
+ }
5373
+ const relevance = computeCosineSimilarity(knowledgePieceIndex.position, taskEmbeddingResult.content);
5374
+ return {
5375
+ content: knowledgePiece.content,
5376
+ relevance,
5377
+ };
5378
+ });
5379
+ const knowledgePiecesSorted = knowledgePiecesWithRelevance.sort((a, b) => a.relevance - b.relevance);
5380
+ const knowledgePiecesLimited = knowledgePiecesSorted.slice(0, 5);
5381
+ console.log('!!! Embedding', {
5382
+ task,
5383
+ taskEmbeddingPrompt,
5384
+ taskEmbeddingResult,
5385
+ firstKnowlegePiece,
5386
+ firstKnowlegeIndex,
5387
+ knowledgePiecesWithRelevance,
5388
+ knowledgePiecesSorted,
5389
+ knowledgePiecesLimited,
5390
+ });
5391
+ return knowledgePiecesLimited.map(({ content }) => `- ${content}`).join('\n');
5302
5392
  // <- TODO: [🧠] Some smart aggregation of knowledge pieces, single-line vs multi-line vs mixed
5303
5393
  }
5394
+ // TODO: !!!!!! Annotate + to new file
5395
+ function computeCosineSimilarity(embeddingVector1, embeddingVector2) {
5396
+ if (embeddingVector1.length !== embeddingVector2.length) {
5397
+ throw new TypeError('Embedding vectors must have the same length');
5398
+ }
5399
+ const dotProduct = embeddingVector1.reduce((sum, value, index) => sum + value * embeddingVector2[index], 0);
5400
+ const magnitude1 = Math.sqrt(embeddingVector1.reduce((sum, value) => sum + value * value, 0));
5401
+ const magnitude2 = Math.sqrt(embeddingVector2.reduce((sum, value) => sum + value * value, 0));
5402
+ return 1 - dotProduct / (magnitude1 * magnitude2);
5403
+ }
5404
+ /**
5405
+ * TODO: !!!! Verify if this is working
5406
+ * TODO: [♨] Implement Better - use keyword search
5407
+ * TODO: [♨] Examples of values
5408
+ */
5304
5409
 
5305
5410
  /**
5306
5411
  * @@@
@@ -5308,9 +5413,9 @@
5308
5413
  * @private internal utility of `createPipelineExecutor`
5309
5414
  */
5310
5415
  async function getReservedParametersForTask(options) {
5311
- const { preparedPipeline, task, pipelineIdentification } = options;
5416
+ const { tools, preparedPipeline, task, pipelineIdentification } = options;
5312
5417
  const context = await getContextForTask(); // <- [🏍]
5313
- const knowledge = await getKnowledgeForTask({ preparedPipeline, task });
5418
+ const knowledge = await getKnowledgeForTask({ tools, preparedPipeline, task });
5314
5419
  const examples = await getExamplesForTask();
5315
5420
  const currentDate = new Date().toISOString(); // <- TODO: [🧠][💩] Better
5316
5421
  const modelName = RESERVED_PARAMETER_MISSING_VALUE;
@@ -5372,6 +5477,7 @@
5372
5477
  }
5373
5478
  const definedParameters = Object.freeze({
5374
5479
  ...(await getReservedParametersForTask({
5480
+ tools,
5375
5481
  preparedPipeline,
5376
5482
  task: currentTask,
5377
5483
  pipelineIdentification,