@promptbook/remote-server 0.95.0 โ 0.98.0-10
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 +12 -0
- package/esm/index.es.js +303 -181
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/anthropic-claude.index.d.ts +2 -2
- package/esm/typings/src/_packages/cli.index.d.ts +4 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/openai.index.d.ts +10 -0
- package/esm/typings/src/_packages/types.index.d.ts +12 -2
- package/esm/typings/src/_packages/wizard.index.d.ts +4 -0
- package/esm/typings/src/config.d.ts +1 -1
- package/esm/typings/src/execution/createPipelineExecutor/$OngoingTaskResult.d.ts +8 -0
- package/esm/typings/src/execution/utils/validatePromptResult.d.ts +53 -0
- package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +3 -3
- package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionToolsOptions.d.ts +2 -2
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionToolsOptions.d.ts +2 -2
- package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +4 -4
- package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionToolsOptions.d.ts +52 -0
- package/esm/typings/src/llm-providers/openai/OpenAiExecutionToolsOptions.d.ts +3 -5
- package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +74 -0
- package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +11 -0
- package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +14 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/umd/index.umd.js +303 -181
- package/umd/index.umd.js.map +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,10 @@ Write AI applications using plain human language across multiple models and plat
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
<blockquote style="color: #ff8811">
|
|
29
|
+
<b>โ Warning:</b> This is a pre-release version of the library. It is not yet ready for production use. Please look at <a href="https://www.npmjs.com/package/@promptbook/core?activeTab=versions">latest stable release</a>.
|
|
30
|
+
</blockquote>
|
|
31
|
+
|
|
28
32
|
## ๐ฆ Package `@promptbook/remote-server`
|
|
29
33
|
|
|
30
34
|
- Promptbooks are [divided into several](#-packages) packages, all are published from [single monorepo](https://github.com/webgptorg/promptbook).
|
|
@@ -56,6 +60,8 @@ Rest of the documentation is common for **entire promptbook ecosystem**:
|
|
|
56
60
|
|
|
57
61
|
During the computer revolution, we have seen [multiple generations of computer languages](https://github.com/webgptorg/promptbook/discussions/180), from the physical rewiring of the vacuum tubes through low-level machine code to the high-level languages like Python or JavaScript. And now, we're on the edge of the **next revolution**!
|
|
58
62
|
|
|
63
|
+
|
|
64
|
+
|
|
59
65
|
It's a revolution of writing software in **plain human language** that is understandable and executable by both humans and machines โ and it's going to change everything!
|
|
60
66
|
|
|
61
67
|
The incredible growth in power of microprocessors and the Moore's Law have been the driving force behind the ever-more powerful languages, and it's been an amazing journey! Similarly, the large language models (like GPT or Claude) are the next big thing in language technology, and they're set to transform the way we interact with computers.
|
|
@@ -181,6 +187,8 @@ Join our growing community of developers and users:
|
|
|
181
187
|
|
|
182
188
|
_A concise, Markdown-based DSL for crafting AI workflows and automations._
|
|
183
189
|
|
|
190
|
+
|
|
191
|
+
|
|
184
192
|
### Introduction
|
|
185
193
|
|
|
186
194
|
Book is a Markdown-based language that simplifies the creation of AI applications, workflows, and automations. With human-readable commands, you can define inputs, outputs, personas, knowledge sources, and actionsโwithout needing model-specific details.
|
|
@@ -230,6 +238,8 @@ Personas can have access to different knowledge, tools and actions. They can als
|
|
|
230
238
|
|
|
231
239
|
- [PERSONA](https://github.com/webgptorg/promptbook/blob/main/documents/commands/PERSONA.md)
|
|
232
240
|
|
|
241
|
+
|
|
242
|
+
|
|
233
243
|
### **3. How:** Knowledge, Instruments and Actions
|
|
234
244
|
|
|
235
245
|
The resources used by the personas are used to do the work.
|
|
@@ -329,6 +339,8 @@ The following glossary is used to clarify certain concepts:
|
|
|
329
339
|
|
|
330
340
|
_Note: This section is not a complete dictionary, more list of general AI / LLM terms that has connection with Promptbook_
|
|
331
341
|
|
|
342
|
+
|
|
343
|
+
|
|
332
344
|
### ๐ฏ Core concepts
|
|
333
345
|
|
|
334
346
|
- [๐ Collection of pipelines](https://github.com/webgptorg/promptbook/discussions/65)
|
package/esm/index.es.js
CHANGED
|
@@ -33,7 +33,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
|
|
|
33
33
|
* @generated
|
|
34
34
|
* @see https://github.com/webgptorg/promptbook
|
|
35
35
|
*/
|
|
36
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.
|
|
36
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.98.0-10';
|
|
37
37
|
/**
|
|
38
38
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
39
39
|
* Note: [๐] Ignore a discrepancy between file name and entity name
|
|
@@ -173,7 +173,7 @@ const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [๐คนโโ๏ธ]
|
|
|
173
173
|
*
|
|
174
174
|
* @public exported from `@promptbook/core`
|
|
175
175
|
*/
|
|
176
|
-
const DEFAULT_MAX_EXECUTION_ATTEMPTS =
|
|
176
|
+
const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [๐คนโโ๏ธ]
|
|
177
177
|
// <- TODO: [๐] Make also `BOOKS_DIRNAME_ALTERNATIVES`
|
|
178
178
|
// TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
|
|
179
179
|
/**
|
|
@@ -1891,7 +1891,7 @@ function jsonParse(value) {
|
|
|
1891
1891
|
throw new Error(spaceTrim((block) => `
|
|
1892
1892
|
${block(error.message)}
|
|
1893
1893
|
|
|
1894
|
-
The JSON text:
|
|
1894
|
+
The expected JSON text:
|
|
1895
1895
|
${block(value)}
|
|
1896
1896
|
`));
|
|
1897
1897
|
}
|
|
@@ -4813,6 +4813,94 @@ function mapAvailableToExpectedParameters(options) {
|
|
|
4813
4813
|
return mappedParameters;
|
|
4814
4814
|
}
|
|
4815
4815
|
|
|
4816
|
+
/**
|
|
4817
|
+
* Just says that the variable is not used but should be kept
|
|
4818
|
+
* No side effects.
|
|
4819
|
+
*
|
|
4820
|
+
* Note: It can be useful for:
|
|
4821
|
+
*
|
|
4822
|
+
* 1) Suppressing eager optimization of unused imports
|
|
4823
|
+
* 2) Suppressing eslint errors of unused variables in the tests
|
|
4824
|
+
* 3) Keeping the type of the variable for type testing
|
|
4825
|
+
*
|
|
4826
|
+
* @param value any values
|
|
4827
|
+
* @returns void
|
|
4828
|
+
* @private within the repository
|
|
4829
|
+
*/
|
|
4830
|
+
function keepUnused(...valuesToKeep) {
|
|
4831
|
+
}
|
|
4832
|
+
|
|
4833
|
+
/**
|
|
4834
|
+
* Replaces parameters in template with values from parameters object
|
|
4835
|
+
*
|
|
4836
|
+
* Note: This function is not places strings into string,
|
|
4837
|
+
* It's more complex and can handle this operation specifically for LLM models
|
|
4838
|
+
*
|
|
4839
|
+
* @param template the template with parameters in {curly} braces
|
|
4840
|
+
* @param parameters the object with parameters
|
|
4841
|
+
* @returns the template with replaced parameters
|
|
4842
|
+
* @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
|
|
4843
|
+
* @public exported from `@promptbook/utils`
|
|
4844
|
+
*/
|
|
4845
|
+
function templateParameters(template, parameters) {
|
|
4846
|
+
for (const [parameterName, parameterValue] of Object.entries(parameters)) {
|
|
4847
|
+
if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
|
|
4848
|
+
throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
|
|
4849
|
+
}
|
|
4850
|
+
else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
|
|
4851
|
+
// TODO: [๐ต]
|
|
4852
|
+
throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
let replacedTemplates = template;
|
|
4856
|
+
let match;
|
|
4857
|
+
let loopLimit = LOOP_LIMIT;
|
|
4858
|
+
while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
|
|
4859
|
+
.exec(replacedTemplates))) {
|
|
4860
|
+
if (loopLimit-- < 0) {
|
|
4861
|
+
throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
|
|
4862
|
+
}
|
|
4863
|
+
const precol = match.groups.precol;
|
|
4864
|
+
const parameterName = match.groups.parameterName;
|
|
4865
|
+
if (parameterName === '') {
|
|
4866
|
+
// Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
|
|
4867
|
+
continue;
|
|
4868
|
+
}
|
|
4869
|
+
if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
|
|
4870
|
+
throw new PipelineExecutionError('Parameter is already opened or not closed');
|
|
4871
|
+
}
|
|
4872
|
+
if (parameters[parameterName] === undefined) {
|
|
4873
|
+
throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
|
|
4874
|
+
}
|
|
4875
|
+
let parameterValue = parameters[parameterName];
|
|
4876
|
+
if (parameterValue === undefined) {
|
|
4877
|
+
throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
|
|
4878
|
+
}
|
|
4879
|
+
parameterValue = valueToString(parameterValue);
|
|
4880
|
+
// Escape curly braces in parameter values to prevent prompt-injection
|
|
4881
|
+
parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
|
|
4882
|
+
if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
|
|
4883
|
+
parameterValue = parameterValue
|
|
4884
|
+
.split('\n')
|
|
4885
|
+
.map((line, index) => (index === 0 ? line : `${precol}${line}`))
|
|
4886
|
+
.join('\n');
|
|
4887
|
+
}
|
|
4888
|
+
replacedTemplates =
|
|
4889
|
+
replacedTemplates.substring(0, match.index + precol.length) +
|
|
4890
|
+
parameterValue +
|
|
4891
|
+
replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
|
|
4892
|
+
}
|
|
4893
|
+
// [๐ซ] Check if there are parameters that are not closed properly
|
|
4894
|
+
if (/{\w+$/.test(replacedTemplates)) {
|
|
4895
|
+
throw new PipelineExecutionError('Parameter is not closed');
|
|
4896
|
+
}
|
|
4897
|
+
// [๐ซ] Check if there are parameters that are not opened properly
|
|
4898
|
+
if (/^\w+}/.test(replacedTemplates)) {
|
|
4899
|
+
throw new PipelineExecutionError('Parameter is not opened');
|
|
4900
|
+
}
|
|
4901
|
+
return replacedTemplates;
|
|
4902
|
+
}
|
|
4903
|
+
|
|
4816
4904
|
/**
|
|
4817
4905
|
* Extracts all code blocks from markdown.
|
|
4818
4906
|
*
|
|
@@ -4915,94 +5003,6 @@ function extractJsonBlock(markdown) {
|
|
|
4915
5003
|
* TODO: [๐ข] Make this logic part of `JsonFormatParser` or `isValidJsonString`
|
|
4916
5004
|
*/
|
|
4917
5005
|
|
|
4918
|
-
/**
|
|
4919
|
-
* Just says that the variable is not used but should be kept
|
|
4920
|
-
* No side effects.
|
|
4921
|
-
*
|
|
4922
|
-
* Note: It can be useful for:
|
|
4923
|
-
*
|
|
4924
|
-
* 1) Suppressing eager optimization of unused imports
|
|
4925
|
-
* 2) Suppressing eslint errors of unused variables in the tests
|
|
4926
|
-
* 3) Keeping the type of the variable for type testing
|
|
4927
|
-
*
|
|
4928
|
-
* @param value any values
|
|
4929
|
-
* @returns void
|
|
4930
|
-
* @private within the repository
|
|
4931
|
-
*/
|
|
4932
|
-
function keepUnused(...valuesToKeep) {
|
|
4933
|
-
}
|
|
4934
|
-
|
|
4935
|
-
/**
|
|
4936
|
-
* Replaces parameters in template with values from parameters object
|
|
4937
|
-
*
|
|
4938
|
-
* Note: This function is not places strings into string,
|
|
4939
|
-
* It's more complex and can handle this operation specifically for LLM models
|
|
4940
|
-
*
|
|
4941
|
-
* @param template the template with parameters in {curly} braces
|
|
4942
|
-
* @param parameters the object with parameters
|
|
4943
|
-
* @returns the template with replaced parameters
|
|
4944
|
-
* @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
|
|
4945
|
-
* @public exported from `@promptbook/utils`
|
|
4946
|
-
*/
|
|
4947
|
-
function templateParameters(template, parameters) {
|
|
4948
|
-
for (const [parameterName, parameterValue] of Object.entries(parameters)) {
|
|
4949
|
-
if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
|
|
4950
|
-
throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
|
|
4951
|
-
}
|
|
4952
|
-
else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
|
|
4953
|
-
// TODO: [๐ต]
|
|
4954
|
-
throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
|
|
4955
|
-
}
|
|
4956
|
-
}
|
|
4957
|
-
let replacedTemplates = template;
|
|
4958
|
-
let match;
|
|
4959
|
-
let loopLimit = LOOP_LIMIT;
|
|
4960
|
-
while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
|
|
4961
|
-
.exec(replacedTemplates))) {
|
|
4962
|
-
if (loopLimit-- < 0) {
|
|
4963
|
-
throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
|
|
4964
|
-
}
|
|
4965
|
-
const precol = match.groups.precol;
|
|
4966
|
-
const parameterName = match.groups.parameterName;
|
|
4967
|
-
if (parameterName === '') {
|
|
4968
|
-
// Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
|
|
4969
|
-
continue;
|
|
4970
|
-
}
|
|
4971
|
-
if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
|
|
4972
|
-
throw new PipelineExecutionError('Parameter is already opened or not closed');
|
|
4973
|
-
}
|
|
4974
|
-
if (parameters[parameterName] === undefined) {
|
|
4975
|
-
throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
|
|
4976
|
-
}
|
|
4977
|
-
let parameterValue = parameters[parameterName];
|
|
4978
|
-
if (parameterValue === undefined) {
|
|
4979
|
-
throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
|
|
4980
|
-
}
|
|
4981
|
-
parameterValue = valueToString(parameterValue);
|
|
4982
|
-
// Escape curly braces in parameter values to prevent prompt-injection
|
|
4983
|
-
parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
|
|
4984
|
-
if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
|
|
4985
|
-
parameterValue = parameterValue
|
|
4986
|
-
.split('\n')
|
|
4987
|
-
.map((line, index) => (index === 0 ? line : `${precol}${line}`))
|
|
4988
|
-
.join('\n');
|
|
4989
|
-
}
|
|
4990
|
-
replacedTemplates =
|
|
4991
|
-
replacedTemplates.substring(0, match.index + precol.length) +
|
|
4992
|
-
parameterValue +
|
|
4993
|
-
replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
|
|
4994
|
-
}
|
|
4995
|
-
// [๐ซ] Check if there are parameters that are not closed properly
|
|
4996
|
-
if (/{\w+$/.test(replacedTemplates)) {
|
|
4997
|
-
throw new PipelineExecutionError('Parameter is not closed');
|
|
4998
|
-
}
|
|
4999
|
-
// [๐ซ] Check if there are parameters that are not opened properly
|
|
5000
|
-
if (/^\w+}/.test(replacedTemplates)) {
|
|
5001
|
-
throw new PipelineExecutionError('Parameter is not opened');
|
|
5002
|
-
}
|
|
5003
|
-
return replacedTemplates;
|
|
5004
|
-
}
|
|
5005
|
-
|
|
5006
5006
|
/**
|
|
5007
5007
|
* Counts number of characters in the text
|
|
5008
5008
|
*
|
|
@@ -5163,6 +5163,68 @@ function checkExpectations(expectations, value) {
|
|
|
5163
5163
|
* Note: [๐] and [๐ค ] are interconnected together
|
|
5164
5164
|
*/
|
|
5165
5165
|
|
|
5166
|
+
/**
|
|
5167
|
+
* Validates a prompt result against expectations and format requirements.
|
|
5168
|
+
* This function provides a common abstraction for result validation that can be used
|
|
5169
|
+
* by both execution logic and caching logic to ensure consistency.
|
|
5170
|
+
*
|
|
5171
|
+
* @param options - The validation options including result string, expectations, and format
|
|
5172
|
+
* @returns Validation result with processed string and validity status
|
|
5173
|
+
* @private internal function of `createPipelineExecutor` and `cacheLlmTools`
|
|
5174
|
+
*/
|
|
5175
|
+
function validatePromptResult(options) {
|
|
5176
|
+
const { resultString, expectations, format } = options;
|
|
5177
|
+
let processedResultString = resultString;
|
|
5178
|
+
let validationError;
|
|
5179
|
+
try {
|
|
5180
|
+
// TODO: [๐] Unite object for expecting amount and format
|
|
5181
|
+
if (format) {
|
|
5182
|
+
if (format === 'JSON') {
|
|
5183
|
+
if (!isValidJsonString(processedResultString)) {
|
|
5184
|
+
// TODO: [๐ข] Do more universally via `FormatParser`
|
|
5185
|
+
try {
|
|
5186
|
+
processedResultString = extractJsonBlock(processedResultString);
|
|
5187
|
+
}
|
|
5188
|
+
catch (error) {
|
|
5189
|
+
keepUnused(error);
|
|
5190
|
+
throw new ExpectError(spaceTrim$1((block) => `
|
|
5191
|
+
Expected valid JSON string
|
|
5192
|
+
|
|
5193
|
+
The expected JSON text:
|
|
5194
|
+
${block(processedResultString)}
|
|
5195
|
+
`));
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
}
|
|
5199
|
+
else {
|
|
5200
|
+
throw new UnexpectedError(`Unknown format "${format}"`);
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
// TODO: [๐] Unite object for expecting amount and format
|
|
5204
|
+
if (expectations) {
|
|
5205
|
+
checkExpectations(expectations, processedResultString);
|
|
5206
|
+
}
|
|
5207
|
+
return {
|
|
5208
|
+
isValid: true,
|
|
5209
|
+
processedResultString,
|
|
5210
|
+
};
|
|
5211
|
+
}
|
|
5212
|
+
catch (error) {
|
|
5213
|
+
if (error instanceof ExpectError) {
|
|
5214
|
+
validationError = error;
|
|
5215
|
+
}
|
|
5216
|
+
else {
|
|
5217
|
+
// Re-throw non-ExpectError errors (like UnexpectedError)
|
|
5218
|
+
throw error;
|
|
5219
|
+
}
|
|
5220
|
+
return {
|
|
5221
|
+
isValid: false,
|
|
5222
|
+
processedResultString,
|
|
5223
|
+
error: validationError,
|
|
5224
|
+
};
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
|
|
5166
5228
|
/**
|
|
5167
5229
|
* Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
|
|
5168
5230
|
* (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
|
|
@@ -5180,17 +5242,18 @@ async function executeAttempts(options) {
|
|
|
5180
5242
|
$resultString: null,
|
|
5181
5243
|
$expectError: null,
|
|
5182
5244
|
$scriptPipelineExecutionErrors: [],
|
|
5245
|
+
$failedResults: [], // Track all failed attempts
|
|
5183
5246
|
};
|
|
5184
5247
|
// TODO: [๐] Make arrayable LLMs -> single LLM DRY
|
|
5185
5248
|
const _llms = arrayableToArray(tools.llm);
|
|
5186
5249
|
const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
|
|
5187
|
-
attempts: for (let
|
|
5188
|
-
const isJokerAttempt =
|
|
5189
|
-
const jokerParameterName = jokerParameterNames[jokerParameterNames.length +
|
|
5250
|
+
attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
|
|
5251
|
+
const isJokerAttempt = attemptIndex < 0;
|
|
5252
|
+
const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
|
|
5190
5253
|
// TODO: [๐ง ][๐ญ] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
|
|
5191
5254
|
if (isJokerAttempt && !jokerParameterName) {
|
|
5192
5255
|
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
5193
|
-
Joker not found in attempt ${
|
|
5256
|
+
Joker not found in attempt ${attemptIndex}
|
|
5194
5257
|
|
|
5195
5258
|
${block(pipelineIdentification)}
|
|
5196
5259
|
`));
|
|
@@ -5388,35 +5451,18 @@ async function executeAttempts(options) {
|
|
|
5388
5451
|
}
|
|
5389
5452
|
}
|
|
5390
5453
|
// TODO: [๐] Unite object for expecting amount and format
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
throw new ExpectError(spaceTrim$1((block) => `
|
|
5401
|
-
Expected valid JSON string
|
|
5402
|
-
|
|
5403
|
-
${block(
|
|
5404
|
-
/*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
|
|
5405
|
-
`));
|
|
5406
|
-
}
|
|
5407
|
-
}
|
|
5408
|
-
}
|
|
5409
|
-
else {
|
|
5410
|
-
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
5411
|
-
Unknown format "${task.format}"
|
|
5412
|
-
|
|
5413
|
-
${block(pipelineIdentification)}
|
|
5414
|
-
`));
|
|
5454
|
+
// Use the common validation function for both format and expectations
|
|
5455
|
+
if (task.format || task.expectations) {
|
|
5456
|
+
const validationResult = validatePromptResult({
|
|
5457
|
+
resultString: $ongoingTaskResult.$resultString || '',
|
|
5458
|
+
expectations: task.expectations,
|
|
5459
|
+
format: task.format,
|
|
5460
|
+
});
|
|
5461
|
+
if (!validationResult.isValid) {
|
|
5462
|
+
throw validationResult.error;
|
|
5415
5463
|
}
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
if (task.expectations) {
|
|
5419
|
-
checkExpectations(task.expectations, $ongoingTaskResult.$resultString || '');
|
|
5464
|
+
// Update the result string in case format processing modified it (e.g., JSON extraction)
|
|
5465
|
+
$ongoingTaskResult.$resultString = validationResult.processedResultString;
|
|
5420
5466
|
}
|
|
5421
5467
|
break attempts;
|
|
5422
5468
|
}
|
|
@@ -5425,6 +5471,15 @@ async function executeAttempts(options) {
|
|
|
5425
5471
|
throw error;
|
|
5426
5472
|
}
|
|
5427
5473
|
$ongoingTaskResult.$expectError = error;
|
|
5474
|
+
// Store each failed attempt
|
|
5475
|
+
if (!Array.isArray($ongoingTaskResult.$failedResults)) {
|
|
5476
|
+
$ongoingTaskResult.$failedResults = [];
|
|
5477
|
+
}
|
|
5478
|
+
$ongoingTaskResult.$failedResults.push({
|
|
5479
|
+
attemptIndex,
|
|
5480
|
+
result: $ongoingTaskResult.$resultString,
|
|
5481
|
+
error: error,
|
|
5482
|
+
});
|
|
5428
5483
|
}
|
|
5429
5484
|
finally {
|
|
5430
5485
|
if (!isJokerAttempt &&
|
|
@@ -5446,35 +5501,41 @@ async function executeAttempts(options) {
|
|
|
5446
5501
|
});
|
|
5447
5502
|
}
|
|
5448
5503
|
}
|
|
5449
|
-
if ($ongoingTaskResult.$expectError !== null &&
|
|
5504
|
+
if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
|
|
5505
|
+
// Note: Create a summary of all failures
|
|
5506
|
+
const failuresSummary = $ongoingTaskResult.$failedResults
|
|
5507
|
+
.map((failure) => spaceTrim$1((block) => {
|
|
5508
|
+
var _a, _b;
|
|
5509
|
+
return `
|
|
5510
|
+
Attempt ${failure.attemptIndex + 1}:
|
|
5511
|
+
Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
|
|
5512
|
+
${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
|
|
5513
|
+
|
|
5514
|
+
Result:
|
|
5515
|
+
${block(failure.result === null
|
|
5516
|
+
? 'null'
|
|
5517
|
+
: spaceTrim$1(failure.result)
|
|
5518
|
+
.split('\n')
|
|
5519
|
+
.map((line) => `> ${line}`)
|
|
5520
|
+
.join('\n'))}
|
|
5521
|
+
`;
|
|
5522
|
+
}))
|
|
5523
|
+
.join('\n\n---\n\n');
|
|
5450
5524
|
throw new PipelineExecutionError(spaceTrim$1((block) => {
|
|
5451
|
-
var _a
|
|
5525
|
+
var _a;
|
|
5452
5526
|
return `
|
|
5453
5527
|
LLM execution failed ${maxExecutionAttempts}x
|
|
5454
5528
|
|
|
5455
5529
|
${block(pipelineIdentification)}
|
|
5456
5530
|
|
|
5457
|
-
---
|
|
5458
5531
|
The Prompt:
|
|
5459
5532
|
${block((((_a = $ongoingTaskResult.$prompt) === null || _a === void 0 ? void 0 : _a.content) || '')
|
|
5460
5533
|
.split('\n')
|
|
5461
5534
|
.map((line) => `> ${line}`)
|
|
5462
5535
|
.join('\n'))}
|
|
5463
5536
|
|
|
5464
|
-
|
|
5465
|
-
${block(
|
|
5466
|
-
.split('\n')
|
|
5467
|
-
.map((line) => `> ${line}`)
|
|
5468
|
-
.join('\n'))}
|
|
5469
|
-
|
|
5470
|
-
Last result:
|
|
5471
|
-
${block($ongoingTaskResult.$resultString === null
|
|
5472
|
-
? 'null'
|
|
5473
|
-
: spaceTrim$1($ongoingTaskResult.$resultString)
|
|
5474
|
-
.split('\n')
|
|
5475
|
-
.map((line) => `> ${line}`)
|
|
5476
|
-
.join('\n'))}
|
|
5477
|
-
---
|
|
5537
|
+
All Failed Attempts:
|
|
5538
|
+
${block(failuresSummary)}
|
|
5478
5539
|
`;
|
|
5479
5540
|
}));
|
|
5480
5541
|
}
|
|
@@ -6305,6 +6366,46 @@ function createPipelineExecutor(options) {
|
|
|
6305
6366
|
return pipelineExecutor;
|
|
6306
6367
|
}
|
|
6307
6368
|
|
|
6369
|
+
/**
|
|
6370
|
+
* Detects if the code is running in a browser environment in main thread (Not in a web worker)
|
|
6371
|
+
*
|
|
6372
|
+
* Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
|
|
6373
|
+
*
|
|
6374
|
+
* @public exported from `@promptbook/utils`
|
|
6375
|
+
*/
|
|
6376
|
+
const $isRunningInBrowser = new Function(`
|
|
6377
|
+
try {
|
|
6378
|
+
return this === window;
|
|
6379
|
+
} catch (e) {
|
|
6380
|
+
return false;
|
|
6381
|
+
}
|
|
6382
|
+
`);
|
|
6383
|
+
/**
|
|
6384
|
+
* TODO: [๐บ]
|
|
6385
|
+
*/
|
|
6386
|
+
|
|
6387
|
+
/**
|
|
6388
|
+
* Detects if the code is running in a web worker
|
|
6389
|
+
*
|
|
6390
|
+
* Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
|
|
6391
|
+
*
|
|
6392
|
+
* @public exported from `@promptbook/utils`
|
|
6393
|
+
*/
|
|
6394
|
+
const $isRunningInWebWorker = new Function(`
|
|
6395
|
+
try {
|
|
6396
|
+
if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
|
|
6397
|
+
return true;
|
|
6398
|
+
} else {
|
|
6399
|
+
return false;
|
|
6400
|
+
}
|
|
6401
|
+
} catch (e) {
|
|
6402
|
+
return false;
|
|
6403
|
+
}
|
|
6404
|
+
`);
|
|
6405
|
+
/**
|
|
6406
|
+
* TODO: [๐บ]
|
|
6407
|
+
*/
|
|
6408
|
+
|
|
6308
6409
|
/**
|
|
6309
6410
|
* Register for LLM tools.
|
|
6310
6411
|
*
|
|
@@ -6473,8 +6574,10 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
|
|
|
6473
6574
|
.list()
|
|
6474
6575
|
.find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
|
|
6475
6576
|
if (registeredItem === undefined) {
|
|
6577
|
+
console.log('!!! $llmToolsRegister.list()', $llmToolsRegister.list());
|
|
6476
6578
|
throw new Error(spaceTrim((block) => `
|
|
6477
6579
|
There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
|
|
6580
|
+
Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
|
|
6478
6581
|
|
|
6479
6582
|
You have probably forgotten install and import the provider package.
|
|
6480
6583
|
To fix this issue, you can:
|
|
@@ -6592,24 +6695,6 @@ function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
|
|
|
6592
6695
|
* TODO: [๐บ] Use some intermediate util splitWords
|
|
6593
6696
|
*/
|
|
6594
6697
|
|
|
6595
|
-
/**
|
|
6596
|
-
* Detects if the code is running in a browser environment in main thread (Not in a web worker)
|
|
6597
|
-
*
|
|
6598
|
-
* Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
|
|
6599
|
-
*
|
|
6600
|
-
* @public exported from `@promptbook/utils`
|
|
6601
|
-
*/
|
|
6602
|
-
new Function(`
|
|
6603
|
-
try {
|
|
6604
|
-
return this === window;
|
|
6605
|
-
} catch (e) {
|
|
6606
|
-
return false;
|
|
6607
|
-
}
|
|
6608
|
-
`);
|
|
6609
|
-
/**
|
|
6610
|
-
* TODO: [๐บ]
|
|
6611
|
-
*/
|
|
6612
|
-
|
|
6613
6698
|
/**
|
|
6614
6699
|
* Detects if the code is running in jest environment
|
|
6615
6700
|
*
|
|
@@ -6628,28 +6713,6 @@ new Function(`
|
|
|
6628
6713
|
* TODO: [๐บ]
|
|
6629
6714
|
*/
|
|
6630
6715
|
|
|
6631
|
-
/**
|
|
6632
|
-
* Detects if the code is running in a web worker
|
|
6633
|
-
*
|
|
6634
|
-
* Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
|
|
6635
|
-
*
|
|
6636
|
-
* @public exported from `@promptbook/utils`
|
|
6637
|
-
*/
|
|
6638
|
-
new Function(`
|
|
6639
|
-
try {
|
|
6640
|
-
if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
|
|
6641
|
-
return true;
|
|
6642
|
-
} else {
|
|
6643
|
-
return false;
|
|
6644
|
-
}
|
|
6645
|
-
} catch (e) {
|
|
6646
|
-
return false;
|
|
6647
|
-
}
|
|
6648
|
-
`);
|
|
6649
|
-
/**
|
|
6650
|
-
* TODO: [๐บ]
|
|
6651
|
-
*/
|
|
6652
|
-
|
|
6653
6716
|
/**
|
|
6654
6717
|
* Makes first letter of a string uppercase
|
|
6655
6718
|
*
|
|
@@ -7821,6 +7884,66 @@ function startRemoteServer(options) {
|
|
|
7821
7884
|
response.setHeader('X-Powered-By', 'Promptbook engine');
|
|
7822
7885
|
next();
|
|
7823
7886
|
});
|
|
7887
|
+
// Note: OpenAI-compatible chat completions endpoint
|
|
7888
|
+
app.post('/v1/chat/completions', async (request, response) => {
|
|
7889
|
+
// TODO: !!!! Make more promptbook-native:
|
|
7890
|
+
try {
|
|
7891
|
+
const params = request.body;
|
|
7892
|
+
const { model, messages } = params;
|
|
7893
|
+
// Convert messages to a single prompt
|
|
7894
|
+
const prompt = messages
|
|
7895
|
+
.map((message) => `${message.role}: ${message.content}`)
|
|
7896
|
+
.join('\n');
|
|
7897
|
+
// Get pipeline for the book
|
|
7898
|
+
if (!collection) {
|
|
7899
|
+
throw new Error('No collection available');
|
|
7900
|
+
}
|
|
7901
|
+
const pipeline = await collection.getPipelineByUrl(model);
|
|
7902
|
+
const pipelineExecutor = createPipelineExecutor({
|
|
7903
|
+
pipeline,
|
|
7904
|
+
tools: await getExecutionToolsFromIdentification({
|
|
7905
|
+
isAnonymous: true,
|
|
7906
|
+
llmToolsConfiguration: [],
|
|
7907
|
+
}),
|
|
7908
|
+
});
|
|
7909
|
+
// Execute the pipeline with the prompt content as input
|
|
7910
|
+
const result = await pipelineExecutor({ prompt }).asPromise({ isCrashedOnError: true });
|
|
7911
|
+
if (!result.isSuccessful) {
|
|
7912
|
+
throw new Error(`Failed to execute book: ${result.errors.join(', ')}`);
|
|
7913
|
+
}
|
|
7914
|
+
// Return the result in OpenAI-compatible format
|
|
7915
|
+
response.json({
|
|
7916
|
+
id: 'chatcmpl-' + Math.random().toString(36).substring(2),
|
|
7917
|
+
object: 'chat.completion',
|
|
7918
|
+
created: Math.floor(Date.now() / 1000),
|
|
7919
|
+
model,
|
|
7920
|
+
choices: [
|
|
7921
|
+
{
|
|
7922
|
+
index: 0,
|
|
7923
|
+
message: {
|
|
7924
|
+
role: 'assistant',
|
|
7925
|
+
content: result.outputParameters.response,
|
|
7926
|
+
},
|
|
7927
|
+
finish_reason: 'stop',
|
|
7928
|
+
},
|
|
7929
|
+
],
|
|
7930
|
+
usage: {
|
|
7931
|
+
prompt_tokens: 0,
|
|
7932
|
+
completion_tokens: 0,
|
|
7933
|
+
total_tokens: 0,
|
|
7934
|
+
},
|
|
7935
|
+
});
|
|
7936
|
+
}
|
|
7937
|
+
catch (error) {
|
|
7938
|
+
response.status(500).json({
|
|
7939
|
+
error: {
|
|
7940
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
7941
|
+
type: 'server_error',
|
|
7942
|
+
code: 'internal_error',
|
|
7943
|
+
},
|
|
7944
|
+
});
|
|
7945
|
+
}
|
|
7946
|
+
});
|
|
7824
7947
|
// TODO: [๐ฅบ] Expose openapiJson to consumer and also allow to add new routes
|
|
7825
7948
|
app.use(OpenApiValidator.middleware({
|
|
7826
7949
|
apiSpec: openapiJson,
|
|
@@ -8181,7 +8304,6 @@ function startRemoteServer(options) {
|
|
|
8181
8304
|
catch (error) {
|
|
8182
8305
|
assertsError(error);
|
|
8183
8306
|
socket.emit('error', serializeError(error));
|
|
8184
|
-
// <- TODO: [๐] There is a problem with the remote server handling errors and sending them back to the client
|
|
8185
8307
|
}
|
|
8186
8308
|
finally {
|
|
8187
8309
|
socket.disconnect();
|