@promptbook/cli 0.104.0 → 0.105.0-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.
package/umd/index.umd.js CHANGED
@@ -56,7 +56,7 @@
56
56
  * @generated
57
57
  * @see https://github.com/webgptorg/promptbook
58
58
  */
59
- const PROMPTBOOK_ENGINE_VERSION = '0.104.0';
59
+ const PROMPTBOOK_ENGINE_VERSION = '0.105.0-0';
60
60
  /**
61
61
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
62
62
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -3502,7 +3502,7 @@
3502
3502
  *
3503
3503
  * @public exported from `@promptbook/utils`
3504
3504
  */
3505
- function deserializeError(error) {
3505
+ function deserializeError(error, isStackAddedToMessage = true) {
3506
3506
  const { name, stack, id } = error; // Added id
3507
3507
  let { message } = error;
3508
3508
  let ErrorClass = ALL_ERRORS[error.name];
@@ -3510,7 +3510,7 @@
3510
3510
  ErrorClass = Error;
3511
3511
  message = `${name}: ${message}`;
3512
3512
  }
3513
- if (stack !== undefined && stack !== '') {
3513
+ if (isStackAddedToMessage && stack !== undefined && stack !== '') {
3514
3514
  message = spaceTrim__default["default"]((block) => `
3515
3515
  ${block(message)}
3516
3516
 
@@ -4312,6 +4312,9 @@
4312
4312
  * @public exported from `@promptbook/utils`
4313
4313
  */
4314
4314
  function parseNumber(value) {
4315
+ if (value === null || value === undefined) {
4316
+ return 0;
4317
+ }
4315
4318
  const originalValue = value;
4316
4319
  if (typeof value === 'number') {
4317
4320
  value = value.toString(); // <- TODO: Maybe more efficient way to do this
@@ -19504,83 +19507,180 @@
19504
19507
  content: msg.content,
19505
19508
  }));
19506
19509
  }
19507
- const rawRequest = {
19508
- ...modelSettings,
19509
- messages: [
19510
- ...(currentModelRequirements.systemMessage === undefined
19511
- ? []
19512
- : [
19513
- {
19514
- role: 'system',
19515
- content: currentModelRequirements.systemMessage,
19516
- },
19517
- ]),
19518
- ...threadMessages,
19519
- {
19520
- role: 'user',
19521
- content: rawPromptContent,
19522
- },
19523
- ],
19524
- user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
19525
- tools: currentModelRequirements.tools === undefined
19526
- ? undefined
19527
- : mapToolsToOpenAi(currentModelRequirements.tools),
19510
+ const messages = [
19511
+ ...(currentModelRequirements.systemMessage === undefined
19512
+ ? []
19513
+ : [
19514
+ {
19515
+ role: 'system',
19516
+ content: currentModelRequirements.systemMessage,
19517
+ },
19518
+ ]),
19519
+ ...threadMessages,
19520
+ {
19521
+ role: 'user',
19522
+ content: rawPromptContent,
19523
+ },
19524
+ ];
19525
+ let totalUsage = {
19526
+ price: uncertainNumber(0),
19527
+ input: {
19528
+ tokensCount: uncertainNumber(0),
19529
+ charactersCount: uncertainNumber(0),
19530
+ wordsCount: uncertainNumber(0),
19531
+ sentencesCount: uncertainNumber(0),
19532
+ linesCount: uncertainNumber(0),
19533
+ paragraphsCount: uncertainNumber(0),
19534
+ pagesCount: uncertainNumber(0),
19535
+ },
19536
+ output: {
19537
+ tokensCount: uncertainNumber(0),
19538
+ charactersCount: uncertainNumber(0),
19539
+ wordsCount: uncertainNumber(0),
19540
+ sentencesCount: uncertainNumber(0),
19541
+ linesCount: uncertainNumber(0),
19542
+ paragraphsCount: uncertainNumber(0),
19543
+ pagesCount: uncertainNumber(0),
19544
+ },
19528
19545
  };
19546
+ const toolCalls = [];
19529
19547
  const start = $getCurrentDate();
19530
- if (this.options.isVerbose) {
19531
- console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
19532
- }
19533
- try {
19534
- const rawResponse = await this.limiter
19535
- .schedule(() => this.makeRequestWithNetworkRetry(() => client.chat.completions.create(rawRequest)))
19536
- .catch((error) => {
19537
- assertsError(error);
19538
- if (this.options.isVerbose) {
19539
- console.info(colors__default["default"].bgRed('error'), error);
19540
- }
19541
- throw error;
19542
- });
19548
+ const tools = 'tools' in prompt && Array.isArray(prompt.tools) ? prompt.tools : currentModelRequirements.tools;
19549
+ let isLooping = true;
19550
+ while (isLooping) {
19551
+ const rawRequest = {
19552
+ ...modelSettings,
19553
+ messages,
19554
+ user: (_a = this.options.userId) === null || _a === void 0 ? void 0 : _a.toString(),
19555
+ tools: tools === undefined ? undefined : mapToolsToOpenAi(tools),
19556
+ };
19543
19557
  if (this.options.isVerbose) {
19544
- console.info(colors__default["default"].bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
19545
- }
19546
- const complete = $getCurrentDate();
19547
- if (!rawResponse.choices[0]) {
19548
- throw new PipelineExecutionError(`No choises from ${this.title}`);
19549
- }
19550
- if (rawResponse.choices.length > 1) {
19551
- // TODO: This should be maybe only warning
19552
- throw new PipelineExecutionError(`More than one choise from ${this.title}`);
19553
- }
19554
- const resultContent = rawResponse.choices[0].message.content;
19555
- const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
19556
- if (resultContent === null) {
19557
- throw new PipelineExecutionError(`No response message from ${this.title}`);
19558
+ console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
19558
19559
  }
19559
- return exportJson({
19560
- name: 'promptResult',
19561
- message: `Result of \`OpenAiCompatibleExecutionTools.callChatModel\``,
19562
- order: [],
19563
- value: {
19564
- content: resultContent,
19565
- modelName: rawResponse.model || modelName,
19566
- timing: {
19567
- start,
19568
- complete,
19560
+ try {
19561
+ const rawResponse = await this.limiter
19562
+ .schedule(() => this.makeRequestWithNetworkRetry(() => client.chat.completions.create(rawRequest)))
19563
+ .catch((error) => {
19564
+ assertsError(error);
19565
+ if (this.options.isVerbose) {
19566
+ console.info(colors__default["default"].bgRed('error'), error);
19567
+ }
19568
+ throw error;
19569
+ });
19570
+ if (this.options.isVerbose) {
19571
+ console.info(colors__default["default"].bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
19572
+ }
19573
+ if (!rawResponse.choices[0]) {
19574
+ throw new PipelineExecutionError(`No choises from ${this.title}`);
19575
+ }
19576
+ const responseMessage = rawResponse.choices[0].message;
19577
+ messages.push(responseMessage);
19578
+ const usage = this.computeUsage(content || '', responseMessage.content || '', rawResponse);
19579
+ totalUsage = addUsage(totalUsage, usage);
19580
+ if (responseMessage.tool_calls && responseMessage.tool_calls.length > 0) {
19581
+ await forEachAsync(responseMessage.tool_calls, {}, async (toolCall) => {
19582
+ const functionName = toolCall.function.name;
19583
+ const functionArgs = toolCall.function.arguments;
19584
+ const executionTools = this.options
19585
+ .executionTools;
19586
+ if (!executionTools || !executionTools.script) {
19587
+ throw new PipelineExecutionError(`Model requested tool '${functionName}' but no executionTools.script were provided in OpenAiCompatibleExecutionTools options`);
19588
+ }
19589
+ // TODO: [DRY] Use some common tool caller
19590
+ const scriptTools = Array.isArray(executionTools.script)
19591
+ ? executionTools.script
19592
+ : [executionTools.script];
19593
+ let functionResponse;
19594
+ try {
19595
+ const scriptTool = scriptTools[0]; // <- TODO: [🧠] Which script tool to use?
19596
+ functionResponse = await scriptTool.execute({
19597
+ scriptLanguage: 'javascript',
19598
+ script: `
19599
+ const args = ${functionArgs};
19600
+ return await ${functionName}(args);
19601
+ `,
19602
+ parameters: {}, // <- TODO: [🧠] What parameters to pass?
19603
+ });
19604
+ }
19605
+ catch (error) {
19606
+ assertsError(error);
19607
+ functionResponse = `Error: ${error.message}`;
19608
+ }
19609
+ messages.push({
19610
+ role: 'tool',
19611
+ tool_call_id: toolCall.id,
19612
+ content: functionResponse,
19613
+ });
19614
+ toolCalls.push({
19615
+ name: functionName,
19616
+ arguments: functionArgs,
19617
+ result: functionResponse,
19618
+ rawToolCall: toolCall,
19619
+ });
19620
+ });
19621
+ continue;
19622
+ }
19623
+ const complete = $getCurrentDate();
19624
+ const resultContent = responseMessage.content;
19625
+ if (resultContent === null) {
19626
+ throw new PipelineExecutionError(`No response message from ${this.title}`);
19627
+ }
19628
+ isLooping = false;
19629
+ return exportJson({
19630
+ name: 'promptResult',
19631
+ message: `Result of \`OpenAiCompatibleExecutionTools.callChatModel\``,
19632
+ order: [],
19633
+ value: {
19634
+ content: resultContent,
19635
+ modelName: rawResponse.model || modelName,
19636
+ timing: {
19637
+ start,
19638
+ complete,
19639
+ },
19640
+ usage: totalUsage,
19641
+ toolCalls,
19642
+ rawPromptContent,
19643
+ rawRequest,
19644
+ rawResponse,
19569
19645
  },
19570
- usage,
19571
- rawPromptContent,
19572
- rawRequest,
19573
- rawResponse,
19574
- // <- [🗯]
19575
- },
19576
- });
19577
- }
19578
- catch (error) {
19579
- assertsError(error);
19580
- // Check if this is an unsupported parameter error
19581
- if (!isUnsupportedParameterError(error)) {
19582
- // If we have attemptStack, include it in the error message
19583
- if (attemptStack.length > 0) {
19646
+ });
19647
+ }
19648
+ catch (error) {
19649
+ isLooping = false;
19650
+ assertsError(error);
19651
+ // Check if this is an unsupported parameter error
19652
+ if (!isUnsupportedParameterError(error)) {
19653
+ // If we have attemptStack, include it in the error message
19654
+ if (attemptStack.length > 0) {
19655
+ throw new PipelineExecutionError(`All attempts failed. Attempt history:\n` +
19656
+ attemptStack
19657
+ .map((a, i) => ` ${i + 1}. Model: ${a.modelName}` +
19658
+ (a.unsupportedParameter ? `, Stripped: ${a.unsupportedParameter}` : '') +
19659
+ `, Error: ${a.errorMessage}` +
19660
+ (a.stripped ? ' (stripped and retried)' : ''))
19661
+ .join('\n') +
19662
+ `\nFinal error: ${error.message}`);
19663
+ }
19664
+ throw error;
19665
+ }
19666
+ // Parse which parameter is unsupported
19667
+ const unsupportedParameter = parseUnsupportedParameterError(error.message);
19668
+ if (!unsupportedParameter) {
19669
+ if (this.options.isVerbose) {
19670
+ console.warn(colors__default["default"].bgYellow('Warning'), 'Could not parse unsupported parameter from error:', error.message);
19671
+ }
19672
+ throw error;
19673
+ }
19674
+ // Create a unique key for this model + parameter combination to prevent infinite loops
19675
+ const retryKey = `${modelName}-${unsupportedParameter}`;
19676
+ if (retriedUnsupportedParameters.has(retryKey)) {
19677
+ // Already retried this parameter, throw the error with attemptStack
19678
+ attemptStack.push({
19679
+ modelName,
19680
+ unsupportedParameter,
19681
+ errorMessage: error.message,
19682
+ stripped: true,
19683
+ });
19584
19684
  throw new PipelineExecutionError(`All attempts failed. Attempt history:\n` +
19585
19685
  attemptStack
19586
19686
  .map((a, i) => ` ${i + 1}. Model: ${a.modelName}` +
@@ -19590,52 +19690,25 @@
19590
19690
  .join('\n') +
19591
19691
  `\nFinal error: ${error.message}`);
19592
19692
  }
19593
- throw error;
19594
- }
19595
- // Parse which parameter is unsupported
19596
- const unsupportedParameter = parseUnsupportedParameterError(error.message);
19597
- if (!unsupportedParameter) {
19693
+ // Mark this parameter as retried
19694
+ retriedUnsupportedParameters.add(retryKey);
19695
+ // Log warning in verbose mode
19598
19696
  if (this.options.isVerbose) {
19599
- console.warn(colors__default["default"].bgYellow('Warning'), 'Could not parse unsupported parameter from error:', error.message);
19697
+ console.warn(colors__default["default"].bgYellow('Warning'), `Removing unsupported parameter '${unsupportedParameter}' for model '${modelName}' and retrying request`);
19600
19698
  }
19601
- throw error;
19602
- }
19603
- // Create a unique key for this model + parameter combination to prevent infinite loops
19604
- const retryKey = `${modelName}-${unsupportedParameter}`;
19605
- if (retriedUnsupportedParameters.has(retryKey)) {
19606
- // Already retried this parameter, throw the error with attemptStack
19699
+ // Add to attemptStack
19607
19700
  attemptStack.push({
19608
19701
  modelName,
19609
19702
  unsupportedParameter,
19610
19703
  errorMessage: error.message,
19611
19704
  stripped: true,
19612
19705
  });
19613
- throw new PipelineExecutionError(`All attempts failed. Attempt history:\n` +
19614
- attemptStack
19615
- .map((a, i) => ` ${i + 1}. Model: ${a.modelName}` +
19616
- (a.unsupportedParameter ? `, Stripped: ${a.unsupportedParameter}` : '') +
19617
- `, Error: ${a.errorMessage}` +
19618
- (a.stripped ? ' (stripped and retried)' : ''))
19619
- .join('\n') +
19620
- `\nFinal error: ${error.message}`);
19706
+ // Remove the unsupported parameter and retry
19707
+ const modifiedModelRequirements = removeUnsupportedModelRequirement(currentModelRequirements, unsupportedParameter);
19708
+ return this.callChatModelWithRetry(prompt, modifiedModelRequirements, attemptStack, retriedUnsupportedParameters);
19621
19709
  }
19622
- // Mark this parameter as retried
19623
- retriedUnsupportedParameters.add(retryKey);
19624
- // Log warning in verbose mode
19625
- if (this.options.isVerbose) {
19626
- console.warn(colors__default["default"].bgYellow('Warning'), `Removing unsupported parameter '${unsupportedParameter}' for model '${modelName}' and retrying request`);
19627
- }
19628
- // Add to attemptStack
19629
- attemptStack.push({
19630
- modelName,
19631
- unsupportedParameter,
19632
- errorMessage: error.message,
19633
- stripped: true,
19634
- });
19635
- // Remove the unsupported parameter and retry
19636
- const modifiedModelRequirements = removeUnsupportedModelRequirement(currentModelRequirements, unsupportedParameter);
19637
- return this.callChatModelWithRetry(prompt, modifiedModelRequirements, attemptStack, retriedUnsupportedParameters);
19638
19710
  }
19711
+ throw new PipelineExecutionError(`Tool calling loop did not return a result from ${this.title}`);
19639
19712
  }
19640
19713
  /**
19641
19714
  * Calls OpenAI API to use a complete model.
@@ -23428,6 +23501,79 @@
23428
23501
  * Note: [💞] Ignore a discrepancy between file name and entity name
23429
23502
  */
23430
23503
 
23504
+ /**
23505
+ * IMPORT commitment definition
23506
+ *
23507
+ * The IMPORT commitment tells the agent to import content from another agent at the current location.
23508
+ *
23509
+ * Example usage in agent source:
23510
+ *
23511
+ * ```book
23512
+ * IMPORT https://s6.ptbk.io/benjamin-white
23513
+ * ```
23514
+ *
23515
+ * @private [🪔] Maybe export the commitments through some package
23516
+ */
23517
+ class ImportCommitmentDefinition extends BaseCommitmentDefinition {
23518
+ constructor(type = 'IMPORT') {
23519
+ super(type);
23520
+ }
23521
+ /**
23522
+ * Short one-line description of IMPORT.
23523
+ */
23524
+ get description() {
23525
+ return 'Import content from another agent.';
23526
+ }
23527
+ /**
23528
+ * Icon for this commitment.
23529
+ */
23530
+ get icon() {
23531
+ return '📥';
23532
+ }
23533
+ /**
23534
+ * Markdown documentation for IMPORT commitment.
23535
+ */
23536
+ get documentation() {
23537
+ return spaceTrim$1.spaceTrim(`
23538
+ # ${this.type}
23539
+
23540
+ Imports content from another agent at the location of the commitment.
23541
+
23542
+ ## Examples
23543
+
23544
+ \`\`\`book
23545
+ My AI Agent
23546
+
23547
+ IMPORT https://s6.ptbk.io/benjamin-white
23548
+ RULE Speak only in English.
23549
+ \`\`\`
23550
+ `);
23551
+ }
23552
+ applyToAgentModelRequirements(requirements, content) {
23553
+ const trimmedContent = content.trim();
23554
+ if (!trimmedContent) {
23555
+ return requirements;
23556
+ }
23557
+ if (!isValidAgentUrl(trimmedContent)) {
23558
+ throw new Error(spaceTrim$1.spaceTrim((block) => `
23559
+ Invalid agent URL in IMPORT commitment: "${trimmedContent}"
23560
+
23561
+ \`\`\`book
23562
+ ${block(content)}
23563
+ \`\`\`
23564
+ `));
23565
+ }
23566
+ const importedAgentUrl = trimmedContent;
23567
+ return {
23568
+ ...requirements,
23569
+ importedAgentUrls: [...(requirements.importedAgentUrls || []), importedAgentUrl],
23570
+ };
23571
+ }
23572
+ }
23573
+ /**
23574
+ * Note: [💞] Ignore a discrepancy between file name and entity name
23575
+ */
23576
+
23431
23577
  /**
23432
23578
  * GOAL commitment definition
23433
23579
  *
@@ -25789,7 +25935,7 @@
25789
25935
  // Add 'web_browser' to tools if not already present
25790
25936
  const updatedTools = existingTools.some((tool) => tool.name === 'web_browser')
25791
25937
  ? existingTools
25792
- : [
25938
+ : ([
25793
25939
  // TODO: [🔰] Use through proper MCP server
25794
25940
  ...existingTools,
25795
25941
  {
@@ -25809,7 +25955,7 @@
25809
25955
  required: ['url'],
25810
25956
  },
25811
25957
  },
25812
- ];
25958
+ ]);
25813
25959
  // Return requirements with updated tools and metadata
25814
25960
  return {
25815
25961
  ...requirements,
@@ -26111,6 +26257,8 @@
26111
26257
  new FormatCommitmentDefinition('FORMAT'),
26112
26258
  new FormatCommitmentDefinition('FORMATS'),
26113
26259
  new FromCommitmentDefinition('FROM'),
26260
+ new ImportCommitmentDefinition('IMPORT'),
26261
+ new ImportCommitmentDefinition('IMPORTS'),
26114
26262
  new ModelCommitmentDefinition('MODEL'),
26115
26263
  new ModelCommitmentDefinition('MODELS'),
26116
26264
  new ActionCommitmentDefinition('ACTION'),