@promptbook/cli 0.112.0-12 → 0.112.0-15

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.
Files changed (77) hide show
  1. package/esm/index.es.js +557 -2337
  2. package/esm/index.es.js.map +1 -1
  3. package/{umd/src/cli/cli-commands/coder/find-fresh-emoji-tag.d.ts → esm/src/cli/cli-commands/coder/find-fresh-emoji-tags.d.ts} +1 -1
  4. package/esm/src/cli/cli-commands/coder.d.ts +1 -1
  5. package/esm/src/commitments/USE_BROWSER/resolveRunBrowserToolForNode.d.ts +1 -1
  6. package/esm/src/commitments/USE_TIMEOUT/TimeoutToolNames.d.ts +1 -0
  7. package/esm/src/commitments/USE_TIMEOUT/TimeoutToolRuntimeAdapter.d.ts +51 -2
  8. package/esm/src/commitments/USE_TIMEOUT/USE_TIMEOUT.d.ts +2 -2
  9. package/esm/src/commitments/USE_TIMEOUT/getTimeoutToolRuntimeAdapterOrDisabledResult.d.ts +2 -2
  10. package/esm/src/commitments/USE_TIMEOUT/parseTimeoutToolArgs.d.ts +14 -1
  11. package/esm/src/execution/createPipelineExecutor/30-executeFormatSubvalues.d.ts +1 -1
  12. package/esm/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  13. package/esm/src/llm-providers/deepseek/deepseek-models.d.ts +1 -1
  14. package/esm/src/llm-providers/google/google-models.d.ts +1 -1
  15. package/esm/src/llm-providers/openai/openai-models.d.ts +1 -1
  16. package/esm/src/scrapers/_boilerplate/BoilerplateScraper.d.ts +1 -2
  17. package/esm/src/scrapers/document/DocumentScraper.d.ts +1 -2
  18. package/esm/src/scrapers/document-legacy/LegacyDocumentScraper.d.ts +1 -2
  19. package/esm/src/scripting/javascript/postprocessing-functions.d.ts +1 -1
  20. package/esm/src/utils/parameters/mapAvailableToExpectedParameters.d.ts +1 -2
  21. package/esm/src/version.d.ts +1 -1
  22. package/package.json +1 -2
  23. package/umd/index.umd.js +771 -2548
  24. package/umd/index.umd.js.map +1 -1
  25. package/{esm/src/cli/cli-commands/coder/find-fresh-emoji-tag.d.ts → umd/src/cli/cli-commands/coder/find-fresh-emoji-tags.d.ts} +1 -1
  26. package/umd/src/cli/cli-commands/coder.d.ts +1 -1
  27. package/umd/src/commitments/USE_BROWSER/resolveRunBrowserToolForNode.d.ts +1 -1
  28. package/umd/src/commitments/USE_TIMEOUT/TimeoutToolNames.d.ts +1 -0
  29. package/umd/src/commitments/USE_TIMEOUT/TimeoutToolRuntimeAdapter.d.ts +51 -2
  30. package/umd/src/commitments/USE_TIMEOUT/USE_TIMEOUT.d.ts +2 -2
  31. package/umd/src/commitments/USE_TIMEOUT/getTimeoutToolRuntimeAdapterOrDisabledResult.d.ts +2 -2
  32. package/umd/src/commitments/USE_TIMEOUT/parseTimeoutToolArgs.d.ts +14 -1
  33. package/umd/src/execution/createPipelineExecutor/30-executeFormatSubvalues.d.ts +1 -1
  34. package/umd/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  35. package/umd/src/llm-providers/deepseek/deepseek-models.d.ts +1 -1
  36. package/umd/src/llm-providers/google/google-models.d.ts +1 -1
  37. package/umd/src/llm-providers/openai/openai-models.d.ts +1 -1
  38. package/umd/src/scrapers/_boilerplate/BoilerplateScraper.d.ts +1 -2
  39. package/umd/src/scrapers/document/DocumentScraper.d.ts +1 -2
  40. package/umd/src/scrapers/document-legacy/LegacyDocumentScraper.d.ts +1 -2
  41. package/umd/src/scripting/javascript/postprocessing-functions.d.ts +1 -1
  42. package/umd/src/utils/parameters/mapAvailableToExpectedParameters.d.ts +1 -2
  43. package/umd/src/version.d.ts +1 -1
  44. package/esm/apps/agents-server/config.d.ts +0 -86
  45. package/esm/apps/agents-server/src/tools/$provideBrowserForServer.d.ts +0 -28
  46. package/esm/apps/agents-server/src/tools/BrowserConnectionProvider.d.ts +0 -142
  47. package/esm/apps/agents-server/src/tools/runBrowserArtifacts.d.ts +0 -25
  48. package/esm/apps/agents-server/src/tools/runBrowserConstants.d.ts +0 -21
  49. package/esm/apps/agents-server/src/tools/runBrowserErrorHandling.d.ts +0 -60
  50. package/esm/apps/agents-server/src/tools/runBrowserErrors.d.ts +0 -73
  51. package/esm/apps/agents-server/src/tools/runBrowserObservability.d.ts +0 -36
  52. package/esm/apps/agents-server/src/tools/runBrowserResultFormatting.d.ts +0 -47
  53. package/esm/apps/agents-server/src/tools/runBrowserRuntime.d.ts +0 -24
  54. package/esm/apps/agents-server/src/tools/runBrowserWorkflow.d.ts +0 -36
  55. package/esm/apps/agents-server/src/tools/run_browser.d.ts +0 -11
  56. package/esm/apps/agents-server/src/utils/retryWithBackoff.d.ts +0 -95
  57. package/esm/apps/agents-server/src/utils/runBrowserArtifactStorage.d.ts +0 -26
  58. package/umd/apps/agents-server/config.d.ts +0 -86
  59. package/umd/apps/agents-server/src/tools/$provideBrowserForServer.d.ts +0 -28
  60. package/umd/apps/agents-server/src/tools/BrowserConnectionProvider.d.ts +0 -142
  61. package/umd/apps/agents-server/src/tools/runBrowserArtifacts.d.ts +0 -25
  62. package/umd/apps/agents-server/src/tools/runBrowserConstants.d.ts +0 -21
  63. package/umd/apps/agents-server/src/tools/runBrowserErrorHandling.d.ts +0 -60
  64. package/umd/apps/agents-server/src/tools/runBrowserErrors.d.ts +0 -73
  65. package/umd/apps/agents-server/src/tools/runBrowserObservability.d.ts +0 -36
  66. package/umd/apps/agents-server/src/tools/runBrowserResultFormatting.d.ts +0 -47
  67. package/umd/apps/agents-server/src/tools/runBrowserRuntime.d.ts +0 -24
  68. package/umd/apps/agents-server/src/tools/runBrowserWorkflow.d.ts +0 -36
  69. package/umd/apps/agents-server/src/tools/run_browser.d.ts +0 -11
  70. package/umd/apps/agents-server/src/utils/retryWithBackoff.d.ts +0 -95
  71. package/umd/apps/agents-server/src/utils/runBrowserArtifactStorage.d.ts +0 -26
  72. /package/esm/scripts/{find-fresh-emoji-tag/find-fresh-emoji-tag.d.ts → find-fresh-emoji-tags/find-fresh-emoji-tags.d.ts} +0 -0
  73. /package/esm/scripts/{find-fresh-emoji-tag → find-fresh-emoji-tags}/utils/$shuffleItems.d.ts +0 -0
  74. /package/esm/scripts/{find-fresh-emoji-tag → find-fresh-emoji-tags}/utils/emojis.d.ts +0 -0
  75. /package/umd/scripts/{find-fresh-emoji-tag/find-fresh-emoji-tag.d.ts → find-fresh-emoji-tags/find-fresh-emoji-tags.d.ts} +0 -0
  76. /package/umd/scripts/{find-fresh-emoji-tag → find-fresh-emoji-tags}/utils/$shuffleItems.d.ts +0 -0
  77. /package/umd/scripts/{find-fresh-emoji-tag → find-fresh-emoji-tags}/utils/emojis.d.ts +0 -0
package/esm/index.es.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import colors from 'colors';
2
2
  import commander from 'commander';
3
- import spaceTrim$2, { spaceTrim as spaceTrim$1 } from 'spacetrim';
3
+ import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
4
4
  import * as fs from 'fs';
5
5
  import { writeFileSync, readFileSync, existsSync } from 'fs';
6
6
  import * as path from 'path';
@@ -14,13 +14,10 @@ import sha256 from 'crypto-js/sha256';
14
14
  import { io } from 'socket.io-client';
15
15
  import { SHA256 } from 'crypto-js';
16
16
  import JSZip from 'jszip';
17
- import { randomBytes, randomUUID, createHash } from 'crypto';
17
+ import { randomBytes, createHash } from 'crypto';
18
18
  import { Readability } from '@mozilla/readability';
19
19
  import { JSDOM } from 'jsdom';
20
20
  import { Converter } from 'showdown';
21
- import { tmpdir } from 'os';
22
- import { ConfigChecker } from 'configchecker';
23
- import { chromium } from 'playwright';
24
21
  import glob from 'glob-promise';
25
22
  import moment from 'moment';
26
23
  import express from 'express';
@@ -60,7 +57,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
60
57
  * @generated
61
58
  * @see https://github.com/webgptorg/promptbook
62
59
  */
63
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-12';
60
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-15';
64
61
  /**
65
62
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
66
63
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -1428,7 +1425,7 @@ function $isRunningInWebWorker() {
1428
1425
  function getErrorReportUrl(error) {
1429
1426
  const report = {
1430
1427
  title: `🐜 Error report from ${NAME}`,
1431
- body: spaceTrim$2((block) => `
1428
+ body: spaceTrim$1((block) => `
1432
1429
 
1433
1430
 
1434
1431
  \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
@@ -1567,7 +1564,7 @@ function handleActionErrors(action) {
1567
1564
  */
1568
1565
  function $initializeAboutCommand(program) {
1569
1566
  const makeCommand = program.command('about');
1570
- makeCommand.description(spaceTrim$2(`
1567
+ makeCommand.description(spaceTrim$1(`
1571
1568
  Tells about Promptbook CLI and its abilities
1572
1569
  `));
1573
1570
  makeCommand.action(handleActionErrors(async () => {
@@ -1607,15 +1604,15 @@ function $initializeAboutCommand(program) {
1607
1604
  */
1608
1605
 
1609
1606
  /**
1610
- * Initializes `coder find-fresh-emoji-tag` command for Promptbook CLI utilities
1607
+ * Initializes `coder find-fresh-emoji-tags` command for Promptbook CLI utilities
1611
1608
  *
1612
1609
  * Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI
1613
1610
  *
1614
1611
  * @private internal function of `promptbookCli`
1615
1612
  */
1616
1613
  function $initializeCoderFindFreshEmojiTagCommand(program) {
1617
- const command = program.command('find-fresh-emoji-tag');
1618
- command.description(spaceTrim$2(`
1614
+ const command = program.command('find-fresh-emoji-tags');
1615
+ command.description(_spaceTrim(`
1619
1616
  Find unused emoji tags in the codebase
1620
1617
 
1621
1618
  Scans entire codebase for emoji tags already in use (format: [emoji])
@@ -1624,7 +1621,7 @@ function $initializeCoderFindFreshEmojiTagCommand(program) {
1624
1621
  `));
1625
1622
  command.action(handleActionErrors(async () => {
1626
1623
  // Note: Import the function dynamically to avoid loading heavy dependencies until needed
1627
- const { findFreshEmojiTag } = await Promise.resolve().then(function () { return findFreshEmojiTag$1; });
1624
+ const { findFreshEmojiTag } = await Promise.resolve().then(function () { return findFreshEmojiTags; });
1628
1625
  try {
1629
1626
  await findFreshEmojiTag();
1630
1627
  }
@@ -1649,7 +1646,7 @@ function $initializeCoderFindFreshEmojiTagCommand(program) {
1649
1646
  */
1650
1647
  function $initializeCoderFindRefactorCandidatesCommand(program) {
1651
1648
  const command = program.command('find-refactor-candidates');
1652
- command.description(spaceTrim$2(`
1649
+ command.description(spaceTrim$1(`
1653
1650
  Scan source files to identify refactoring candidates
1654
1651
 
1655
1652
  Flags files that exceed:
@@ -1839,7 +1836,7 @@ function buildPromptSlug$1(template, title) {
1839
1836
  */
1840
1837
  function $initializeCoderRunCommand(program) {
1841
1838
  const command = program.command('run');
1842
- command.description(spaceTrim$2(`
1839
+ command.description(spaceTrim$1(`
1843
1840
  Execute coding prompts through selected AI agent
1844
1841
 
1845
1842
  Runners:
@@ -1857,7 +1854,7 @@ function $initializeCoderRunCommand(program) {
1857
1854
  `));
1858
1855
  command.option('--dry-run', 'Print unwritten prompts without executing', false);
1859
1856
  command.option('--agent <agent-name>', 'Select runner: openai-codex, cline, claude-code, opencode, gemini (required for non-dry-run)');
1860
- command.option('--model <model>', spaceTrim$2(`
1857
+ command.option('--model <model>', spaceTrim$1(`
1861
1858
  Model to use (required for openai-codex and gemini)
1862
1859
 
1863
1860
  OpenAI examples: gpt-5.2-codex, default
@@ -1945,7 +1942,7 @@ function parseIntOption(value) {
1945
1942
  */
1946
1943
  function $initializeCoderVerifyCommand(program) {
1947
1944
  const command = program.command('verify');
1948
- command.description(spaceTrim$2(`
1945
+ command.description(spaceTrim$1(`
1949
1946
  Interactive verification helper for completed prompts
1950
1947
 
1951
1948
  Features:
@@ -1983,7 +1980,7 @@ function $initializeCoderVerifyCommand(program) {
1983
1980
  * - find-refactor-candidates: Find files that need refactoring
1984
1981
  * - run: Run coding prompts with AI agents
1985
1982
  * - verify: Verify completed prompts
1986
- * - find-fresh-emoji-tag: Find unused emoji tags
1983
+ * - find-fresh-emoji-tags: Find unused emoji tags
1987
1984
  *
1988
1985
  * Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI
1989
1986
  *
@@ -1991,7 +1988,7 @@ function $initializeCoderVerifyCommand(program) {
1991
1988
  */
1992
1989
  function $initializeCoderCommand(program) {
1993
1990
  const coderCommand = program.command('coder');
1994
- coderCommand.description(spaceTrim$2(`
1991
+ coderCommand.description(spaceTrim$1(`
1995
1992
  Coding utilities for automated development workflows
1996
1993
 
1997
1994
  Subcommands:
@@ -1999,7 +1996,7 @@ function $initializeCoderCommand(program) {
1999
1996
  - find-refactor-candidates: Find files that need refactoring
2000
1997
  - run: Run coding prompts with AI agents
2001
1998
  - verify: Verify completed prompts
2002
- - find-fresh-emoji-tag: Find unused emoji tags
1999
+ - find-fresh-emoji-tags: Find unused emoji tags
2003
2000
  `));
2004
2001
  // Register all subcommands
2005
2002
  $initializeCoderGenerateBoilerplatesCommand(coderCommand);
@@ -2028,7 +2025,7 @@ function $initializeCoderCommand(program) {
2028
2025
  */
2029
2026
  function $initializeHelloCommand(program) {
2030
2027
  const helloCommand = program.command('hello');
2031
- helloCommand.description(spaceTrim$2(`
2028
+ helloCommand.description(spaceTrim$1(`
2032
2029
  Just command for testing
2033
2030
  `));
2034
2031
  helloCommand.alias('hi');
@@ -2290,13 +2287,13 @@ function $registeredLlmToolsMessage() {
2290
2287
  });
2291
2288
  const usedEnvMessage = $usedEnvFilename === null ? `Unknown \`.env\` file` : `Used \`.env\` file:\n${$usedEnvFilename}`;
2292
2289
  if (metadata.length === 0) {
2293
- return spaceTrim$2((block) => `
2290
+ return spaceTrim$1((block) => `
2294
2291
  No LLM providers are available.
2295
2292
 
2296
2293
  ${block(usedEnvMessage)}
2297
2294
  `);
2298
2295
  }
2299
- return spaceTrim$2((block) => `
2296
+ return spaceTrim$1((block) => `
2300
2297
 
2301
2298
  ${block(usedEnvMessage)}
2302
2299
 
@@ -2342,7 +2339,7 @@ function $registeredLlmToolsMessage() {
2342
2339
  morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
2343
2340
  }
2344
2341
  }
2345
- let providerMessage = spaceTrim$2(`
2342
+ let providerMessage = spaceTrim$1(`
2346
2343
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
2347
2344
  ${morePieces.join('; ')}
2348
2345
  `);
@@ -2408,7 +2405,7 @@ function jsonParse(value) {
2408
2405
  }
2409
2406
  else if (typeof value !== 'string') {
2410
2407
  console.error('Can not parse JSON from non-string value.', { text: value });
2411
- throw new Error(spaceTrim$2(`
2408
+ throw new Error(spaceTrim$1(`
2412
2409
  Can not parse JSON from non-string value.
2413
2410
 
2414
2411
  The value type: ${typeof value}
@@ -2422,7 +2419,7 @@ function jsonParse(value) {
2422
2419
  if (!(error instanceof Error)) {
2423
2420
  throw error;
2424
2421
  }
2425
- throw new Error(spaceTrim$2((block) => `
2422
+ throw new Error(spaceTrim$1((block) => `
2426
2423
  ${block(error.message)}
2427
2424
 
2428
2425
  The expected JSON text:
@@ -2644,7 +2641,7 @@ class $EnvStorage {
2644
2641
  .filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
2645
2642
  .filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
2646
2643
  .join('\n');
2647
- const newEnvContent = spaceTrim$2((block) => `
2644
+ const newEnvContent = spaceTrim$1((block) => `
2648
2645
  ${block(updatedEnvContent)}
2649
2646
 
2650
2647
  # ${GENERATOR_WARNING_IN_ENV}
@@ -2755,7 +2752,7 @@ function checkSerializableAsJson(options) {
2755
2752
  }
2756
2753
  else if (typeof value === 'object') {
2757
2754
  if (value instanceof Date) {
2758
- throw new UnexpectedError(spaceTrim$2((block) => `
2755
+ throw new UnexpectedError(spaceTrim$1((block) => `
2759
2756
  \`${name}\` is Date
2760
2757
 
2761
2758
  Use \`string_date_iso8601\` instead
@@ -2774,7 +2771,7 @@ function checkSerializableAsJson(options) {
2774
2771
  throw new UnexpectedError(`${name} is RegExp`);
2775
2772
  }
2776
2773
  else if (value instanceof Error) {
2777
- throw new UnexpectedError(spaceTrim$2((block) => `
2774
+ throw new UnexpectedError(spaceTrim$1((block) => `
2778
2775
  \`${name}\` is unserialized Error
2779
2776
 
2780
2777
  Use function \`serializeError\`
@@ -2797,7 +2794,7 @@ function checkSerializableAsJson(options) {
2797
2794
  }
2798
2795
  catch (error) {
2799
2796
  assertsError(error);
2800
- throw new UnexpectedError(spaceTrim$2((block) => `
2797
+ throw new UnexpectedError(spaceTrim$1((block) => `
2801
2798
  \`${name}\` is not serializable
2802
2799
 
2803
2800
  ${block(error.stack || error.message)}
@@ -2829,7 +2826,7 @@ function checkSerializableAsJson(options) {
2829
2826
  }
2830
2827
  }
2831
2828
  else {
2832
- throw new UnexpectedError(spaceTrim$2((block) => `
2829
+ throw new UnexpectedError(spaceTrim$1((block) => `
2833
2830
  \`${name}\` is unknown type
2834
2831
 
2835
2832
  Additional message for \`${name}\`:
@@ -3093,7 +3090,7 @@ function isSerializableAsJson(value) {
3093
3090
  */
3094
3091
  function stringifyPipelineJson(pipeline) {
3095
3092
  if (!isSerializableAsJson(pipeline)) {
3096
- throw new UnexpectedError(spaceTrim$2(`
3093
+ throw new UnexpectedError(spaceTrim$1(`
3097
3094
  Cannot stringify the pipeline, because it is not serializable as JSON
3098
3095
 
3099
3096
  There can be multiple reasons:
@@ -4007,7 +4004,7 @@ function deserializeError(error, isStackAddedToMessage = true) {
4007
4004
  message = `${name}: ${message}`;
4008
4005
  }
4009
4006
  if (isStackAddedToMessage && stack !== undefined && stack !== '') {
4010
- message = spaceTrim$2((block) => `
4007
+ message = spaceTrim$1((block) => `
4011
4008
  ${block(message)}
4012
4009
 
4013
4010
  Original stack trace:
@@ -4034,7 +4031,7 @@ async function createRemoteClient(options) {
4034
4031
  const remoteServerUrlParsed = new URL(remoteServerUrl);
4035
4032
  if (remoteServerUrlParsed.pathname !== '/' && remoteServerUrlParsed.pathname !== '') {
4036
4033
  remoteServerUrlParsed.pathname = '/';
4037
- throw new Error(spaceTrim$2((block) => `
4034
+ throw new Error(spaceTrim$1((block) => `
4038
4035
  Remote server requires root url \`/\`
4039
4036
 
4040
4037
  You have provided \`remoteServerUrl\`:
@@ -4360,7 +4357,7 @@ function serializeError(error) {
4360
4357
  const { name, message, stack } = error;
4361
4358
  const { id } = error;
4362
4359
  if (!Object.keys(ALL_ERRORS).includes(name)) {
4363
- console.error(spaceTrim$2((block) => `
4360
+ console.error(spaceTrim$1((block) => `
4364
4361
 
4365
4362
  Cannot serialize error with name "${name}"
4366
4363
 
@@ -4885,7 +4882,7 @@ function buildParametersSection(items) {
4885
4882
  const entries = items
4886
4883
  .flatMap((item) => formatParameterListItem(item).split(/\r?\n/))
4887
4884
  .filter((line) => line !== '');
4888
- return spaceTrim$2((block) => `
4885
+ return spaceTrim$1((block) => `
4889
4886
  **Parameters:**
4890
4887
  ${block(entries.join('\n'))}
4891
4888
 
@@ -4958,7 +4955,7 @@ function isPromptString(value) {
4958
4955
  */
4959
4956
  function prompt(strings, ...values) {
4960
4957
  if (values.length === 0) {
4961
- return new PromptString(spaceTrim$2(strings.join('')));
4958
+ return new PromptString(spaceTrim$1(strings.join('')));
4962
4959
  }
4963
4960
  const stringsWithHiddenParameters = strings.map((stringsItem) => ParameterEscaping.hideBrackets(stringsItem));
4964
4961
  const parameterMetadata = values.map((value) => {
@@ -4999,7 +4996,7 @@ function prompt(strings, ...values) {
4999
4996
  ? `${result}${stringsItem}`
5000
4997
  : `${result}${stringsItem}${ParameterSection.formatParameterPlaceholder(parameterName)}`;
5001
4998
  }, '');
5002
- pipelineString = spaceTrim$2(pipelineString);
4999
+ pipelineString = spaceTrim$1(pipelineString);
5003
5000
  try {
5004
5001
  pipelineString = templateParameters(pipelineString, parameters);
5005
5002
  }
@@ -5008,7 +5005,7 @@ function prompt(strings, ...values) {
5008
5005
  throw error;
5009
5006
  }
5010
5007
  console.error({ pipelineString, parameters, parameterNames: parameterNamesOrdered, error });
5011
- throw new UnexpectedError(spaceTrim$2((block) => `
5008
+ throw new UnexpectedError(spaceTrim$1((block) => `
5012
5009
  Internal error in prompt template literal
5013
5010
 
5014
5011
  ${block(JSON.stringify({ strings, values }, null, 4))}}
@@ -5231,7 +5228,7 @@ const CountUtils = {
5231
5228
  * @public exported from `@promptbook/utils`
5232
5229
  */
5233
5230
  function computeHash(value) {
5234
- return SHA256(hexEncoder.parse(spaceTrim$2(valueToString(value)))).toString( /* hex */);
5231
+ return SHA256(hexEncoder.parse(spaceTrim$1(valueToString(value)))).toString( /* hex */);
5235
5232
  }
5236
5233
  /**
5237
5234
  * TODO: [🥬][🥬] Use this ACRY
@@ -7517,7 +7514,7 @@ function cacheLlmTools(llmTools, options = {}) {
7517
7514
  let normalizedContent = content;
7518
7515
  normalizedContent = normalizedContent.replace(/\s+/g, ' ');
7519
7516
  normalizedContent = normalizedContent.split('\r\n').join('\n');
7520
- normalizedContent = spaceTrim$2(normalizedContent);
7517
+ normalizedContent = spaceTrim$1(normalizedContent);
7521
7518
  // Note: Do not need to save everything in the cache, just the relevant parameters
7522
7519
  const relevantParameterNames = extractParameterNames(content);
7523
7520
  const relevantParameters = Object.fromEntries(Object.entries(parameters).filter(([key]) => relevantParameterNames.has(key)));
@@ -7987,14 +7984,14 @@ class MultipleLlmExecutionTools {
7987
7984
  if (description === undefined) {
7988
7985
  return headLine;
7989
7986
  }
7990
- return spaceTrim$2((block) => `
7987
+ return spaceTrim$1((block) => `
7991
7988
  ${headLine}
7992
7989
 
7993
7990
  ${ /* <- Note: Indenting the description: */block(description)}
7994
7991
  `);
7995
7992
  })
7996
7993
  .join('\n\n');
7997
- return spaceTrim$2((block) => `
7994
+ return spaceTrim$1((block) => `
7998
7995
  Multiple LLM Providers:
7999
7996
 
8000
7997
  ${block(innerModelsTitlesAndDescriptions)}
@@ -8096,7 +8093,7 @@ class MultipleLlmExecutionTools {
8096
8093
  // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
8097
8094
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
8098
8095
  // 3) ...
8099
- spaceTrim$2((block) => `
8096
+ spaceTrim$1((block) => `
8100
8097
  All execution tools of ${this.title} failed:
8101
8098
 
8102
8099
  ${block(errors
@@ -8109,7 +8106,7 @@ class MultipleLlmExecutionTools {
8109
8106
  throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\` into ${this.title}`);
8110
8107
  }
8111
8108
  else {
8112
- throw new PipelineExecutionError(spaceTrim$2((block) => `
8109
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
8113
8110
  You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}" into ${this.title}
8114
8111
 
8115
8112
  Available \`LlmExecutionTools\`:
@@ -8146,7 +8143,7 @@ class MultipleLlmExecutionTools {
8146
8143
  */
8147
8144
  function joinLlmExecutionTools(title, ...llmExecutionTools) {
8148
8145
  if (llmExecutionTools.length === 0) {
8149
- const warningMessage = spaceTrim$2(`
8146
+ const warningMessage = spaceTrim$1(`
8150
8147
  You have not provided any \`LlmExecutionTools\`
8151
8148
  This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.
8152
8149
 
@@ -8204,7 +8201,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
8204
8201
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
8205
8202
  if (registeredItem === undefined) {
8206
8203
  // console.log('$llmToolsRegister.list()', $llmToolsRegister.list());
8207
- throw new Error(spaceTrim$2((block) => `
8204
+ throw new Error(spaceTrim$1((block) => `
8208
8205
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
8209
8206
  Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
8210
8207
 
@@ -8272,14 +8269,14 @@ async function $provideLlmToolsFromEnv(options = {}) {
8272
8269
  const configuration = await $provideLlmToolsConfigurationFromEnv();
8273
8270
  if (configuration.length === 0) {
8274
8271
  if ($llmToolsMetadataRegister.list().length === 0) {
8275
- throw new UnexpectedError(spaceTrim$2((block) => `
8272
+ throw new UnexpectedError(spaceTrim$1((block) => `
8276
8273
  No LLM tools registered, this is probably a bug in the Promptbook library
8277
8274
 
8278
8275
  ${block($registeredLlmToolsMessage())}}
8279
8276
  `));
8280
8277
  }
8281
8278
  // TODO: [🥃]
8282
- throw new Error(spaceTrim$2((block) => `
8279
+ throw new Error(spaceTrim$1((block) => `
8283
8280
  No LLM tools found in the environment
8284
8281
 
8285
8282
  ${block($registeredLlmToolsMessage())}}
@@ -8389,7 +8386,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
8389
8386
  else if (urlOrRequest instanceof Request) {
8390
8387
  url = urlOrRequest.url;
8391
8388
  }
8392
- throw new PromptbookFetchError(spaceTrim$2((block) => `
8389
+ throw new PromptbookFetchError(spaceTrim$1((block) => `
8393
8390
  Can not fetch "${url}"
8394
8391
 
8395
8392
  Fetch error:
@@ -8443,7 +8440,7 @@ async function $provideLlmToolsForCli(options) {
8443
8440
  console.log(colors.red(`You can not login to remote server in non-interactive mode`));
8444
8441
  process.exit(1);
8445
8442
  }
8446
- console.info(colors.cyan(spaceTrim$2(`
8443
+ console.info(colors.cyan(spaceTrim$1(`
8447
8444
  You will be logged in to ${remoteServerUrl}
8448
8445
  If you don't have an account, it will be created automatically.
8449
8446
  `)));
@@ -8517,7 +8514,7 @@ async function $provideLlmToolsForCli(options) {
8517
8514
  */
8518
8515
  function $initializeListModelsCommand(program) {
8519
8516
  const listModelsCommand = program.command('list-models');
8520
- listModelsCommand.description(spaceTrim$2(`
8517
+ listModelsCommand.description(spaceTrim$1(`
8521
8518
  List all available and configured LLM models
8522
8519
  `));
8523
8520
  listModelsCommand.alias('models');
@@ -9006,14 +9003,14 @@ function $registeredScrapersMessage(availableScrapers) {
9006
9003
  return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
9007
9004
  });
9008
9005
  if (metadata.length === 0) {
9009
- return spaceTrim$2(`
9006
+ return spaceTrim$1(`
9010
9007
  **No scrapers are available**
9011
9008
 
9012
9009
  This is a unexpected behavior, you are probably using some broken version of Promptbook
9013
9010
  At least there should be available the metadata of the scrapers
9014
9011
  `);
9015
9012
  }
9016
- return spaceTrim$2((block) => `
9013
+ return spaceTrim$1((block) => `
9017
9014
  Available scrapers are:
9018
9015
  ${block(metadata
9019
9016
  .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
@@ -9064,7 +9061,7 @@ function $registeredScrapersMessage(availableScrapers) {
9064
9061
  */
9065
9062
  function $initializeListScrapersCommand(program) {
9066
9063
  const listModelsCommand = program.command('list-scrapers');
9067
- listModelsCommand.description(spaceTrim$2(`
9064
+ listModelsCommand.description(spaceTrim$1(`
9068
9065
  List all available and configured scrapers and executables
9069
9066
  `));
9070
9067
  listModelsCommand.alias('scrapers');
@@ -9072,7 +9069,7 @@ function $initializeListScrapersCommand(program) {
9072
9069
  // TODO: [🌞] Do not allow on REMOTE_SERVER strategy
9073
9070
  const scrapers = await $provideScrapersForNode({});
9074
9071
  const executables = await $provideExecutablesForNode();
9075
- console.info(spaceTrim$2((block) => `
9072
+ console.info(spaceTrim$1((block) => `
9076
9073
  ${block($registeredScrapersMessage(scrapers))}
9077
9074
 
9078
9075
  All mime-types which can be scraped:
@@ -9102,7 +9099,7 @@ function $initializeListScrapersCommand(program) {
9102
9099
  */
9103
9100
  function $initializeLoginCommand(program) {
9104
9101
  const loginCommand = program.command('login');
9105
- loginCommand.description(spaceTrim$2(`
9102
+ loginCommand.description(spaceTrim$1(`
9106
9103
  Login to the remote Promptbook server
9107
9104
  `));
9108
9105
  loginCommand.action(handleActionErrors(async (cliOptions) => {
@@ -9602,7 +9599,7 @@ function pipelineJsonToString(pipelineJson) {
9602
9599
  pipelineString += '\n\n';
9603
9600
  pipelineString += '```' + contentLanguage;
9604
9601
  pipelineString += '\n';
9605
- pipelineString += spaceTrim$2(content);
9602
+ pipelineString += spaceTrim$1(content);
9606
9603
  // <- TODO: [main] !!3 Escape
9607
9604
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
9608
9605
  pipelineString += '\n';
@@ -10237,7 +10234,7 @@ const CsvFormatParser = {
10237
10234
  const { value, outputParameterName, settings, mapCallback, onProgress } = options;
10238
10235
  const csv = csvParse(value, settings);
10239
10236
  if (csv.errors.length !== 0) {
10240
- throw new CsvFormatError(spaceTrim$2((block) => `
10237
+ throw new CsvFormatError(spaceTrim$1((block) => `
10241
10238
  CSV parsing error
10242
10239
 
10243
10240
  Error(s) from CSV parsing:
@@ -10282,7 +10279,7 @@ const CsvFormatParser = {
10282
10279
  const { value, settings, mapCallback, onProgress } = options;
10283
10280
  const csv = csvParse(value, settings);
10284
10281
  if (csv.errors.length !== 0) {
10285
- throw new CsvFormatError(spaceTrim$2((block) => `
10282
+ throw new CsvFormatError(spaceTrim$1((block) => `
10286
10283
  CSV parsing error
10287
10284
 
10288
10285
  Error(s) from CSV parsing:
@@ -10468,7 +10465,7 @@ function mapAvailableToExpectedParameters(options) {
10468
10465
  }
10469
10466
  // Phase 2️⃣: Non-matching mapping
10470
10467
  if (expectedParameterNames.size !== availableParametersNames.size) {
10471
- throw new PipelineExecutionError(spaceTrim$2((block) => `
10468
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
10472
10469
  Can not map available parameters to expected parameters
10473
10470
 
10474
10471
  Mapped parameters:
@@ -10883,7 +10880,7 @@ async function executeFormatSubvalues(options) {
10883
10880
  return /* not await */ executeAttempts({ ...options, logLlmCall });
10884
10881
  }
10885
10882
  if (jokerParameterNames.length !== 0) {
10886
- throw new UnexpectedError(spaceTrim$2((block) => `
10883
+ throw new UnexpectedError(spaceTrim$1((block) => `
10887
10884
  JOKER parameters are not supported together with FOREACH command
10888
10885
 
10889
10886
  [🧞‍♀️] This should be prevented in \`validatePipeline\`
@@ -10896,7 +10893,7 @@ async function executeFormatSubvalues(options) {
10896
10893
  if (formatDefinition === undefined) {
10897
10894
  throw new UnexpectedError(
10898
10895
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
10899
- spaceTrim$2((block) => `
10896
+ spaceTrim$1((block) => `
10900
10897
  Unsupported format "${task.foreach.formatName}"
10901
10898
 
10902
10899
  Available formats:
@@ -10913,7 +10910,7 @@ async function executeFormatSubvalues(options) {
10913
10910
  if (subvalueParser === undefined) {
10914
10911
  throw new UnexpectedError(
10915
10912
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
10916
- spaceTrim$2((block) => `
10913
+ spaceTrim$1((block) => `
10917
10914
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
10918
10915
 
10919
10916
  Available subformat names for format "${formatDefinition.formatName}":
@@ -10953,7 +10950,7 @@ async function executeFormatSubvalues(options) {
10953
10950
  if (!(error instanceof PipelineExecutionError)) {
10954
10951
  throw error;
10955
10952
  }
10956
- const highLevelError = new PipelineExecutionError(spaceTrim$2((block) => `
10953
+ const highLevelError = new PipelineExecutionError(spaceTrim$1((block) => `
10957
10954
  ${error.message}
10958
10955
 
10959
10956
  This is error in FOREACH command when mapping ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -10977,7 +10974,7 @@ async function executeFormatSubvalues(options) {
10977
10974
  ...options,
10978
10975
  priority: priority + index,
10979
10976
  parameters: allSubparameters,
10980
- pipelineIdentification: spaceTrim$2((block) => `
10977
+ pipelineIdentification: spaceTrim$1((block) => `
10981
10978
  ${block(pipelineIdentification)}
10982
10979
  Subparameter index: ${index}
10983
10980
  `),
@@ -10986,7 +10983,7 @@ async function executeFormatSubvalues(options) {
10986
10983
  }
10987
10984
  catch (error) {
10988
10985
  if (length > BIG_DATASET_TRESHOLD) {
10989
- console.error(spaceTrim$2((block) => `
10986
+ console.error(spaceTrim$1((block) => `
10990
10987
  ${error.message}
10991
10988
 
10992
10989
  This is error in FOREACH command when processing ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -12030,7 +12027,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
12030
12027
  const fileExtension = getFileExtension(filename);
12031
12028
  const mimeType = extensionToMimeType(fileExtension || '');
12032
12029
  if (!(await isFileExisting(filename, tools.fs))) {
12033
- throw new NotFoundError(spaceTrim$2((block) => `
12030
+ throw new NotFoundError(spaceTrim$1((block) => `
12034
12031
  Can not make source handler for file which does not exist:
12035
12032
 
12036
12033
  File:
@@ -12123,7 +12120,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
12123
12120
  // <- TODO: [🪓] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
12124
12121
  break;
12125
12122
  }
12126
- console.warn(spaceTrim$2((block) => `
12123
+ console.warn(spaceTrim$1((block) => `
12127
12124
  Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
12128
12125
 
12129
12126
  The source:
@@ -12139,7 +12136,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
12139
12136
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
12140
12137
  }
12141
12138
  if (partialPieces === null) {
12142
- throw new KnowledgeScrapeError(spaceTrim$2((block) => `
12139
+ throw new KnowledgeScrapeError(spaceTrim$1((block) => `
12143
12140
  Cannot scrape knowledge
12144
12141
 
12145
12142
  The source:
@@ -12475,7 +12472,7 @@ const knowledgeCommandParser = {
12475
12472
  */
12476
12473
  parse(input) {
12477
12474
  const { args } = input;
12478
- const knowledgeSourceContent = spaceTrim$2(args[0] || '');
12475
+ const knowledgeSourceContent = spaceTrim$1(args[0] || '');
12479
12476
  if (knowledgeSourceContent === '') {
12480
12477
  throw new ParseError(`Source is not defined`);
12481
12478
  }
@@ -12619,7 +12616,7 @@ const sectionCommandParser = {
12619
12616
  normalized = normalized.split('DIALOGUE').join('DIALOG');
12620
12617
  const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
12621
12618
  if (taskTypes.length !== 1) {
12622
- throw new ParseError(spaceTrim$2((block) => `
12619
+ throw new ParseError(spaceTrim$1((block) => `
12623
12620
  Unknown section type "${normalized}"
12624
12621
 
12625
12622
  Supported section types are:
@@ -12639,7 +12636,7 @@ const sectionCommandParser = {
12639
12636
  */
12640
12637
  $applyToTaskJson(command, $taskJson, $pipelineJson) {
12641
12638
  if ($taskJson.isSectionTypeSet === true) {
12642
- throw new ParseError(spaceTrim$2(`
12639
+ throw new ParseError(spaceTrim$1(`
12643
12640
  Section type is already defined in the section.
12644
12641
  It can be defined only once.
12645
12642
  `));
@@ -12919,7 +12916,7 @@ const expectCommandParser = {
12919
12916
  /**
12920
12917
  * Description of the FORMAT command
12921
12918
  */
12922
- description: spaceTrim$2(`
12919
+ description: spaceTrim$1(`
12923
12920
  Expect command describes the desired output of the task *(after post-processing)*
12924
12921
  It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.
12925
12922
  `),
@@ -12993,7 +12990,7 @@ const expectCommandParser = {
12993
12990
  }
12994
12991
  catch (error) {
12995
12992
  assertsError(error);
12996
- throw new ParseError(spaceTrim$2((block) => `
12993
+ throw new ParseError(spaceTrim$1((block) => `
12997
12994
  Invalid FORMAT command
12998
12995
  ${block(error.message)}:
12999
12996
  `));
@@ -13105,7 +13102,7 @@ function validateParameterName(parameterName) {
13105
13102
  if (!(error instanceof ParseError)) {
13106
13103
  throw error;
13107
13104
  }
13108
- throw new ParseError(spaceTrim$2((block) => `
13105
+ throw new ParseError(spaceTrim$1((block) => `
13109
13106
  ${block(error.message)}
13110
13107
 
13111
13108
  Tried to validate parameter name:
@@ -13164,7 +13161,7 @@ const foreachCommandParser = {
13164
13161
  const assignSign = args[3];
13165
13162
  const formatDefinition = FORMAT_DEFINITIONS.find((formatDefinition) => [formatDefinition.formatName, ...(formatDefinition.aliases || [])].includes(formatName));
13166
13163
  if (formatDefinition === undefined) {
13167
- throw new ParseError(spaceTrim$2((block) => `
13164
+ throw new ParseError(spaceTrim$1((block) => `
13168
13165
  Unsupported format "${formatName}"
13169
13166
 
13170
13167
  Available formats:
@@ -13176,7 +13173,7 @@ const foreachCommandParser = {
13176
13173
  }
13177
13174
  const subvalueParser = formatDefinition.subvalueParsers.find((subvalueParser) => [subvalueParser.subvalueName, ...(subvalueParser.aliases || [])].includes(subformatName));
13178
13175
  if (subvalueParser === undefined) {
13179
- throw new ParseError(spaceTrim$2((block) => `
13176
+ throw new ParseError(spaceTrim$1((block) => `
13180
13177
  Unsupported subformat name "${subformatName}" for format "${formatName}"
13181
13178
 
13182
13179
  Available subformat names for format "${formatDefinition.formatName}":
@@ -13224,7 +13221,7 @@ const foreachCommandParser = {
13224
13221
  outputSubparameterName = 'newLine';
13225
13222
  }
13226
13223
  else {
13227
- throw new ParseError(spaceTrim$2(`
13224
+ throw new ParseError(spaceTrim$1(`
13228
13225
  FOREACH ${formatName} ${subformatName} must specify output subparameter
13229
13226
 
13230
13227
  Correct example:
@@ -13300,7 +13297,7 @@ const formatCommandParser = {
13300
13297
  /**
13301
13298
  * Description of the FORMAT command
13302
13299
  */
13303
- description: spaceTrim$2(`
13300
+ description: spaceTrim$1(`
13304
13301
  Format command describes the desired output of the task (after post-processing)
13305
13302
  It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.
13306
13303
  `),
@@ -13672,7 +13669,7 @@ const formfactorCommandParser = {
13672
13669
  const formfactorNameCandidate = args[0].toUpperCase();
13673
13670
  const formfactor = FORMFACTOR_DEFINITIONS.find((definition) => [definition.name, ...{ aliasNames: [], ...definition }.aliasNames].includes(formfactorNameCandidate));
13674
13671
  if (formfactor === undefined) {
13675
- throw new ParseError(spaceTrim$2((block) => `
13672
+ throw new ParseError(spaceTrim$1((block) => `
13676
13673
  Unknown formfactor name "${formfactorNameCandidate}"
13677
13674
 
13678
13675
  Available formfactors:
@@ -13691,7 +13688,7 @@ const formfactorCommandParser = {
13691
13688
  */
13692
13689
  $applyToPipelineJson(command, $pipelineJson) {
13693
13690
  if ($pipelineJson.formfactorName !== undefined && $pipelineJson.formfactorName !== command.formfactorName) {
13694
- throw new ParseError(spaceTrim$2(`
13691
+ throw new ParseError(spaceTrim$1(`
13695
13692
  Redefinition of \`FORMFACTOR\` in the pipeline head
13696
13693
 
13697
13694
  You have used:
@@ -13839,7 +13836,7 @@ const modelCommandParser = {
13839
13836
  */
13840
13837
  parse(input) {
13841
13838
  const { args, normalized } = input;
13842
- const availableVariantsMessage = spaceTrim$2((block) => `
13839
+ const availableVariantsMessage = spaceTrim$1((block) => `
13843
13840
  Available variants are:
13844
13841
  ${block(MODEL_VARIANTS.map((variantName) => `- ${variantName}${variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)'}`).join('\n'))}
13845
13842
  `);
@@ -13861,14 +13858,14 @@ const modelCommandParser = {
13861
13858
  // <- Note: [🤖]
13862
13859
  }
13863
13860
  else if (normalized.startsWith('MODEL_VARIANT_EMBED')) {
13864
- spaceTrim$2((block) => `
13861
+ spaceTrim$1((block) => `
13865
13862
  Embedding model can not be used in pipeline
13866
13863
 
13867
13864
  ${block(availableVariantsMessage)}
13868
13865
  `);
13869
13866
  }
13870
13867
  else {
13871
- throw new ParseError(spaceTrim$2((block) => `
13868
+ throw new ParseError(spaceTrim$1((block) => `
13872
13869
  Unknown model variant in command:
13873
13870
 
13874
13871
  ${block(availableVariantsMessage)}
@@ -13883,7 +13880,7 @@ const modelCommandParser = {
13883
13880
  };
13884
13881
  }
13885
13882
  else {
13886
- throw new ParseError(spaceTrim$2((block) => `
13883
+ throw new ParseError(spaceTrim$1((block) => `
13887
13884
  Unknown model key in command.
13888
13885
 
13889
13886
  Supported model keys are:
@@ -13910,7 +13907,7 @@ const modelCommandParser = {
13910
13907
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
13911
13908
  }
13912
13909
  else {
13913
- throw new ParseError(spaceTrim$2(`
13910
+ throw new ParseError(spaceTrim$1(`
13914
13911
  Redefinition of \`MODEL ${command.key}\` in the pipeline head
13915
13912
 
13916
13913
  You have used:
@@ -13938,7 +13935,7 @@ const modelCommandParser = {
13938
13935
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
13939
13936
  }
13940
13937
  else {
13941
- throw new ParseError(spaceTrim$2(`
13938
+ throw new ParseError(spaceTrim$1(`
13942
13939
  Redefinition of MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}"
13943
13940
 
13944
13941
  You have used:
@@ -13948,7 +13945,7 @@ const modelCommandParser = {
13948
13945
  }
13949
13946
  }
13950
13947
  if (command.value === ($pipelineJson.defaultModelRequirements || {})[command.key]) {
13951
- console.log(spaceTrim$2(`
13948
+ console.log(spaceTrim$1(`
13952
13949
  Setting MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}" to the same value as in the pipeline head
13953
13950
 
13954
13951
  In pipeline head:
@@ -14031,7 +14028,7 @@ const parameterCommandParser = {
14031
14028
  // <- TODO: When [🥶] fixed, change to:
14032
14029
  // > const parameterDescriptionRaw = rawArgs.split(parameterNameRaw).join('').trim();
14033
14030
  if (parameterDescriptionRaw && parameterDescriptionRaw.match(/\{(?<embeddedParameterName>[a-z0-9_]+)\}/im)) {
14034
- throw new ParseError(spaceTrim$2((block) => `
14031
+ throw new ParseError(spaceTrim$1((block) => `
14035
14032
  Parameter \`{${parameterNameRaw}}\` can not contain another parameter in description
14036
14033
 
14037
14034
  The description:
@@ -14213,7 +14210,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
14213
14210
  persona.description = personaDescription;
14214
14211
  return;
14215
14212
  }
14216
- console.warn(spaceTrim$2(`
14213
+ console.warn(spaceTrim$1(`
14217
14214
 
14218
14215
  Persona "${personaName}" is defined multiple times with different description:
14219
14216
 
@@ -14224,7 +14221,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
14224
14221
  ${personaDescription}
14225
14222
 
14226
14223
  `));
14227
- persona.description += spaceTrim$2('\n\n' + personaDescription);
14224
+ persona.description += spaceTrim$1('\n\n' + personaDescription);
14228
14225
  }
14229
14226
 
14230
14227
  /**
@@ -15065,7 +15062,7 @@ function removeMarkdownComments(content) {
15065
15062
  */
15066
15063
  function isFlatPipeline(pipelineString) {
15067
15064
  pipelineString = removeMarkdownComments(pipelineString);
15068
- pipelineString = spaceTrim$2(pipelineString);
15065
+ pipelineString = spaceTrim$1(pipelineString);
15069
15066
  const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
15070
15067
  //const isLastLineReturnStatement = pipelineString.split(/\r?\n/).pop()!.split('`').join('').startsWith('->');
15071
15068
  const isBacktickBlockUsed = pipelineString.includes('```');
@@ -15091,7 +15088,7 @@ function deflatePipeline(pipelineString) {
15091
15088
  if (!isFlatPipeline(pipelineString)) {
15092
15089
  return pipelineString;
15093
15090
  }
15094
- pipelineString = spaceTrim$2(pipelineString);
15091
+ pipelineString = spaceTrim$1(pipelineString);
15095
15092
  const pipelineStringLines = pipelineString.split(/\r?\n/);
15096
15093
  const potentialReturnStatement = pipelineStringLines.pop();
15097
15094
  let returnStatement;
@@ -15104,19 +15101,19 @@ function deflatePipeline(pipelineString) {
15104
15101
  returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
15105
15102
  pipelineStringLines.push(potentialReturnStatement);
15106
15103
  }
15107
- const prompt = spaceTrim$2(pipelineStringLines.join('\n'));
15104
+ const prompt = spaceTrim$1(pipelineStringLines.join('\n'));
15108
15105
  let quotedPrompt;
15109
15106
  if (prompt.split(/\r?\n/).length <= 1) {
15110
15107
  quotedPrompt = `> ${prompt}`;
15111
15108
  }
15112
15109
  else {
15113
- quotedPrompt = spaceTrim$2((block) => `
15110
+ quotedPrompt = spaceTrim$1((block) => `
15114
15111
  \`\`\`
15115
15112
  ${block(prompt.split('`').join('\\`'))}
15116
15113
  \`\`\`
15117
15114
  `);
15118
15115
  }
15119
- pipelineString = validatePipelineString(spaceTrim$2((block) => `
15116
+ pipelineString = validatePipelineString(spaceTrim$1((block) => `
15120
15117
  # ${DEFAULT_BOOK_TITLE}
15121
15118
 
15122
15119
  ## Prompt
@@ -15180,7 +15177,7 @@ function extractAllListItemsFromMarkdown(markdown) {
15180
15177
  function extractOneBlockFromMarkdown(markdown) {
15181
15178
  const codeBlocks = extractAllBlocksFromMarkdown(markdown);
15182
15179
  if (codeBlocks.length !== 1) {
15183
- throw new ParseError(spaceTrim$2((block) => `
15180
+ throw new ParseError(spaceTrim$1((block) => `
15184
15181
  There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
15185
15182
 
15186
15183
  ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
@@ -15205,7 +15202,7 @@ function parseMarkdownSection(value) {
15205
15202
  }
15206
15203
  const title = lines[0].replace(/^#+\s*/, '');
15207
15204
  const level = (_b = (_a = lines[0].match(/^#+/)) === null || _a === void 0 ? void 0 : _a[0].length) !== null && _b !== void 0 ? _b : 0;
15208
- const content = spaceTrim$2(lines.slice(1).join('\n'));
15205
+ const content = spaceTrim$1(lines.slice(1).join('\n'));
15209
15206
  if (level < 1 || level > 6) {
15210
15207
  throw new ParseError('Markdown section must have heading level between 1 and 6');
15211
15208
  }
@@ -15233,7 +15230,7 @@ function splitMarkdownIntoSections(markdown) {
15233
15230
  if (buffer.length === 0) {
15234
15231
  return;
15235
15232
  }
15236
- let section = spaceTrim$2(buffer.join('\n'));
15233
+ let section = spaceTrim$1(buffer.join('\n'));
15237
15234
  if (section === '') {
15238
15235
  return;
15239
15236
  }
@@ -15308,7 +15305,7 @@ function flattenMarkdown(markdown) {
15308
15305
  flattenedMarkdown += `## ${title}` + `\n\n`;
15309
15306
  flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
15310
15307
  }
15311
- return spaceTrim$2(flattenedMarkdown);
15308
+ return spaceTrim$1(flattenedMarkdown);
15312
15309
  }
15313
15310
  /**
15314
15311
  * TODO: [🏛] This can be part of markdown builder
@@ -15959,8 +15956,8 @@ class MarkdownScraper {
15959
15956
  knowledgeTextPieces.map(async (knowledgeTextPiece, i) => {
15960
15957
  // Note: These are just default values, they will be overwritten by the actual values:
15961
15958
  let name = `piece-${i}`;
15962
- let title = spaceTrim$2(knowledgeTextPiece.substring(0, 100));
15963
- const knowledgePieceContent = spaceTrim$2(knowledgeTextPiece);
15959
+ let title = spaceTrim$1(knowledgeTextPiece.substring(0, 100));
15960
+ const knowledgePieceContent = spaceTrim$1(knowledgeTextPiece);
15964
15961
  let keywords = [];
15965
15962
  const index = [];
15966
15963
  /*
@@ -15973,7 +15970,7 @@ class MarkdownScraper {
15973
15970
  isCrashedOnError: true,
15974
15971
  });
15975
15972
  const { title: titleRaw = 'Untitled' } = titleResult.outputParameters;
15976
- title = spaceTrim$2(titleRaw) /* <- TODO: Maybe do in pipeline */;
15973
+ title = spaceTrim$1(titleRaw) /* <- TODO: Maybe do in pipeline */;
15977
15974
  name = titleToName(title);
15978
15975
  // --- Keywords
15979
15976
  const keywordsResult = await prepareKeywordsExecutor({ knowledgePieceContent }).asPromise({
@@ -16326,2071 +16323,61 @@ async function fetchUrlContent(url) {
16326
16323
  */
16327
16324
 
16328
16325
  /**
16329
- * Prompt parameter key used to pass hidden runtime context to tool execution.
16330
- *
16331
- * @private internal runtime wiring for commitment tools
16332
- */
16333
- const TOOL_RUNTIME_CONTEXT_PARAMETER = 'promptbookToolRuntimeContext';
16334
- /**
16335
- * Hidden argument key used to pass runtime context into individual tool calls.
16336
- *
16337
- * @private internal runtime wiring for commitment tools
16338
- */
16339
- const TOOL_RUNTIME_CONTEXT_ARGUMENT = '__promptbookToolRuntimeContext';
16340
- /**
16341
- * Prompt parameter key used to pass a hidden tool-progress listener token into script execution.
16342
- *
16343
- * @private internal runtime wiring for commitment tools
16344
- */
16345
- const TOOL_PROGRESS_TOKEN_PARAMETER = 'promptbookToolProgressToken';
16346
- /**
16347
- * Hidden argument key used to pass a tool-progress listener token into individual tool calls.
16348
- *
16349
- * @private internal runtime wiring for commitment tools
16350
- */
16351
- const TOOL_PROGRESS_TOKEN_ARGUMENT = '__promptbookToolProgressToken';
16352
- /**
16353
- * Monotonic counter used for hidden progress-listener tokens.
16354
- *
16355
- * @private internal runtime wiring for commitment tools
16356
- */
16357
- let toolCallProgressListenerCounter = 0;
16358
- /**
16359
- * Active tool-progress listeners keyed by hidden execution token.
16360
- *
16361
- * @private internal runtime wiring for commitment tools
16362
- */
16363
- const toolCallProgressListeners = new Map();
16364
- /**
16365
- * Parses unknown runtime context payload into a normalized object.
16366
- *
16367
- * @private internal runtime wiring for commitment tools
16368
- */
16369
- function parseToolRuntimeContext(rawValue) {
16370
- if (!rawValue) {
16371
- return null;
16372
- }
16373
- let parsed = rawValue;
16374
- if (typeof rawValue === 'string') {
16375
- try {
16376
- parsed = JSON.parse(rawValue);
16377
- }
16378
- catch (_a) {
16379
- return null;
16380
- }
16381
- }
16382
- if (!parsed || typeof parsed !== 'object') {
16383
- return null;
16384
- }
16385
- return parsed;
16386
- }
16387
- /**
16388
- * Reads runtime context attached to tool call arguments.
16389
- *
16390
- * @private internal runtime wiring for commitment tools
16391
- */
16392
- function readToolRuntimeContextFromToolArgs(args) {
16393
- return parseToolRuntimeContext(args[TOOL_RUNTIME_CONTEXT_ARGUMENT]);
16394
- }
16395
- /**
16396
- * Reads the hidden tool-progress token from tool arguments.
16397
- *
16398
- * @private internal runtime wiring for commitment tools
16399
- */
16400
- function readToolProgressTokenFromToolArgs(args) {
16401
- const token = args[TOOL_PROGRESS_TOKEN_ARGUMENT];
16402
- return typeof token === 'string' && token.trim().length > 0 ? token : null;
16403
- }
16404
- /**
16405
- * Serializes runtime context for prompt parameters.
16406
- *
16407
- * @private internal runtime wiring for commitment tools
16408
- */
16409
- function serializeToolRuntimeContext(context) {
16410
- return JSON.stringify(context);
16411
- }
16412
- /**
16413
- * Registers one in-memory listener that receives progress updates emitted by a running tool.
16414
- *
16415
- * The returned token is passed into script execution as a hidden argument so tool implementations
16416
- * can stream progress without exposing extra parameters to the model.
16417
- *
16418
- * @param listener - Listener notified about tool progress.
16419
- * @returns Hidden token used to route progress updates.
16420
- * @private internal runtime wiring for commitment tools
16421
- */
16422
- function registerToolCallProgressListener(listener) {
16423
- toolCallProgressListenerCounter += 1;
16424
- const token = `tool-progress:${Date.now()}:${toolCallProgressListenerCounter}`;
16425
- toolCallProgressListeners.set(token, listener);
16426
- return token;
16427
- }
16428
- /**
16429
- * Unregisters one in-memory progress listener.
16430
- *
16431
- * @param token - Token previously created by `registerToolCallProgressListener`.
16432
- * @private internal runtime wiring for commitment tools
16433
- */
16434
- function unregisterToolCallProgressListener(token) {
16435
- toolCallProgressListeners.delete(token);
16436
- }
16437
- /**
16438
- * Emits one tool progress update using a hidden token carried in tool arguments.
16439
- *
16440
- * @param args - Raw tool arguments including hidden runtime keys.
16441
- * @param update - Incremental progress update.
16442
- * @returns `true` when a listener was found and notified.
16443
- * @private internal runtime wiring for commitment tools
16444
- */
16445
- function emitToolCallProgressFromToolArgs(args, update) {
16446
- const token = readToolProgressTokenFromToolArgs(args);
16447
- if (!token) {
16448
- return false;
16449
- }
16450
- const listener = toolCallProgressListeners.get(token);
16451
- if (!listener) {
16452
- return false;
16453
- }
16454
- listener(update);
16455
- return true;
16456
- }
16457
- /**
16458
- * Note: [💞] Ignore a discrepancy between file name and entity name
16459
- */
16460
-
16461
- /**
16462
- * Logical public directory marker used in `run_browser` payload paths.
16326
+ * Cached implementation of `run_browser` when it can be resolved.
16463
16327
  *
16464
- * This value is kept stable for UI parsing and `/api/browser-artifacts/*` URL mapping.
16465
- */
16466
- const RUN_BROWSER_ARTIFACT_PUBLIC_DIRECTORY = '.playwright-cli';
16467
- /**
16468
- * Runtime environment variable that overrides local artifact storage directory.
16469
- */
16470
- const RUN_BROWSER_ARTIFACT_STORAGE_DIRECTORY_ENV = 'RUN_BROWSER_ARTIFACT_STORAGE_DIRECTORY';
16471
- /**
16472
- * Default writable directory for `run_browser` screenshot/video artifacts.
16473
- */
16474
- const DEFAULT_RUN_BROWSER_ARTIFACT_STORAGE_DIRECTORY = join(tmpdir(), 'promptbook', 'run-browser-artifacts');
16475
- /**
16476
- * Converts Windows separators to POSIX separators for payload paths.
16477
- */
16478
- function toPosixPath$1(pathname) {
16479
- return pathname.split('\\').join('/');
16480
- }
16481
- /**
16482
- * Resolves writable filesystem directory used for artifact persistence.
16483
- */
16484
- function resolveRunBrowserArtifactStorageDirectory() {
16485
- const configuredStorageDirectory = process.env[RUN_BROWSER_ARTIFACT_STORAGE_DIRECTORY_ENV];
16486
- if (configuredStorageDirectory && configuredStorageDirectory.trim()) {
16487
- return configuredStorageDirectory.trim();
16488
- }
16489
- return DEFAULT_RUN_BROWSER_ARTIFACT_STORAGE_DIRECTORY;
16490
- }
16491
- /**
16492
- * Resolves absolute filesystem path of one artifact filename.
16493
- */
16494
- function resolveRunBrowserArtifactFilesystemPath(artifactFilename) {
16495
- return join(resolveRunBrowserArtifactStorageDirectory(), artifactFilename);
16496
- }
16497
- /**
16498
- * Resolves payload path of one artifact filename used by replay renderers.
16499
- */
16500
- function resolveRunBrowserArtifactPublicPath(artifactFilename) {
16501
- return toPosixPath$1(`${RUN_BROWSER_ARTIFACT_PUBLIC_DIRECTORY}/${artifactFilename}`);
16502
- }
16503
-
16504
- /**
16505
- * Error code used for remote-browser infrastructure outages.
16506
- */
16507
- const REMOTE_BROWSER_UNAVAILABLE_ERROR_CODE = 'REMOTE_BROWSER_UNAVAILABLE';
16508
- /**
16509
- * Error thrown when a remote Playwright browser cannot be reached.
16510
- */
16511
- class RemoteBrowserUnavailableError extends KnowledgeScrapeError {
16512
- constructor(options) {
16513
- var _a;
16514
- super(options.message);
16515
- this.code = REMOTE_BROWSER_UNAVAILABLE_ERROR_CODE;
16516
- this.isRetryable = true;
16517
- this.debug = options.debug;
16518
- this.suggestedNextSteps =
16519
- (_a = options.suggestedNextSteps) !== null && _a !== void 0 ? _a : [
16520
- 'Verify remote browser infrastructure is running and reachable from Agents Server.',
16521
- 'Check firewall and DNS routing for the remote browser host and port.',
16522
- 'Retry later or continue with non-graphical fallback scraping.',
16523
- ];
16524
- this.cause = options.cause;
16525
- Object.setPrototypeOf(this, RemoteBrowserUnavailableError.prototype);
16526
- }
16527
- }
16528
- /**
16529
- * Returns true when an unknown value is one of the remote-browser outage errors.
16530
- */
16531
- function isRemoteBrowserUnavailableError(error) {
16532
- return error instanceof RemoteBrowserUnavailableError;
16533
- }
16534
- /**
16535
- * Sanitizes a remote websocket endpoint so debug payloads never expose path secrets.
16536
- */
16537
- function sanitizeRemoteBrowserEndpoint(wsEndpoint) {
16538
- var _a, _b;
16539
- try {
16540
- const parsedEndpoint = new URL(wsEndpoint);
16541
- return {
16542
- protocol: parsedEndpoint.protocol || null,
16543
- host: parsedEndpoint.hostname || null,
16544
- port: parsedEndpoint.port ? Number.parseInt(parsedEndpoint.port, 10) : null,
16545
- };
16546
- }
16547
- catch (_c) {
16548
- const hostPortMatch = wsEndpoint.trim().match(/^(?:wss?:\/\/)?(?<host>[^:/?#]+)(?::(?<port>\d{1,5}))?/i);
16549
- const host = ((_a = hostPortMatch === null || hostPortMatch === void 0 ? void 0 : hostPortMatch.groups) === null || _a === void 0 ? void 0 : _a.host) || null;
16550
- const parsedPort = (_b = hostPortMatch === null || hostPortMatch === void 0 ? void 0 : hostPortMatch.groups) === null || _b === void 0 ? void 0 : _b.port;
16551
- return {
16552
- protocol: wsEndpoint.startsWith('wss://') ? 'wss:' : wsEndpoint.startsWith('ws://') ? 'ws:' : null,
16553
- host,
16554
- port: parsedPort ? Number.parseInt(parsedPort, 10) : null,
16555
- };
16556
- }
16557
- }
16558
- /**
16559
- * Extracts network-like error code from unknown error payload.
16560
- */
16561
- function extractNetworkErrorCode(error) {
16562
- var _a;
16563
- if (error && typeof error === 'object') {
16564
- const maybeCode = error.code;
16565
- if (typeof maybeCode === 'string' && maybeCode.trim()) {
16566
- return maybeCode.trim().toUpperCase();
16567
- }
16568
- }
16569
- const message = getErrorMessage(error);
16570
- const match = message.match(/\b(ECONNREFUSED|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|ECONNRESET|EHOSTUNREACH|ENETUNREACH)\b/i);
16571
- return ((_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || null;
16572
- }
16573
- /**
16574
- * Classifies whether an unknown error most likely represents remote browser infra outage.
16575
- */
16576
- function isRemoteBrowserInfrastructureError(error) {
16577
- const networkErrorCode = extractNetworkErrorCode(error);
16578
- if (networkErrorCode) {
16579
- return true;
16580
- }
16581
- const message = getErrorMessage(error).toLowerCase();
16582
- const isWebSocketFailure = message.includes('websocket') ||
16583
- message.includes('<ws error>') ||
16584
- message.includes('ws connect error') ||
16585
- message.includes('socket hang up');
16586
- const hasHandshakeFailure = message.includes('unexpected server response') ||
16587
- message.includes('handshake') ||
16588
- message.includes('code=1006') ||
16589
- message.includes('disconnected');
16590
- return isWebSocketFailure && hasHandshakeFailure;
16591
- }
16592
- /**
16593
- * Converts unknown thrown values into safe string messages.
16594
- */
16595
- function getErrorMessage(error) {
16596
- return error instanceof Error ? error.message : String(error);
16597
- }
16598
- /**
16599
- * Converts unknown errors into stack payloads that are safe to render in debug mode.
16600
- */
16601
- function getErrorStack(error) {
16602
- return error instanceof Error && error.stack ? error.stack : null;
16603
- }
16604
-
16605
- /**
16606
- * Matches unsupported characters in snapshot file suffixes.
16607
- */
16608
- const SNAPSHOT_FILE_SUFFIX_UNSAFE_CHARACTER_PATTERN = /[^a-z0-9-]/g;
16609
- /**
16610
- * Creates one filesystem-safe optional filename suffix for a snapshot.
16611
- */
16612
- function createSnapshotFileSuffix(rawSuffix) {
16613
- if (!rawSuffix) {
16614
- return '';
16615
- }
16616
- const normalized = rawSuffix
16617
- .trim()
16618
- .toLowerCase()
16619
- .replace(/\s+/g, '-')
16620
- .replace(SNAPSHOT_FILE_SUFFIX_UNSAFE_CHARACTER_PATTERN, '-')
16621
- .replace(/-+/g, '-')
16622
- .replace(/^-|-$/g, '');
16623
- return normalized;
16624
- }
16625
- /**
16626
- * Resolves snapshot filename for one session and optional stage suffix.
16627
- */
16628
- function resolveSnapshotFilename(sessionId, fileSuffix) {
16629
- const safeSuffix = createSnapshotFileSuffix(fileSuffix);
16630
- return safeSuffix ? `${sessionId}-${safeSuffix}.png` : `${sessionId}.png`;
16631
- }
16632
- /**
16633
- * Creates one user-facing description for an executed browser action.
16634
- */
16635
- function formatActionSummary(action) {
16636
- switch (action.type) {
16637
- case 'navigate':
16638
- return `Navigate to ${action.url}`;
16639
- case 'click':
16640
- return `Click ${action.selector}`;
16641
- case 'type':
16642
- return `Type into ${action.selector}`;
16643
- case 'wait':
16644
- return `Wait ${action.milliseconds}ms`;
16645
- case 'scroll':
16646
- return action.selector ? `Scroll ${action.pixels}px in ${action.selector}` : `Scroll ${action.pixels}px on page`;
16647
- }
16648
- }
16649
- /**
16650
- * Screenshot/artifact and page-cleanup helpers for `run_browser`.
16651
- *
16652
- * @private function of `run_browser`
16653
- */
16654
- const runBrowserArtifacts = {
16655
- /**
16656
- * Captures a screenshot artifact for the current page and returns relative path.
16657
- */
16658
- async captureSnapshot(page, sessionId, fileSuffix) {
16659
- const snapshotFilename = resolveSnapshotFilename(sessionId, fileSuffix);
16660
- const snapshotDirectoryPath = resolveRunBrowserArtifactStorageDirectory();
16661
- const snapshotPath = resolveRunBrowserArtifactFilesystemPath(snapshotFilename);
16662
- try {
16663
- await mkdir(snapshotDirectoryPath, { recursive: true });
16664
- try {
16665
- await page.screenshot({ path: snapshotPath, fullPage: true });
16666
- }
16667
- catch (error) {
16668
- console.warn('[run_browser] Full-page snapshot failed, retrying viewport-only screenshot', {
16669
- sessionId,
16670
- snapshotFilename,
16671
- error: getErrorMessage(error),
16672
- });
16673
- await page.screenshot({ path: snapshotPath, fullPage: false });
16674
- }
16675
- return resolveRunBrowserArtifactPublicPath(snapshotFilename);
16676
- }
16677
- catch (error) {
16678
- console.error('[run_browser] Failed to capture snapshot', {
16679
- sessionId,
16680
- snapshotFilename,
16681
- error: getErrorMessage(error),
16682
- });
16683
- return null;
16684
- }
16685
- },
16686
- /**
16687
- * Safely retrieves page title from current browser page.
16688
- */
16689
- async getPageTitle(page) {
16690
- try {
16691
- return await page.title();
16692
- }
16693
- catch (_a) {
16694
- return null;
16695
- }
16696
- },
16697
- /**
16698
- * Closes browser page and logs non-fatal cleanup errors.
16699
- */
16700
- async cleanupPage(page, sessionId) {
16701
- if (!page) {
16702
- return;
16703
- }
16704
- try {
16705
- await page.close();
16706
- }
16707
- catch (error) {
16708
- console.error('[run_browser] Failed to cleanup browser page', {
16709
- sessionId,
16710
- error: getErrorMessage(error),
16711
- });
16712
- }
16713
- },
16714
- /**
16715
- * Captures one screenshot artifact and enriches it with page metadata.
16716
- */
16717
- async captureSnapshotArtifact(options) {
16718
- const { page, sessionId, label, fileSuffix, actionIndex, action } = options;
16719
- const path = await this.captureSnapshot(page, sessionId, fileSuffix);
16720
- if (!path) {
16721
- return null;
16722
- }
16723
- const actionSummary = action ? formatActionSummary(action) : undefined;
16724
- return {
16725
- kind: 'screenshot',
16726
- label,
16727
- path,
16728
- capturedAt: new Date().toISOString(),
16729
- url: page.url(),
16730
- title: await this.getPageTitle(page),
16731
- actionIndex,
16732
- actionSummary,
16733
- };
16734
- },
16735
- };
16736
-
16737
- /**
16738
- * Shared constants used by the `run_browser` tool.
16739
- *
16740
- * @private internal constants of `run_browser`
16741
- */
16742
- const runBrowserConstants = {
16743
- sessionPrefix: 'agents-server-run-browser',
16744
- snapshotDirectory: '.playwright-cli',
16745
- resultSchema: 'promptbook/run-browser@1',
16746
- defaultWaitMs: 1000,
16747
- maxWaitMs: 60000,
16748
- defaultScrollPixels: 800,
16749
- defaultNavigationTimeoutMs: 20000,
16750
- defaultActionTimeoutMs: 15000,
16751
- fallbackDynamicContentWarning: 'Remote browser is unavailable. Fallback scraping was used and dynamic content may be missing.',
16752
- validationErrorCode: 'RUN_BROWSER_VALIDATION_ERROR',
16753
- navigationFailedErrorCode: 'RUN_BROWSER_NAVIGATION_FAILED',
16754
- actionFailedErrorCode: 'RUN_BROWSER_ACTION_FAILED',
16755
- cancelledErrorCode: 'RUN_BROWSER_CANCELLED',
16756
- unknownErrorCode: 'RUN_BROWSER_UNKNOWN_ERROR',
16757
- };
16758
-
16759
- const config = ConfigChecker.from({
16760
- ...process.env,
16761
- // Note: To expose env variables to the browser, using this seemingly strange syntax:
16762
- // @see https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#exposing-environment-variables-to-the-browser
16763
- NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL,
16764
- NEXT_PUBLIC_VERCEL_ENV: process.env.NEXT_PUBLIC_VERCEL_ENV,
16765
- NEXT_PUBLIC_VERCEL_TARGET_ENV: process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV,
16766
- NEXT_PUBLIC_VERCEL_URL: process.env.NEXT_PUBLIC_VERCEL_URL,
16767
- NEXT_PUBLIC_VERCEL_BRANCH_URL: process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL,
16768
- NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL: process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL,
16769
- NEXT_PUBLIC_VERCEL_GIT_PROVIDER: process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER,
16770
- NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER: process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER,
16771
- NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG: process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG,
16772
- NEXT_PUBLIC_VERCEL_GIT_REPO_ID: process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_ID,
16773
- NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,
16774
- NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE,
16775
- NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF,
16776
- NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME,
16777
- NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_LOGIN: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_LOGIN,
16778
- NEXT_PUBLIC_VERCEL_GIT_PREVIOUS_SHA: process.env.NEXT_PUBLIC_VERCEL_GIT_PREVIOUS_SHA,
16779
- NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID: process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID,
16780
- });
16781
- /**
16782
- * Public URL of the deployment, e.g. "https://my-app.vercel.app"
16783
- *
16784
- * Note: When a request resolves through the global `_Server` registry,
16785
- * this URL will be overridden by the matched server domain.
16786
- */
16787
- config.get('NEXT_PUBLIC_SITE_URL').url().value;
16788
- /**
16789
- * [♐️] Vercel environment: "development" | "preview" | "production"
16790
- */
16791
- config.get('NEXT_PUBLIC_VERCEL_ENV').value;
16792
- /**
16793
- * [♐️] Target environment – can be system or custom
16794
- */
16795
- config.get('NEXT_PUBLIC_VERCEL_TARGET_ENV').value;
16796
- /**
16797
- * [♐️] Deployment URL (without https://), e.g. "my-app-abc123.vercel.app"
16798
- */
16799
- config.get('NEXT_PUBLIC_VERCEL_URL').value;
16800
- /**
16801
- * [♐️] Branch URL (without https://), only for branch deployments
16802
- */
16803
- config.get('NEXT_PUBLIC_VERCEL_BRANCH_URL').value;
16804
- /**
16805
- * [♐️] Production domain of the project
16806
- */
16807
- config.get('NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL').value;
16808
- /**
16809
- * [♐️] Git provider (github | gitlab | bitbucket)
16810
- */
16811
- config.get('NEXT_PUBLIC_VERCEL_GIT_PROVIDER').value;
16812
- /**
16813
- * [♐️] Repository owner (e.g. "hejny")
16814
- */
16815
- config.get('NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER').value;
16816
- /**
16817
- * [♐️] Repository slug (e.g. "my-project")
16818
- */
16819
- config.get('NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG').value;
16820
- /**
16821
- * [♐️] Repository internal ID
16822
- */
16823
- config.get('NEXT_PUBLIC_VERCEL_GIT_REPO_ID').value;
16824
- /**
16825
- * [♐️] Git commit SHA (short or long)
16826
- */
16827
- config.get('NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA').value;
16828
- /**
16829
- * [♐️] Commit message used for this deployment
16830
- */
16831
- config.get('NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE').value;
16832
- /**
16833
- * [♐️] Branch name (ref), e.g. "main"
16834
- */
16835
- config.get('NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF').value;
16836
- /**
16837
- * Author name of the commit
16838
- */
16839
- config.get('NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME').value;
16840
- /**
16841
- * [♐️] Author login/username
16842
- */
16843
- config.get('NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_LOGIN').value;
16844
- /**
16845
- * [♐️] Previous deployment commit SHA (if exists)
16846
- */
16847
- config.get('NEXT_PUBLIC_VERCEL_GIT_PREVIOUS_SHA').value;
16848
- /**
16849
- * [♐️] Pull Request ID for PR-based deployments
16850
- */
16851
- config.get('NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID').value;
16852
- /**
16853
- * Supabase table prefix
16854
- *
16855
- * This remains the fallback/default prefix used before `_Server` contains records
16856
- * or for local development requests.
16857
- */
16858
- config.get('SUPABASE_TABLE_PREFIX').value;
16859
- /**
16860
- * WebSocket endpoint URL for remote Playwright browser server (e.g., ws://browser-server:3000).
16861
- *
16862
- * When set, browser automation will connect to this remote server instead of launching a local browser.
16863
- * This is useful for environments like Vercel where running a full browser locally is not possible.
16864
- * Leave empty to use local browser mode.
16865
- */
16866
- const rawRemoteBrowserUrl = config.get('REMOTE_BROWSER_URL').value;
16867
- /**
16868
- * WebSocket endpoint URL for remote Playwright browser server (e.g., ws://browser-server:3000).
16869
- *
16870
- * When set, browser automation will connect to this remote server instead of launching a local browser.
16871
- * This is useful for environments like Vercel where running a full browser locally is not possible.
16872
- * Leave empty to use local browser mode.
16873
- */
16874
- const REMOTE_BROWSER_URL = typeof rawRemoteBrowserUrl === 'string' ? rawRemoteBrowserUrl : '';
16875
-
16876
- /**
16877
- * Reads a positive integer value from environment variables.
16878
- */
16879
- function resolvePositiveIntFromEnv$1(variableName, defaultValue) {
16880
- const rawValue = process.env[variableName];
16881
- if (!rawValue || !rawValue.trim()) {
16882
- return defaultValue;
16883
- }
16884
- const parsed = Number.parseInt(rawValue.trim(), 10);
16885
- if (!Number.isFinite(parsed) || parsed <= 0) {
16886
- return defaultValue;
16887
- }
16888
- return parsed;
16889
- }
16890
- /**
16891
- * Runtime helpers for mode/session/timeout handling in `run_browser`.
16892
- *
16893
- * @private function of `run_browser`
16894
- */
16895
- const runBrowserRuntime = {
16896
- /**
16897
- * Creates a dedicated session id for one tool invocation.
16898
- */
16899
- createRunBrowserSessionId() {
16900
- return `${runBrowserConstants.sessionPrefix}-${randomUUID()}`;
16901
- },
16902
- /**
16903
- * Determines whether the browser tool is running in local or remote mode.
16904
- */
16905
- resolveExecutionMode() {
16906
- return REMOTE_BROWSER_URL && REMOTE_BROWSER_URL.trim().length > 0 ? 'remote' : 'local';
16907
- },
16908
- /**
16909
- * Converts the execution mode into a human-readable label.
16910
- */
16911
- formatExecutionMode(mode) {
16912
- return mode === 'remote' ? 'remote-browser' : 'local-browser';
16913
- },
16914
- /**
16915
- * Resolves timeout configuration from env defaults and optional call overrides.
16916
- */
16917
- resolveTimeoutConfiguration(overrides) {
16918
- const envNavigationTimeoutMs = resolvePositiveIntFromEnv$1('RUN_BROWSER_NAVIGATION_TIMEOUT_MS', runBrowserConstants.defaultNavigationTimeoutMs);
16919
- const envActionTimeoutMs = resolvePositiveIntFromEnv$1('RUN_BROWSER_ACTION_TIMEOUT_MS', runBrowserConstants.defaultActionTimeoutMs);
16920
- const navigationTimeoutMs = (overrides === null || overrides === void 0 ? void 0 : overrides.navigationMs) && Number.isFinite(overrides.navigationMs) && overrides.navigationMs > 0
16921
- ? Math.floor(overrides.navigationMs)
16922
- : envNavigationTimeoutMs;
16923
- const actionTimeoutMs = (overrides === null || overrides === void 0 ? void 0 : overrides.actionMs) && Number.isFinite(overrides.actionMs) && overrides.actionMs > 0
16924
- ? Math.floor(overrides.actionMs)
16925
- : envActionTimeoutMs;
16926
- return {
16927
- navigationTimeoutMs,
16928
- actionTimeoutMs,
16929
- };
16930
- },
16931
- };
16932
-
16933
- /**
16934
- * Error classification and cancellation helpers used by `run_browser`.
16935
- *
16936
- * @private function of `run_browser`
16937
- */
16938
- const runBrowserErrorHandling = {
16939
- /**
16940
- * Creates one tagged ParseError used for deterministic input validation failures.
16941
- */
16942
- createRunBrowserValidationError(options) {
16943
- const error = new ParseError(options.message);
16944
- error.name = 'RunBrowserValidationError';
16945
- error.runBrowserCode = runBrowserConstants.validationErrorCode;
16946
- error.isRetryable = false;
16947
- error.suggestedNextSteps = [
16948
- 'Fix the action payload to match the run_browser schema.',
16949
- 'Check selectors and required action fields before retrying.',
16950
- ];
16951
- error.debug = options.debug;
16952
- return error;
16953
- },
16954
- /**
16955
- * Creates one tagged KnowledgeScrapeError used for navigation failures.
16956
- */
16957
- createRunBrowserNavigationError(options) {
16958
- const error = new KnowledgeScrapeError(options.message);
16959
- error.name = 'RunBrowserNavigationError';
16960
- error.runBrowserCode = runBrowserConstants.navigationFailedErrorCode;
16961
- error.isRetryable = false;
16962
- error.suggestedNextSteps = [
16963
- 'Verify the URL is reachable and not blocked.',
16964
- 'Retry with a simpler action sequence.',
16965
- ];
16966
- error.debug = options.debug;
16967
- error.cause = options.cause;
16968
- return error;
16969
- },
16970
- /**
16971
- * Creates one tagged KnowledgeScrapeError used for action failures.
16972
- */
16973
- createRunBrowserActionError(options) {
16974
- const error = new KnowledgeScrapeError(options.message);
16975
- error.name = 'RunBrowserActionError';
16976
- error.runBrowserCode = runBrowserConstants.actionFailedErrorCode;
16977
- error.isRetryable = false;
16978
- error.suggestedNextSteps = [
16979
- 'Verify selectors and action values.',
16980
- 'Reduce the action sequence to isolate the failing step.',
16981
- ];
16982
- error.debug = options.debug;
16983
- error.cause = options.cause;
16984
- return error;
16985
- },
16986
- /**
16987
- * Creates one tagged KnowledgeScrapeError used for cancellation.
16988
- */
16989
- createRunBrowserCancelledError(options) {
16990
- const error = new KnowledgeScrapeError(options.message);
16991
- error.name = 'RunBrowserCancelledError';
16992
- error.runBrowserCode = runBrowserConstants.cancelledErrorCode;
16993
- error.isRetryable = true;
16994
- error.suggestedNextSteps = [
16995
- 'Retry while request context is still active.',
16996
- 'Increase timeout if operation is expected to run longer.',
16997
- ];
16998
- error.debug = options.debug;
16999
- error.cause = options.cause;
17000
- return error;
17001
- },
17002
- /**
17003
- * Checks whether an unknown error carries run_browser classification tags.
17004
- */
17005
- isTaggedRunBrowserError(error) {
17006
- if (!error || typeof error !== 'object') {
17007
- return false;
17008
- }
17009
- const candidate = error;
17010
- return (typeof candidate.runBrowserCode === 'string' &&
17011
- typeof candidate.isRetryable === 'boolean' &&
17012
- Array.isArray(candidate.suggestedNextSteps) &&
17013
- typeof candidate.debug === 'object' &&
17014
- candidate.debug !== null);
17015
- },
17016
- /**
17017
- * Converts unknown errors into structured tool error payloads.
17018
- */
17019
- classifyRunBrowserToolError(options) {
17020
- if (isRemoteBrowserUnavailableError(options.error)) {
17021
- return {
17022
- code: options.error.code,
17023
- message: options.error.message,
17024
- isRetryable: options.error.isRetryable,
17025
- suggestedNextSteps: options.error.suggestedNextSteps,
17026
- debug: {
17027
- ...options.error.debug,
17028
- sessionId: options.sessionId,
17029
- mode: runBrowserRuntime.formatExecutionMode(options.mode),
17030
- },
17031
- };
17032
- }
17033
- if (this.isTaggedRunBrowserError(options.error)) {
17034
- return {
17035
- code: options.error.runBrowserCode,
17036
- message: options.error.message,
17037
- isRetryable: options.error.isRetryable,
17038
- suggestedNextSteps: options.error.suggestedNextSteps,
17039
- debug: {
17040
- ...options.error.debug,
17041
- sessionId: options.sessionId,
17042
- mode: runBrowserRuntime.formatExecutionMode(options.mode),
17043
- },
17044
- };
17045
- }
17046
- const remoteBrowserEndpoint = REMOTE_BROWSER_URL && REMOTE_BROWSER_URL.trim().length > 0
17047
- ? sanitizeRemoteBrowserEndpoint(REMOTE_BROWSER_URL.trim())
17048
- : null;
17049
- const message = getErrorMessage(options.error);
17050
- return {
17051
- code: runBrowserConstants.unknownErrorCode,
17052
- message,
17053
- isRetryable: false,
17054
- suggestedNextSteps: ['Inspect debug details to identify the failing phase.', 'Retry with fewer actions.'],
17055
- debug: {
17056
- sessionId: options.sessionId,
17057
- mode: runBrowserRuntime.formatExecutionMode(options.mode),
17058
- remoteBrowserEndpoint,
17059
- message,
17060
- stack: getErrorStack(options.error),
17061
- },
17062
- };
17063
- },
17064
- /**
17065
- * Asserts that the run was not aborted.
17066
- */
17067
- assertNotAborted(signal, sessionId) {
17068
- if (!(signal === null || signal === void 0 ? void 0 : signal.aborted)) {
17069
- return;
17070
- }
17071
- throw this.createRunBrowserCancelledError({
17072
- message: 'run_browser execution was cancelled.',
17073
- debug: { sessionId },
17074
- });
17075
- },
17076
- /**
17077
- * Returns true when the tool error represents remote browser unavailability.
17078
- */
17079
- isRemoteBrowserUnavailableCode(code) {
17080
- return code === REMOTE_BROWSER_UNAVAILABLE_ERROR_CODE;
17081
- },
17082
- };
17083
-
17084
- /**
17085
- * In-memory observability counters for browser tool execution.
17086
- */
17087
- const RUN_BROWSER_OBSERVABILITY = {
17088
- totalRuns: 0,
17089
- fallbackRuns: 0,
17090
- errorCodeCounts: {},
17091
- };
17092
- /**
17093
- * Observability counters and metric logging for `run_browser`.
17094
- *
17095
- * @private function of `run_browser`
17096
- */
17097
- const runBrowserObservability = {
17098
- /**
17099
- * Increments total-run counter and returns the updated value.
17100
- */
17101
- incrementTotalRuns() {
17102
- RUN_BROWSER_OBSERVABILITY.totalRuns++;
17103
- return RUN_BROWSER_OBSERVABILITY.totalRuns;
17104
- },
17105
- /**
17106
- * Returns current total run count.
17107
- */
17108
- getTotalRuns() {
17109
- return RUN_BROWSER_OBSERVABILITY.totalRuns;
17110
- },
17111
- /**
17112
- * Increments fallback counter and returns updated metrics.
17113
- */
17114
- incrementFallbackRunsAndGetMetrics() {
17115
- RUN_BROWSER_OBSERVABILITY.fallbackRuns++;
17116
- return {
17117
- fallbackRuns: RUN_BROWSER_OBSERVABILITY.fallbackRuns,
17118
- fallbackRate: RUN_BROWSER_OBSERVABILITY.totalRuns === 0
17119
- ? 0
17120
- : RUN_BROWSER_OBSERVABILITY.fallbackRuns / RUN_BROWSER_OBSERVABILITY.totalRuns,
17121
- };
17122
- },
17123
- /**
17124
- * Increments one error-code counter and returns the updated value.
17125
- */
17126
- incrementRunBrowserErrorCodeCounter(code) {
17127
- const currentValue = RUN_BROWSER_OBSERVABILITY.errorCodeCounts[code] || 0;
17128
- const nextValue = currentValue + 1;
17129
- RUN_BROWSER_OBSERVABILITY.errorCodeCounts[code] = nextValue;
17130
- return nextValue;
17131
- },
17132
- /**
17133
- * Writes one structured metric line for browser-tool observability.
17134
- */
17135
- logRunBrowserMetric(options) {
17136
- console.info('[run_browser][metric]', {
17137
- tool: 'run_browser',
17138
- mode: options.mode,
17139
- sessionId: options.sessionId,
17140
- event: options.event,
17141
- ...(options.payload || {}),
17142
- });
17143
- },
17144
- };
17145
-
17146
- /**
17147
- * Computes one compact preview of a fallback scrape payload.
17148
- */
17149
- function createContentPreview(content) {
17150
- const normalized = content.replace(/\s+/g, ' ').trim();
17151
- if (normalized.length <= 280) {
17152
- return normalized;
17153
- }
17154
- return `${normalized.slice(0, 277)}...`;
17155
- }
17156
- /**
17157
- * Payload and markdown formatters for `run_browser` outcomes.
17158
- *
17159
- * @private function of `run_browser`
17160
- */
17161
- const runBrowserResultFormatting = {
17162
- /**
17163
- * Produces one structured payload consumed by chat UI browser replay renderers.
17164
- */
17165
- createResultPayload(options) {
17166
- return {
17167
- schema: runBrowserConstants.resultSchema,
17168
- sessionId: options.sessionId,
17169
- mode: options.mode,
17170
- modeUsed: options.modeUsed,
17171
- initialUrl: options.initialUrl,
17172
- finalUrl: options.finalUrl,
17173
- finalTitle: options.finalTitle,
17174
- executedActions: options.executedActions,
17175
- artifacts: options.artifacts,
17176
- warning: options.warning,
17177
- error: options.error,
17178
- fallback: options.modeUsed === 'fallback' && options.fallbackContent !== null
17179
- ? {
17180
- scraper: 'fetch_url_content',
17181
- contentPreview: createContentPreview(options.fallbackContent),
17182
- }
17183
- : null,
17184
- timing: options.timing,
17185
- };
17186
- },
17187
- /**
17188
- * Produces a model-friendly markdown summary from browser execution artifacts.
17189
- */
17190
- formatSuccessResult(options) {
17191
- const { payload, snapshotPath } = options;
17192
- return spaceTrim$1((block) => {
17193
- var _a, _b, _c;
17194
- return `
17195
- # Browser run completed
17196
-
17197
- **Session:** ${payload.sessionId}
17198
- **Mode requested:** ${runBrowserRuntime.formatExecutionMode(payload.mode)}
17199
- **Mode used:** ${payload.modeUsed}
17200
- **Initial URL:** ${payload.initialUrl}
17201
- **Executed actions:** ${payload.executedActions.length}
17202
-
17203
- ## Final page
17204
-
17205
- - URL: ${payload.finalUrl || 'Unknown'}
17206
- - Title: ${payload.finalTitle || 'Unknown'}
17207
-
17208
- ## Timings
17209
-
17210
- - Connect: ${(_a = payload.timing.connectDurationMs) !== null && _a !== void 0 ? _a : 'Unknown'} ms
17211
- - Initial navigation: ${(_b = payload.timing.initialNavigationDurationMs) !== null && _b !== void 0 ? _b : 'Unknown'} ms
17212
- - Time to first byte: ${(_c = payload.timing.timeToFirstByteMs) !== null && _c !== void 0 ? _c : 'Unknown'} ms
17213
- - Total: ${payload.timing.totalDurationMs} ms
17214
-
17215
- ${payload.artifacts.length === 0
17216
- ? ''
17217
- : `
17218
- ## Visual replay
17219
-
17220
- ${payload.artifacts
17221
- .map((artifact, index) => {
17222
- const actionPart = artifact.actionSummary ? ` (${artifact.actionSummary})` : '';
17223
- return `- ${index + 1}. ${artifact.label}${actionPart}: ${artifact.path}`;
17224
- })
17225
- .join('\n')}
17226
- `}
17227
-
17228
- ${!snapshotPath
17229
- ? ''
17230
- : `
17231
- ## Final snapshot
17232
-
17233
- ${snapshotPath}
17234
- `}
17235
-
17236
- ## Playback payload
17237
-
17238
- \`\`\`json
17239
- ${JSON.stringify(payload, null, 2)}
17240
- \`\`\`
17241
-
17242
- ${block(payload.executedActions.length === 0
17243
- ? ''
17244
- : `
17245
- ## Action log
17246
-
17247
- ${payload.executedActions
17248
- .map((action, index) => `- ${index + 1}. ${JSON.stringify(action)}`)
17249
- .join('\n')}
17250
- `)}
17251
-
17252
- Note: Browser page has been automatically closed to free up resources.
17253
- `;
17254
- });
17255
- },
17256
- /**
17257
- * Produces a model-friendly markdown payload when fallback scraping is used.
17258
- */
17259
- formatFallbackResult(options) {
17260
- const { payload, fallbackContent, requestedActions } = options;
17261
- return spaceTrim$1(`
17262
- # Browser run completed with fallback
17263
-
17264
- **Session:** ${payload.sessionId}
17265
- **Mode requested:** ${runBrowserRuntime.formatExecutionMode(payload.mode)}
17266
- **Mode used:** ${payload.modeUsed}
17267
- **Initial URL:** ${payload.initialUrl}
17268
- **Requested actions:** ${requestedActions}
17269
- **Executed actions:** ${payload.executedActions.length}
17270
- **Warning:** ${payload.warning || runBrowserConstants.fallbackDynamicContentWarning}
17271
-
17272
- ## Extracted content
17273
-
17274
- ${fallbackContent}
17275
-
17276
- ## Playback payload
17277
-
17278
- \`\`\`json
17279
- ${JSON.stringify(payload, null, 2)}
17280
- \`\`\`
17281
- `);
17282
- },
17283
- /**
17284
- * Produces a model-friendly markdown error payload from browser execution failures.
17285
- */
17286
- formatErrorResult(options) {
17287
- const { payload } = options;
17288
- const toolError = payload.error;
17289
- const suggestedNextSteps = (toolError === null || toolError === void 0 ? void 0 : toolError.suggestedNextSteps) || [];
17290
- return spaceTrim$1(`
17291
- # Browser run failed
17292
-
17293
- **Session:** ${payload.sessionId}
17294
- **Mode requested:** ${runBrowserRuntime.formatExecutionMode(payload.mode)}
17295
- **Mode used:** ${payload.modeUsed}
17296
- **Initial URL:** ${payload.initialUrl}
17297
- **Error code:** ${(toolError === null || toolError === void 0 ? void 0 : toolError.code) || runBrowserConstants.unknownErrorCode}
17298
- **Error:** ${(toolError === null || toolError === void 0 ? void 0 : toolError.message) || 'Unknown browser tool error'}
17299
-
17300
- ${suggestedNextSteps.length === 0
17301
- ? ''
17302
- : `
17303
- ## Suggested next steps
17304
-
17305
- ${suggestedNextSteps.map((step) => `- ${step}`).join('\n')}
17306
- `}
17307
-
17308
- ## Playback payload
17309
-
17310
- \`\`\`json
17311
- ${JSON.stringify(payload, null, 2)}
17312
- \`\`\`
17313
-
17314
- The browser tool could not complete the requested actions.
17315
- `);
17316
- },
17317
- };
17318
-
17319
- /**
17320
- * @@@
17321
- *
17322
- * @private within the repository
17323
- */
17324
- function locateChrome() {
17325
- return locateApp({
17326
- appName: 'Chrome',
17327
- linuxWhich: 'google-chrome',
17328
- windowsSuffix: '\\Google\\Chrome\\Application\\chrome.exe',
17329
- macOsName: 'Google Chrome',
17330
- });
17331
- }
17332
-
17333
- /**
17334
- * Creates one standard abort error for cancelled retry loops.
17335
- *
17336
- * @private utility for Agents Server runtime retries
17337
- */
17338
- function createAbortError$1() {
17339
- const error = new Error('Operation was aborted.');
17340
- error.name = 'AbortError';
17341
- return error;
17342
- }
17343
- /**
17344
- * Throws when the supplied signal is already aborted.
17345
- *
17346
- * @private utility for Agents Server runtime retries
17347
- */
17348
- function assertNotAborted(signal) {
17349
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
17350
- throw createAbortError$1();
17351
- }
17352
- }
17353
- /**
17354
- * Waits for a duration while respecting cancellation.
17355
- *
17356
- * @private utility for Agents Server runtime retries
17357
- */
17358
- async function sleepWithAbort(delayMs, signal) {
17359
- if (delayMs <= 0) {
17360
- assertNotAborted(signal);
17361
- return;
17362
- }
17363
- await new Promise((resolve, reject) => {
17364
- const timeout = setTimeout(() => {
17365
- signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
17366
- resolve();
17367
- }, delayMs);
17368
- const onAbort = () => {
17369
- clearTimeout(timeout);
17370
- signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
17371
- reject(createAbortError$1());
17372
- };
17373
- signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
17374
- });
17375
- }
17376
- /**
17377
- * Resolves the retry wait duration for one failed attempt.
17378
- *
17379
- * @private utility for Agents Server runtime retries
17380
- */
17381
- function resolveBackoffDelayMs(options) {
17382
- const exponentialDelay = options.initialDelayMs * Math.pow(options.backoffFactor, Math.max(0, options.attempt - 1));
17383
- const boundedDelay = Math.min(exponentialDelay, options.maxDelayMs);
17384
- const jitterDelay = boundedDelay * options.jitterRatio * Math.max(0, options.random());
17385
- return Math.max(0, Math.round(boundedDelay + jitterDelay));
17386
- }
17387
- /**
17388
- * Retries one async operation with exponential backoff and jitter.
17389
- *
17390
- * @private utility for Agents Server runtime retries
17391
- */
17392
- async function retryWithBackoff(operation, options) {
17393
- var _a, _b, _c;
17394
- const startedAt = Date.now();
17395
- const totalAttempts = Math.max(1, options.retries + 1);
17396
- const random = (_a = options.random) !== null && _a !== void 0 ? _a : Math.random;
17397
- const sleep = (_b = options.sleep) !== null && _b !== void 0 ? _b : sleepWithAbort;
17398
- for (let attempt = 1; attempt <= totalAttempts; attempt++) {
17399
- assertNotAborted(options.signal);
17400
- try {
17401
- const value = await operation(attempt);
17402
- return {
17403
- value,
17404
- attempts: attempt,
17405
- durationMs: Date.now() - startedAt,
17406
- };
17407
- }
17408
- catch (error) {
17409
- const isLastAttempt = attempt >= totalAttempts;
17410
- const isRetryable = options.shouldRetry ? options.shouldRetry(error, attempt) : true;
17411
- if (isLastAttempt || !isRetryable) {
17412
- throw error;
17413
- }
17414
- const delayMs = resolveBackoffDelayMs({
17415
- attempt,
17416
- initialDelayMs: options.initialDelayMs,
17417
- maxDelayMs: options.maxDelayMs,
17418
- backoffFactor: options.backoffFactor,
17419
- jitterRatio: options.jitterRatio,
17420
- random,
17421
- });
17422
- (_c = options.onRetry) === null || _c === void 0 ? void 0 : _c.call(options, {
17423
- attempt,
17424
- retries: options.retries,
17425
- delayMs,
17426
- error,
17427
- });
17428
- await sleep(delayMs, options.signal);
17429
- }
17430
- }
17431
- throw new Error('Retry loop exited unexpectedly.');
17432
- }
17433
-
17434
- const DEFAULT_BROWSER_USER_DATA_DIR = join(tmpdir(), 'promptbook', 'browser', 'user-data');
17435
- /**
17436
- * Default remote browser connect timeout in milliseconds.
17437
- */
17438
- const DEFAULT_REMOTE_CONNECT_TIMEOUT_MS = 10000;
17439
- /**
17440
- * Default retry count for remote browser connection establishment.
17441
- */
17442
- const DEFAULT_REMOTE_CONNECT_RETRIES = 2;
17443
- /**
17444
- * Default initial retry delay for remote browser connection.
17445
- */
17446
- const DEFAULT_REMOTE_CONNECT_BACKOFF_INITIAL_MS = 250;
17447
- /**
17448
- * Default maximum retry delay for remote browser connection.
17449
- */
17450
- const DEFAULT_REMOTE_CONNECT_BACKOFF_MAX_MS = 1000;
17451
- /**
17452
- * Default exponential multiplier for remote browser retry delay.
17453
- */
17454
- const DEFAULT_REMOTE_CONNECT_BACKOFF_FACTOR = 4;
17455
- /**
17456
- * Default retry jitter ratio for remote browser connection.
17457
- */
17458
- const DEFAULT_REMOTE_CONNECT_JITTER_RATIO = 0.2;
17459
- /**
17460
- * In-memory metrics counters for remote browser connect attempts.
17461
- */
17462
- const REMOTE_BROWSER_CONNECT_METRICS = {
17463
- success: 0,
17464
- failure: 0,
17465
- };
17466
- /**
17467
- * Reads a positive integer from environment variables with a fallback default.
17468
- */
17469
- function resolvePositiveIntFromEnv(variableName, defaultValue) {
17470
- const rawValue = process.env[variableName];
17471
- if (!rawValue || !rawValue.trim()) {
17472
- return defaultValue;
17473
- }
17474
- const parsed = Number.parseInt(rawValue.trim(), 10);
17475
- if (!Number.isFinite(parsed) || parsed <= 0) {
17476
- return defaultValue;
17477
- }
17478
- return parsed;
17479
- }
17480
- /**
17481
- * Reads a positive number from environment variables with a fallback default.
17482
- */
17483
- function resolvePositiveNumberFromEnv(variableName, defaultValue) {
17484
- const rawValue = process.env[variableName];
17485
- if (!rawValue || !rawValue.trim()) {
17486
- return defaultValue;
17487
- }
17488
- const parsed = Number.parseFloat(rawValue.trim());
17489
- if (!Number.isFinite(parsed) || parsed <= 0) {
17490
- return defaultValue;
17491
- }
17492
- return parsed;
17493
- }
17494
- /**
17495
- * Reads a non-negative integer from environment variables with a fallback default.
17496
- */
17497
- function resolveNonNegativeIntFromEnv(variableName, defaultValue) {
17498
- const rawValue = process.env[variableName];
17499
- if (!rawValue || !rawValue.trim()) {
17500
- return defaultValue;
17501
- }
17502
- const parsed = Number.parseInt(rawValue.trim(), 10);
17503
- if (!Number.isFinite(parsed) || parsed < 0) {
17504
- return defaultValue;
17505
- }
17506
- return parsed;
17507
- }
17508
- /**
17509
- * Reads a non-negative number from environment variables with a fallback default.
17510
- */
17511
- function resolveNonNegativeNumberFromEnv(variableName, defaultValue) {
17512
- const rawValue = process.env[variableName];
17513
- if (!rawValue || !rawValue.trim()) {
17514
- return defaultValue;
17515
- }
17516
- const parsed = Number.parseFloat(rawValue.trim());
17517
- if (!Number.isFinite(parsed) || parsed < 0) {
17518
- return defaultValue;
17519
- }
17520
- return parsed;
17521
- }
17522
- /**
17523
- * Creates one standard abort error.
17524
- */
17525
- function createAbortError() {
17526
- const error = new Error('Browser connection request was aborted.');
17527
- error.name = 'AbortError';
17528
- return error;
17529
- }
17530
- /**
17531
- * Provides browser context instances with support for both local and remote browser connections.
17532
- *
17533
- * This provider manages browser lifecycle and supports:
17534
- * - Local mode: Launches a persistent Chromium context on the same machine
17535
- * - Remote mode: Connects to a remote Playwright browser via WebSocket
17536
- *
17537
- * The remote mode is useful for environments like Vercel where running a full browser
17538
- * is not possible due to resource constraints.
17539
- *
17540
- * @private internal utility for Agents Server browser tools
16328
+ * @private internal utility for USE BROWSER commitment
17541
16329
  */
17542
- class BrowserConnectionProvider {
17543
- /**
17544
- * Creates a new BrowserConnectionProvider.
17545
- *
17546
- * @param options - Provider options
17547
- * @param options.isVerbose - Enable verbose logging
17548
- */
17549
- constructor(options = {}) {
17550
- var _a, _b, _c, _d, _e, _f, _g, _h;
17551
- this.browserContext = null;
17552
- this.connectionMode = null;
17553
- this.isVerbose = (_a = options.isVerbose) !== null && _a !== void 0 ? _a : false;
17554
- this.remoteConnectTimeoutMs =
17555
- (_b = options.remoteConnectTimeoutMs) !== null && _b !== void 0 ? _b : resolvePositiveIntFromEnv('RUN_BROWSER_CONNECT_TIMEOUT_MS', DEFAULT_REMOTE_CONNECT_TIMEOUT_MS);
17556
- this.remoteConnectRetries =
17557
- (_c = options.remoteConnectRetries) !== null && _c !== void 0 ? _c : resolveNonNegativeIntFromEnv('RUN_BROWSER_CONNECT_RETRIES', DEFAULT_REMOTE_CONNECT_RETRIES);
17558
- this.remoteConnectBackoffInitialMs =
17559
- (_d = options.remoteConnectBackoffInitialMs) !== null && _d !== void 0 ? _d : resolvePositiveIntFromEnv('RUN_BROWSER_CONNECT_BACKOFF_INITIAL_MS', DEFAULT_REMOTE_CONNECT_BACKOFF_INITIAL_MS);
17560
- this.remoteConnectBackoffMaxMs =
17561
- (_e = options.remoteConnectBackoffMaxMs) !== null && _e !== void 0 ? _e : resolvePositiveIntFromEnv('RUN_BROWSER_CONNECT_BACKOFF_MAX_MS', DEFAULT_REMOTE_CONNECT_BACKOFF_MAX_MS);
17562
- this.remoteConnectBackoffFactor =
17563
- (_f = options.remoteConnectBackoffFactor) !== null && _f !== void 0 ? _f : resolvePositiveNumberFromEnv('RUN_BROWSER_CONNECT_BACKOFF_FACTOR', DEFAULT_REMOTE_CONNECT_BACKOFF_FACTOR);
17564
- this.remoteConnectJitterRatio =
17565
- (_g = options.remoteConnectJitterRatio) !== null && _g !== void 0 ? _g : resolveNonNegativeNumberFromEnv('RUN_BROWSER_CONNECT_JITTER_RATIO', DEFAULT_REMOTE_CONNECT_JITTER_RATIO);
17566
- this.random = (_h = options.random) !== null && _h !== void 0 ? _h : Math.random;
17567
- this.sleep = options.sleep;
17568
- }
17569
- /**
17570
- * Gets a browser context, creating a new one if needed.
17571
- *
17572
- * This method automatically determines whether to use local or remote browser
17573
- * based on the REMOTE_BROWSER_URL environment variable.
17574
- *
17575
- * @returns Browser context instance
17576
- */
17577
- async getBrowserContext(options = {}) {
17578
- var _a;
17579
- if ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
17580
- throw createAbortError();
17581
- }
17582
- // Check if we have a cached connection that's still valid
17583
- if (this.browserContext !== null && this.isBrowserContextAlive(this.browserContext)) {
17584
- return this.browserContext;
17585
- }
17586
- // Determine connection mode from configuration
17587
- const mode = this.resolveConnectionMode();
17588
- this.connectionMode = mode;
17589
- if (this.isVerbose) {
17590
- console.info('[BrowserConnectionProvider] Creating new browser context', {
17591
- mode: mode.type,
17592
- wsEndpoint: mode.type === 'remote' ? mode.wsEndpoint : undefined,
17593
- });
17594
- }
17595
- // Create new browser context based on mode
17596
- if (mode.type === 'local') {
17597
- this.browserContext = await this.createLocalBrowserContext();
17598
- }
17599
- else {
17600
- this.browserContext = await this.createRemoteBrowserContext(mode.wsEndpoint, options);
17601
- }
17602
- return this.browserContext;
17603
- }
17604
- /**
17605
- * Closes all pages in the current browser context.
17606
- *
17607
- * This method is useful for cleanup between agent tasks without closing
17608
- * the entire browser instance.
17609
- */
17610
- async closeAllPages() {
17611
- if (!this.browserContext) {
17612
- return;
17613
- }
17614
- try {
17615
- const pages = this.browserContext.pages();
17616
- if (this.isVerbose) {
17617
- console.info('[BrowserConnectionProvider] Closing all pages', {
17618
- pageCount: pages.length,
17619
- });
17620
- }
17621
- await Promise.all(pages.map((page) => page.close().catch((error) => {
17622
- console.error('[BrowserConnectionProvider] Failed to close page', { error });
17623
- })));
17624
- }
17625
- catch (error) {
17626
- console.error('[BrowserConnectionProvider] Error closing pages', { error });
17627
- }
17628
- }
17629
- /**
17630
- * Closes the browser context and disconnects from the browser.
17631
- *
17632
- * This should be called when the browser is no longer needed to free up resources.
17633
- * For local mode, this closes the browser process. For remote mode, it disconnects
17634
- * from the remote browser but doesn't shut down the remote server.
17635
- */
17636
- async close() {
17637
- var _a;
17638
- if (!this.browserContext) {
17639
- return;
17640
- }
17641
- try {
17642
- if (this.isVerbose) {
17643
- console.info('[BrowserConnectionProvider] Closing browser context', {
17644
- mode: (_a = this.connectionMode) === null || _a === void 0 ? void 0 : _a.type,
17645
- });
17646
- }
17647
- await this.browserContext.close();
17648
- this.browserContext = null;
17649
- this.connectionMode = null;
17650
- }
17651
- catch (error) {
17652
- console.error('[BrowserConnectionProvider] Error closing browser context', { error });
17653
- // Reset state even if close fails
17654
- this.browserContext = null;
17655
- this.connectionMode = null;
17656
- }
17657
- }
17658
- /**
17659
- * Checks if a browser context is still alive and connected.
17660
- *
17661
- * @param context - Browser context to check
17662
- * @returns True if the context is connected and usable
17663
- */
17664
- isBrowserContextAlive(context) {
17665
- try {
17666
- const browser = context.browser();
17667
- return browser !== null && browser.isConnected();
17668
- }
17669
- catch (_a) {
17670
- return false;
17671
- }
17672
- }
17673
- /**
17674
- * Determines whether to use local or remote browser based on configuration.
17675
- *
17676
- * @returns Connection mode configuration
17677
- */
17678
- resolveConnectionMode() {
17679
- const remoteBrowserUrl = REMOTE_BROWSER_URL;
17680
- if (remoteBrowserUrl && remoteBrowserUrl.trim().length > 0) {
17681
- return {
17682
- type: 'remote',
17683
- wsEndpoint: remoteBrowserUrl.trim(),
17684
- };
17685
- }
17686
- return { type: 'local' };
17687
- }
17688
- /**
17689
- * Creates a local browser context using persistent Chromium.
17690
- *
17691
- * @returns Local browser context
17692
- */
17693
- async createLocalBrowserContext() {
17694
- if (this.isVerbose) {
17695
- console.info('[BrowserConnectionProvider] Launching local browser context');
17696
- }
17697
- const userDataDir = join(DEFAULT_BROWSER_USER_DATA_DIR, 'run-browser');
17698
- await mkdir(userDataDir, { recursive: true });
17699
- const launchOptions = {
17700
- headless: false,
17701
- args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
17702
- };
17703
- try {
17704
- const chromePath = await locateChrome();
17705
- launchOptions.executablePath = chromePath;
17706
- }
17707
- catch (error) {
17708
- if (this.isVerbose) {
17709
- console.warn('[BrowserConnectionProvider] Could not locate system Chrome; using Playwright bundled Chromium', {
17710
- error: error instanceof Error ? error.message : String(error),
17711
- });
17712
- }
17713
- }
17714
- return await chromium.launchPersistentContext(userDataDir, launchOptions);
17715
- }
17716
- /**
17717
- * Creates a remote browser context by connecting to a Playwright server.
17718
- *
17719
- * @param wsEndpoint - WebSocket endpoint of the remote Playwright server
17720
- * @returns Remote browser context
17721
- */
17722
- async createRemoteBrowserContext(wsEndpoint, options) {
17723
- const endpointDebug = sanitizeRemoteBrowserEndpoint(wsEndpoint);
17724
- const startedAt = Date.now();
17725
- if (this.isVerbose) {
17726
- console.info('[BrowserConnectionProvider] Connecting to remote browser', {
17727
- endpoint: endpointDebug,
17728
- connectTimeoutMs: this.remoteConnectTimeoutMs,
17729
- retries: this.remoteConnectRetries,
17730
- });
17731
- }
17732
- let attempts = 0;
17733
- try {
17734
- const connectResult = await retryWithBackoff(async (attempt) => {
17735
- attempts = attempt;
17736
- return await chromium.connect(wsEndpoint, {
17737
- timeout: this.remoteConnectTimeoutMs,
17738
- });
17739
- }, {
17740
- retries: this.remoteConnectRetries,
17741
- initialDelayMs: this.remoteConnectBackoffInitialMs,
17742
- maxDelayMs: this.remoteConnectBackoffMaxMs,
17743
- backoffFactor: this.remoteConnectBackoffFactor,
17744
- jitterRatio: this.remoteConnectJitterRatio,
17745
- signal: options.signal,
17746
- shouldRetry: (error) => isRemoteBrowserInfrastructureError(error),
17747
- onRetry: ({ attempt, delayMs, error }) => {
17748
- console.warn('[run_browser][retry]', {
17749
- tool: 'run_browser',
17750
- mode: 'remote-browser',
17751
- sessionId: options.sessionId || null,
17752
- event: 'remote_browser_connect_retry',
17753
- attempt,
17754
- delayMs,
17755
- endpoint: endpointDebug,
17756
- errorCode: extractNetworkErrorCode(error),
17757
- error: getErrorMessage(error),
17758
- });
17759
- },
17760
- random: this.random,
17761
- sleep: this.sleep,
17762
- });
17763
- const browser = connectResult.value;
17764
- // For remote connections, we need to create a new context
17765
- // Note: Remote browsers don't support persistent contexts
17766
- const context = await browser.newContext();
17767
- REMOTE_BROWSER_CONNECT_METRICS.success++;
17768
- console.info('[run_browser][metric]', {
17769
- tool: 'run_browser',
17770
- mode: 'remote-browser',
17771
- sessionId: options.sessionId || null,
17772
- event: 'remote_browser_connect_success',
17773
- attempts: connectResult.attempts,
17774
- connectDurationMs: connectResult.durationMs,
17775
- endpoint: endpointDebug,
17776
- counter: REMOTE_BROWSER_CONNECT_METRICS.success,
17777
- });
17778
- if (this.isVerbose) {
17779
- console.info('[BrowserConnectionProvider] Successfully connected to remote browser');
17780
- }
17781
- return context;
17782
- }
17783
- catch (error) {
17784
- REMOTE_BROWSER_CONNECT_METRICS.failure++;
17785
- const durationMs = Date.now() - startedAt;
17786
- const remoteInfraUnavailable = isRemoteBrowserInfrastructureError(error);
17787
- if (remoteInfraUnavailable) {
17788
- const remoteBrowserUnavailableError = new RemoteBrowserUnavailableError({
17789
- message: `Remote browser is unavailable. Could not establish a websocket connection.`,
17790
- debug: {
17791
- endpoint: endpointDebug,
17792
- attempts: Math.max(1, attempts),
17793
- connectTimeoutMs: this.remoteConnectTimeoutMs,
17794
- durationMs,
17795
- networkErrorCode: extractNetworkErrorCode(error),
17796
- originalMessage: getErrorMessage(error),
17797
- },
17798
- cause: error,
17799
- });
17800
- console.warn('[run_browser][metric]', {
17801
- tool: 'run_browser',
17802
- mode: 'remote-browser',
17803
- sessionId: options.sessionId || null,
17804
- event: 'remote_browser_connect_failure',
17805
- errorCode: remoteBrowserUnavailableError.code,
17806
- attempts: Math.max(1, attempts),
17807
- connectDurationMs: durationMs,
17808
- endpoint: endpointDebug,
17809
- counter: REMOTE_BROWSER_CONNECT_METRICS.failure,
17810
- });
17811
- throw remoteBrowserUnavailableError;
17812
- }
17813
- console.error('[run_browser][metric]', {
17814
- tool: 'run_browser',
17815
- mode: 'remote-browser',
17816
- sessionId: options.sessionId || null,
17817
- event: 'remote_browser_connect_failure',
17818
- errorCode: 'REMOTE_BROWSER_CONNECT_ERROR',
17819
- attempts: Math.max(1, attempts),
17820
- connectDurationMs: durationMs,
17821
- endpoint: endpointDebug,
17822
- error: getErrorMessage(error),
17823
- counter: REMOTE_BROWSER_CONNECT_METRICS.failure,
17824
- });
17825
- throw error;
17826
- }
17827
- }
17828
- }
17829
-
16330
+ let cachedRunBrowserTool = null;
17830
16331
  /**
17831
- * Singleton instance of the browser connection provider.
16332
+ * Cached loading error to avoid repeating expensive resolution attempts.
17832
16333
  *
17833
- * @private internal cache for `$provideBrowserForServer`
16334
+ * @private internal utility for USE BROWSER commitment
17834
16335
  */
17835
- let browserProvider = null;
16336
+ let cachedRunBrowserToolError = null;
17836
16337
  /**
17837
- * Provides a browser context for server-side operations, with caching to reuse instances.
17838
- *
17839
- * This function supports both local and remote browser connections based on environment configuration.
17840
- * Use REMOTE_BROWSER_URL environment variable to configure a remote Playwright server.
16338
+ * Attempts to load the server-side `run_browser` tool lazily.
17841
16339
  *
17842
- * @param options - Optional runtime request options used for cancellation and logging context.
17843
- * @returns Browser context instance
16340
+ * @returns Loaded `run_browser` implementation
16341
+ * @private internal utility for USE BROWSER commitment
17844
16342
  */
17845
- async function $provideBrowserForServer(options = {}) {
17846
- if (browserProvider === null) {
17847
- browserProvider = new BrowserConnectionProvider({ isVerbose: false });
16343
+ function loadRunBrowserToolForNode() {
16344
+ if (cachedRunBrowserTool !== null) {
16345
+ return cachedRunBrowserTool;
17848
16346
  }
17849
- return await browserProvider.getBrowserContext(options);
17850
- }
17851
- /**
17852
- * TODO: [🏓] Unite `xxxForServer` and `xxxForNode` naming
17853
- */
17854
-
17855
- /**
17856
- * Attempts to compute time-to-first-byte from Playwright response timing.
17857
- */
17858
- function resolveTimeToFirstByteMs(response) {
17859
- if (!response) {
17860
- return null;
16347
+ if (cachedRunBrowserToolError !== null) {
16348
+ throw cachedRunBrowserToolError;
17861
16349
  }
17862
16350
  try {
17863
- const timing = response.request().timing();
17864
- if (typeof (timing === null || timing === void 0 ? void 0 : timing.responseStart) === 'number' &&
17865
- typeof (timing === null || timing === void 0 ? void 0 : timing.startTime) === 'number' &&
17866
- timing.responseStart >= timing.startTime) {
17867
- return Math.round(timing.responseStart - timing.startTime);
17868
- }
17869
- }
17870
- catch (_a) {
17871
- return null;
17872
- }
17873
- return null;
17874
- }
17875
- /**
17876
- * Page open, action normalization and action execution helpers for `run_browser`.
17877
- *
17878
- * @private function of `run_browser`
17879
- */
17880
- const runBrowserWorkflow = {
17881
- /**
17882
- * Opens a new browser page and navigates to the requested URL.
17883
- */
17884
- async openPageWithUrl(options) {
17885
- runBrowserErrorHandling.assertNotAborted(options.signal, options.sessionId);
17886
- const connectStartedAt = Date.now();
17887
- const browserContext = await $provideBrowserForServer({
17888
- signal: options.signal,
17889
- sessionId: options.sessionId,
17890
- });
17891
- const connectDurationMs = Date.now() - connectStartedAt;
17892
- const page = await browserContext.newPage();
17893
- page.setDefaultNavigationTimeout(options.timeouts.navigationTimeoutMs);
17894
- page.setDefaultTimeout(options.timeouts.actionTimeoutMs);
17895
- const navigationStartedAt = Date.now();
17896
- try {
17897
- const navigationResponse = await page.goto(options.url, {
17898
- waitUntil: 'domcontentloaded',
17899
- timeout: options.timeouts.navigationTimeoutMs,
17900
- });
17901
- return {
17902
- page,
17903
- connectDurationMs,
17904
- initialNavigationDurationMs: Date.now() - navigationStartedAt,
17905
- timeToFirstByteMs: resolveTimeToFirstByteMs(navigationResponse),
17906
- };
17907
- }
17908
- catch (error) {
17909
- throw runBrowserErrorHandling.createRunBrowserNavigationError({
17910
- message: `Failed to navigate to \`${options.url}\`.`,
17911
- debug: {
17912
- phase: 'initial-navigation',
17913
- url: options.url,
17914
- navigationTimeoutMs: options.timeouts.navigationTimeoutMs,
17915
- },
17916
- cause: error,
17917
- });
17918
- }
17919
- },
17920
- /**
17921
- * Validates and normalizes browser actions received from the model.
17922
- */
17923
- normalizeActions(actions) {
17924
- if (!actions || actions.length === 0) {
17925
- return [];
17926
- }
17927
- return actions.map((action, index) => this.normalizeAction(action, index));
17928
- },
17929
- /**
17930
- * Validates and normalizes a single action.
17931
- */
17932
- normalizeAction(action, index) {
17933
- var _a, _b, _c;
17934
- switch (action.type) {
17935
- case 'navigate': {
17936
- const url = String(action.value || '').trim();
17937
- if (!url) {
17938
- throw runBrowserErrorHandling.createRunBrowserValidationError({
17939
- message: spaceTrim$1(`Action ${index + 1}: \`navigate\` requires non-empty \`value\` URL.`),
17940
- debug: {
17941
- actionIndex: index + 1,
17942
- actionType: action.type,
17943
- },
17944
- });
17945
- }
17946
- return { type: 'navigate', url };
17947
- }
17948
- case 'click': {
17949
- const selector = String(action.selector || '').trim();
17950
- if (!selector) {
17951
- throw runBrowserErrorHandling.createRunBrowserValidationError({
17952
- message: spaceTrim$1(`Action ${index + 1}: \`click\` requires non-empty \`selector\`.`),
17953
- debug: {
17954
- actionIndex: index + 1,
17955
- actionType: action.type,
17956
- },
17957
- });
17958
- }
17959
- return { type: 'click', selector };
17960
- }
17961
- case 'type': {
17962
- const selector = String(action.selector || '').trim();
17963
- if (!selector) {
17964
- throw runBrowserErrorHandling.createRunBrowserValidationError({
17965
- message: spaceTrim$1(`Action ${index + 1}: \`type\` requires non-empty \`selector\`.`),
17966
- debug: {
17967
- actionIndex: index + 1,
17968
- actionType: action.type,
17969
- },
17970
- });
17971
- }
17972
- const text = String((_a = action.value) !== null && _a !== void 0 ? _a : '');
17973
- return { type: 'type', selector, text };
17974
- }
17975
- case 'wait': {
17976
- const requestedValue = Number.parseInt(String((_b = action.value) !== null && _b !== void 0 ? _b : runBrowserConstants.defaultWaitMs), 10);
17977
- const milliseconds = Number.isFinite(requestedValue)
17978
- ? Math.min(Math.max(requestedValue, 1), runBrowserConstants.maxWaitMs)
17979
- : runBrowserConstants.defaultWaitMs;
17980
- return { type: 'wait', milliseconds };
17981
- }
17982
- case 'scroll': {
17983
- const requestedValue = Number.parseInt(String((_c = action.value) !== null && _c !== void 0 ? _c : runBrowserConstants.defaultScrollPixels), 10);
17984
- const pixels = Number.isFinite(requestedValue) ? requestedValue : runBrowserConstants.defaultScrollPixels;
17985
- const rawSelector = String(action.selector || '').trim();
17986
- return { type: 'scroll', selector: rawSelector || null, pixels };
17987
- }
17988
- }
17989
- },
17990
- /**
17991
- * Executes one normalized browser action on a Playwright page.
17992
- */
17993
- async executeAction(options) {
17994
- const { page, action, actionIndex, timeouts, signal } = options;
17995
- runBrowserErrorHandling.assertNotAborted(signal, `action-${actionIndex}`);
17996
- try {
17997
- switch (action.type) {
17998
- case 'navigate':
17999
- await page.goto(action.url, {
18000
- waitUntil: 'domcontentloaded',
18001
- timeout: timeouts.navigationTimeoutMs,
18002
- });
18003
- return;
18004
- case 'click':
18005
- await page.locator(action.selector).first().click({ timeout: timeouts.actionTimeoutMs });
18006
- return;
18007
- case 'type':
18008
- await page.locator(action.selector).first().fill(action.text, { timeout: timeouts.actionTimeoutMs });
18009
- return;
18010
- case 'wait':
18011
- if (action.milliseconds > timeouts.actionTimeoutMs) {
18012
- throw runBrowserErrorHandling.createRunBrowserActionError({
18013
- message: `Action ${actionIndex}: \`wait\` exceeds action timeout (${timeouts.actionTimeoutMs}ms).`,
18014
- debug: {
18015
- actionIndex,
18016
- action,
18017
- actionTimeoutMs: timeouts.actionTimeoutMs,
18018
- },
18019
- });
18020
- }
18021
- await page.waitForTimeout(action.milliseconds);
18022
- return;
18023
- case 'scroll':
18024
- if (action.selector) {
18025
- await page
18026
- .locator(action.selector)
18027
- .first()
18028
- .scrollIntoViewIfNeeded({ timeout: timeouts.actionTimeoutMs });
18029
- }
18030
- await page.mouse.wheel(0, action.pixels);
18031
- return;
18032
- }
18033
- }
18034
- catch (error) {
18035
- if (runBrowserErrorHandling.isTaggedRunBrowserError(error)) {
18036
- throw error;
18037
- }
18038
- if (action.type === 'navigate') {
18039
- throw runBrowserErrorHandling.createRunBrowserNavigationError({
18040
- message: `Action ${actionIndex}: failed to navigate to \`${action.url}\`.`,
18041
- debug: {
18042
- actionIndex,
18043
- action,
18044
- navigationTimeoutMs: timeouts.navigationTimeoutMs,
18045
- },
18046
- cause: error,
18047
- });
18048
- }
18049
- throw runBrowserErrorHandling.createRunBrowserActionError({
18050
- message: `Action ${actionIndex}: failed to execute \`${action.type}\`.`,
18051
- debug: {
18052
- actionIndex,
18053
- action,
18054
- actionTimeoutMs: timeouts.actionTimeoutMs,
18055
- },
18056
- cause: error,
18057
- });
18058
- }
18059
- },
18060
- };
18061
-
18062
- /**
18063
- * Summarizes one normalized browser action in user-facing language.
18064
- */
18065
- function formatRunBrowserActionSummary(action) {
18066
- switch (action.type) {
18067
- case 'navigate':
18068
- return `Navigate to ${action.url}`;
18069
- case 'click':
18070
- return `Click ${action.selector}`;
18071
- case 'type':
18072
- return `Type into ${action.selector}`;
18073
- case 'wait':
18074
- return `Wait ${action.milliseconds}ms`;
18075
- case 'scroll':
18076
- return action.selector ? `Scroll ${action.pixels}px in ${action.selector}` : `Scroll ${action.pixels}px on page`;
18077
- }
18078
- }
18079
- /**
18080
- * Emits one incremental browser-tool update when a hidden chat-progress listener is attached.
18081
- */
18082
- function emitRunBrowserProgress(args, update) {
18083
- emitToolCallProgressFromToolArgs(args, update);
18084
- }
18085
- /**
18086
- * Returns the current timestamp in the branded ISO-8601 format used by tool-call logs.
18087
- */
18088
- function createRunBrowserLogTimestamp() {
18089
- return new Date().toISOString();
18090
- }
18091
- /**
18092
- * Executes non-graphical fallback scraping.
18093
- */
18094
- async function runFallbackScrape(url) {
18095
- return await fetchUrlContent(url);
18096
- }
18097
- /**
18098
- * Runs interactive browser automation through Playwright.
18099
- *
18100
- * @param args Tool arguments provided by the model.
18101
- * @param internalOptions Optional runtime options for cancellation.
18102
- * @returns Markdown summary with structured playback payload.
18103
- */
18104
- async function run_browser(args, internalOptions = {}) {
18105
- runBrowserObservability.incrementTotalRuns();
18106
- const startedAt = Date.now();
18107
- const sessionId = runBrowserRuntime.createRunBrowserSessionId();
18108
- const initialUrl = String(args.url || '').trim();
18109
- const mode = runBrowserRuntime.resolveExecutionMode();
18110
- const timeoutConfiguration = runBrowserRuntime.resolveTimeoutConfiguration(args.timeouts);
18111
- let page = null;
18112
- let connectDurationMs = null;
18113
- let initialNavigationDurationMs = null;
18114
- let timeToFirstByteMs = null;
18115
- try {
18116
- if (!initialUrl) {
18117
- throw runBrowserErrorHandling.createRunBrowserValidationError({
18118
- message: 'Missing required `url` argument.',
18119
- debug: {
18120
- field: 'url',
18121
- },
18122
- });
18123
- }
18124
- const normalizedActions = runBrowserWorkflow.normalizeActions(args.actions);
18125
- runBrowserErrorHandling.assertNotAborted(internalOptions.signal, sessionId);
18126
- const openedPage = await runBrowserWorkflow.openPageWithUrl({
18127
- url: initialUrl,
18128
- sessionId,
18129
- timeouts: timeoutConfiguration,
18130
- signal: internalOptions.signal,
18131
- });
18132
- page = openedPage.page;
18133
- connectDurationMs = openedPage.connectDurationMs;
18134
- initialNavigationDurationMs = openedPage.initialNavigationDurationMs;
18135
- timeToFirstByteMs = openedPage.timeToFirstByteMs;
18136
- emitRunBrowserProgress(args, {
18137
- state: 'PARTIAL',
18138
- log: {
18139
- createdAt: createRunBrowserLogTimestamp(),
18140
- kind: 'browser-session',
18141
- title: 'Browser ready',
18142
- message: 'Opened the initial page and started the browser session.',
18143
- payload: {
18144
- sessionId,
18145
- initialUrl,
18146
- connectDurationMs,
18147
- initialNavigationDurationMs,
18148
- timeToFirstByteMs,
18149
- },
18150
- },
18151
- });
18152
- const artifacts = [];
18153
- const initialArtifact = await runBrowserArtifacts.captureSnapshotArtifact({
18154
- page,
18155
- sessionId,
18156
- label: 'Initial page',
18157
- fileSuffix: 'initial',
18158
- });
18159
- if (initialArtifact) {
18160
- artifacts.push(initialArtifact);
18161
- }
18162
- for (const [index, action] of normalizedActions.entries()) {
18163
- runBrowserErrorHandling.assertNotAborted(internalOptions.signal, sessionId);
18164
- emitRunBrowserProgress(args, {
18165
- state: 'PARTIAL',
18166
- log: {
18167
- createdAt: createRunBrowserLogTimestamp(),
18168
- kind: 'browser-action',
18169
- title: `Action ${index + 1} running`,
18170
- message: formatRunBrowserActionSummary(action),
18171
- payload: {
18172
- actionIndex: index + 1,
18173
- action,
18174
- phase: 'running',
18175
- },
18176
- },
18177
- });
18178
- await runBrowserWorkflow.executeAction({
18179
- page,
18180
- action,
18181
- actionIndex: index + 1,
18182
- timeouts: timeoutConfiguration,
18183
- signal: internalOptions.signal,
18184
- });
18185
- emitRunBrowserProgress(args, {
18186
- state: 'PARTIAL',
18187
- log: {
18188
- createdAt: createRunBrowserLogTimestamp(),
18189
- kind: 'browser-action',
18190
- title: `Action ${index + 1} finished`,
18191
- message: formatRunBrowserActionSummary(action),
18192
- payload: {
18193
- actionIndex: index + 1,
18194
- action,
18195
- phase: 'complete',
18196
- },
18197
- },
18198
- });
18199
- const actionArtifact = await runBrowserArtifacts.captureSnapshotArtifact({
18200
- page,
18201
- sessionId,
18202
- label: `After action ${index + 1}`,
18203
- fileSuffix: `action-${String(index + 1).padStart(3, '0')}-${action.type}`,
18204
- actionIndex: index + 1,
18205
- action,
18206
- });
18207
- if (actionArtifact) {
18208
- artifacts.push(actionArtifact);
18209
- }
18210
- }
18211
- const snapshotPath = await runBrowserArtifacts.captureSnapshot(page, sessionId);
18212
- const finalUrl = page.url();
18213
- const finalTitle = await runBrowserArtifacts.getPageTitle(page);
18214
- if (snapshotPath) {
18215
- artifacts.push({
18216
- kind: 'screenshot',
18217
- label: 'Final page',
18218
- path: snapshotPath,
18219
- capturedAt: new Date().toISOString(),
18220
- url: finalUrl,
18221
- title: finalTitle,
18222
- });
16351
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
16352
+ const runBrowserModule = require('../../../apps/agents-server/src/tools/run_browser');
16353
+ if (typeof runBrowserModule.run_browser !== 'function') {
16354
+ throw new Error('run_browser value is not a function but ' + typeof runBrowserModule.run_browser);
18223
16355
  }
18224
- const payload = runBrowserResultFormatting.createResultPayload({
18225
- sessionId,
18226
- mode,
18227
- modeUsed: 'remote-browser',
18228
- initialUrl,
18229
- finalUrl,
18230
- finalTitle,
18231
- executedActions: normalizedActions,
18232
- artifacts,
18233
- warning: null,
18234
- error: null,
18235
- fallbackContent: null,
18236
- timing: {
18237
- connectDurationMs,
18238
- initialNavigationDurationMs,
18239
- timeToFirstByteMs,
18240
- totalDurationMs: Date.now() - startedAt,
18241
- },
18242
- });
18243
- runBrowserObservability.logRunBrowserMetric({
18244
- event: 'run_browser_success',
18245
- sessionId,
18246
- mode: 'remote-browser',
18247
- payload: {
18248
- actions: normalizedActions.length,
18249
- connectDurationMs,
18250
- initialNavigationDurationMs,
18251
- timeToFirstByteMs,
18252
- },
18253
- });
18254
- return runBrowserResultFormatting.formatSuccessResult({
18255
- payload,
18256
- snapshotPath,
18257
- });
16356
+ cachedRunBrowserTool = runBrowserModule.run_browser;
16357
+ return cachedRunBrowserTool;
18258
16358
  }
18259
16359
  catch (error) {
18260
- const toolError = runBrowserErrorHandling.classifyRunBrowserToolError({
18261
- error,
18262
- sessionId,
18263
- mode,
18264
- });
18265
- const errorCodeCount = runBrowserObservability.incrementRunBrowserErrorCodeCounter(toolError.code);
18266
- if (runBrowserErrorHandling.isRemoteBrowserUnavailableCode(toolError.code) && initialUrl) {
18267
- const fallbackContent = await runFallbackScrape(initialUrl);
18268
- const { fallbackRuns, fallbackRate } = runBrowserObservability.incrementFallbackRunsAndGetMetrics();
18269
- emitRunBrowserProgress(args, {
18270
- state: 'PARTIAL',
18271
- log: {
18272
- createdAt: createRunBrowserLogTimestamp(),
18273
- kind: 'warning',
18274
- level: 'warning',
18275
- title: 'Fallback enabled',
18276
- message: 'Remote browser was unavailable, so fallback scraping was used instead.',
18277
- payload: {
18278
- errorCode: toolError.code,
18279
- initialUrl,
18280
- },
18281
- },
18282
- });
18283
- const payload = runBrowserResultFormatting.createResultPayload({
18284
- sessionId,
18285
- mode,
18286
- modeUsed: 'fallback',
18287
- initialUrl,
18288
- finalUrl: null,
18289
- finalTitle: null,
18290
- executedActions: [],
18291
- artifacts: [],
18292
- warning: runBrowserConstants.fallbackDynamicContentWarning,
18293
- error: toolError,
18294
- fallbackContent,
18295
- timing: {
18296
- connectDurationMs,
18297
- initialNavigationDurationMs,
18298
- timeToFirstByteMs,
18299
- totalDurationMs: Date.now() - startedAt,
18300
- },
18301
- });
18302
- runBrowserObservability.logRunBrowserMetric({
18303
- event: 'run_browser_fallback_used',
18304
- sessionId,
18305
- mode: 'fallback',
18306
- payload: {
18307
- errorCode: toolError.code,
18308
- errorCodeCount,
18309
- fallbackRuns,
18310
- totalRuns: runBrowserObservability.getTotalRuns(),
18311
- fallbackRate,
18312
- },
18313
- });
18314
- return runBrowserResultFormatting.formatFallbackResult({
18315
- payload,
18316
- fallbackContent,
18317
- requestedActions: Array.isArray(args.actions) ? args.actions.length : 0,
18318
- });
18319
- }
18320
- emitRunBrowserProgress(args, {
18321
- state: 'ERROR',
18322
- log: {
18323
- createdAt: createRunBrowserLogTimestamp(),
18324
- kind: 'error',
18325
- level: 'error',
18326
- title: 'Browser run failed',
18327
- message: toolError.message,
18328
- payload: {
18329
- code: toolError.code,
18330
- debug: toolError.debug,
18331
- },
18332
- },
18333
- });
18334
- const payload = runBrowserResultFormatting.createResultPayload({
18335
- sessionId,
18336
- mode,
18337
- modeUsed: 'remote-browser',
18338
- initialUrl,
18339
- finalUrl: page ? page.url() : null,
18340
- finalTitle: page ? await runBrowserArtifacts.getPageTitle(page) : null,
18341
- executedActions: [],
18342
- artifacts: [],
18343
- warning: null,
18344
- error: toolError,
18345
- fallbackContent: null,
18346
- timing: {
18347
- connectDurationMs,
18348
- initialNavigationDurationMs,
18349
- timeToFirstByteMs,
18350
- totalDurationMs: Date.now() - startedAt,
18351
- },
18352
- });
18353
- runBrowserObservability.logRunBrowserMetric({
18354
- event: 'run_browser_failed',
18355
- sessionId,
18356
- mode: 'remote-browser',
18357
- payload: {
18358
- errorCode: toolError.code,
18359
- errorCodeCount,
18360
- connectDurationMs,
18361
- initialNavigationDurationMs,
18362
- timeToFirstByteMs,
18363
- },
18364
- });
18365
- return runBrowserResultFormatting.formatErrorResult({
18366
- payload,
18367
- });
18368
- }
18369
- finally {
18370
- await runBrowserArtifacts.cleanupPage(page, sessionId);
16360
+ assertsError(error);
16361
+ cachedRunBrowserToolError = error;
16362
+ throw error;
18371
16363
  }
18372
16364
  }
18373
-
18374
16365
  /**
18375
16366
  * Resolves the server-side implementation of the `run_browser` tool for Node.js environments.
18376
16367
  *
18377
- * This uses lazy `require` to keep the core package decoupled from Agents Server internals.
16368
+ * This uses fully lazy resolution to keep CLI startup independent from optional browser tooling.
18378
16369
  * When the server tool cannot be resolved, the fallback implementation throws a helpful error.
18379
16370
  *
18380
16371
  * @private internal utility for USE BROWSER commitment
18381
16372
  */
18382
16373
  function resolveRunBrowserToolForNode() {
18383
- try {
18384
- // eslint-disable-next-line @typescript-eslint/no-var-requires
18385
- // const { run_browser } = require('../../../apps/agents-server/src/tools/run_browser');
18386
- if (typeof run_browser !== 'function') {
18387
- throw new Error('run_browser value is not a function but ' + typeof run_browser);
16374
+ return async (args) => {
16375
+ try {
16376
+ const runBrowserTool = loadRunBrowserToolForNode();
16377
+ return await runBrowserTool(args);
18388
16378
  }
18389
- return run_browser;
18390
- }
18391
- catch (error) {
18392
- assertsError(error);
18393
- return async () => {
16379
+ catch (error) {
16380
+ assertsError(error);
18394
16381
  throw new EnvironmentMismatchError(spaceTrim$1((block) => `
18395
16382
  \`run_browser\` tool is not available in this environment.
18396
16383
  This commitment requires the Agents Server browser runtime with Playwright CLI.
@@ -18398,8 +16385,8 @@ function resolveRunBrowserToolForNode() {
18398
16385
  ${error.name}:
18399
16386
  ${block(error.message)}
18400
16387
  `));
18401
- };
18402
- }
16388
+ }
16389
+ };
18403
16390
  }
18404
16391
 
18405
16392
  /**
@@ -20234,6 +18221,110 @@ const parseMemoryToolArgs = {
20234
18221
  },
20235
18222
  };
20236
18223
 
18224
+ /**
18225
+ * Prompt parameter key used to pass hidden runtime context to tool execution.
18226
+ *
18227
+ * @private internal runtime wiring for commitment tools
18228
+ */
18229
+ const TOOL_RUNTIME_CONTEXT_PARAMETER = 'promptbookToolRuntimeContext';
18230
+ /**
18231
+ * Hidden argument key used to pass runtime context into individual tool calls.
18232
+ *
18233
+ * @private internal runtime wiring for commitment tools
18234
+ */
18235
+ const TOOL_RUNTIME_CONTEXT_ARGUMENT = '__promptbookToolRuntimeContext';
18236
+ /**
18237
+ * Prompt parameter key used to pass a hidden tool-progress listener token into script execution.
18238
+ *
18239
+ * @private internal runtime wiring for commitment tools
18240
+ */
18241
+ const TOOL_PROGRESS_TOKEN_PARAMETER = 'promptbookToolProgressToken';
18242
+ /**
18243
+ * Hidden argument key used to pass a tool-progress listener token into individual tool calls.
18244
+ *
18245
+ * @private internal runtime wiring for commitment tools
18246
+ */
18247
+ const TOOL_PROGRESS_TOKEN_ARGUMENT = '__promptbookToolProgressToken';
18248
+ /**
18249
+ * Monotonic counter used for hidden progress-listener tokens.
18250
+ *
18251
+ * @private internal runtime wiring for commitment tools
18252
+ */
18253
+ let toolCallProgressListenerCounter = 0;
18254
+ /**
18255
+ * Active tool-progress listeners keyed by hidden execution token.
18256
+ *
18257
+ * @private internal runtime wiring for commitment tools
18258
+ */
18259
+ const toolCallProgressListeners = new Map();
18260
+ /**
18261
+ * Parses unknown runtime context payload into a normalized object.
18262
+ *
18263
+ * @private internal runtime wiring for commitment tools
18264
+ */
18265
+ function parseToolRuntimeContext(rawValue) {
18266
+ if (!rawValue) {
18267
+ return null;
18268
+ }
18269
+ let parsed = rawValue;
18270
+ if (typeof rawValue === 'string') {
18271
+ try {
18272
+ parsed = JSON.parse(rawValue);
18273
+ }
18274
+ catch (_a) {
18275
+ return null;
18276
+ }
18277
+ }
18278
+ if (!parsed || typeof parsed !== 'object') {
18279
+ return null;
18280
+ }
18281
+ return parsed;
18282
+ }
18283
+ /**
18284
+ * Reads runtime context attached to tool call arguments.
18285
+ *
18286
+ * @private internal runtime wiring for commitment tools
18287
+ */
18288
+ function readToolRuntimeContextFromToolArgs(args) {
18289
+ return parseToolRuntimeContext(args[TOOL_RUNTIME_CONTEXT_ARGUMENT]);
18290
+ }
18291
+ /**
18292
+ * Serializes runtime context for prompt parameters.
18293
+ *
18294
+ * @private internal runtime wiring for commitment tools
18295
+ */
18296
+ function serializeToolRuntimeContext(context) {
18297
+ return JSON.stringify(context);
18298
+ }
18299
+ /**
18300
+ * Registers one in-memory listener that receives progress updates emitted by a running tool.
18301
+ *
18302
+ * The returned token is passed into script execution as a hidden argument so tool implementations
18303
+ * can stream progress without exposing extra parameters to the model.
18304
+ *
18305
+ * @param listener - Listener notified about tool progress.
18306
+ * @returns Hidden token used to route progress updates.
18307
+ * @private internal runtime wiring for commitment tools
18308
+ */
18309
+ function registerToolCallProgressListener(listener) {
18310
+ toolCallProgressListenerCounter += 1;
18311
+ const token = `tool-progress:${Date.now()}:${toolCallProgressListenerCounter}`;
18312
+ toolCallProgressListeners.set(token, listener);
18313
+ return token;
18314
+ }
18315
+ /**
18316
+ * Unregisters one in-memory progress listener.
18317
+ *
18318
+ * @param token - Token previously created by `registerToolCallProgressListener`.
18319
+ * @private internal runtime wiring for commitment tools
18320
+ */
18321
+ function unregisterToolCallProgressListener(token) {
18322
+ toolCallProgressListeners.delete(token);
18323
+ }
18324
+ /**
18325
+ * Note: [💞] Ignore a discrepancy between file name and entity name
18326
+ */
18327
+
20237
18328
  /**
20238
18329
  * Resolves runtime context from hidden tool arguments.
20239
18330
  *
@@ -27942,9 +26033,9 @@ function createTimeoutSystemMessage(extraInstructions) {
27942
26033
  return spaceTrim$1((block) => `
27943
26034
  Timeout scheduling:
27944
26035
  - Use "set_timeout" to wake this same chat thread in the future.
27945
- - Timers are thread-scoped, not global for the whole agent.
26036
+ - Use "list_timeouts" to review timeouts across all chats for the same user+agent scope.
26037
+ - "cancel_timeout" accepts a timeout id from any chat in this same user+agent scope.
27946
26038
  - When one timeout elapses, you will receive a new user-like message that explicitly says it is a timeout wake-up and includes the \`timeoutId\`.
27947
- - Use "cancel_timeout" when a previously scheduled timeout is no longer relevant.
27948
26039
  - Do not claim a timer was set or cancelled unless the tool confirms it.
27949
26040
  ${block(extraInstructions)}
27950
26041
  `);
@@ -28005,13 +26096,6 @@ function parseToolExecutionEnvelope(rawValue) {
28005
26096
  * @private internal utility of USE TIMEOUT
28006
26097
  */
28007
26098
  function createDisabledTimeoutResult(action, message) {
28008
- if (action === 'set') {
28009
- return {
28010
- action,
28011
- status: 'disabled',
28012
- message,
28013
- };
28014
- }
28015
26099
  return {
28016
26100
  action,
28017
26101
  status: 'disabled',
@@ -28038,6 +26122,18 @@ function getTimeoutToolRuntimeAdapterOrDisabledResult(action, runtimeContext) {
28038
26122
  }
28039
26123
  }
28040
26124
 
26125
+ /**
26126
+ * Default number of rows returned by `list_timeouts`.
26127
+ *
26128
+ * @private internal USE TIMEOUT constant
26129
+ */
26130
+ const DEFAULT_LIST_TIMEOUTS_LIMIT = 20;
26131
+ /**
26132
+ * Hard cap for `list_timeouts` page size.
26133
+ *
26134
+ * @private internal USE TIMEOUT constant
26135
+ */
26136
+ const MAX_LIST_TIMEOUTS_LIMIT = 100;
28041
26137
  /**
28042
26138
  * Parses and validates `USE TIMEOUT` tool arguments.
28043
26139
  *
@@ -28072,6 +26168,31 @@ const parseTimeoutToolArgs = {
28072
26168
  }
28073
26169
  return { timeoutId };
28074
26170
  },
26171
+ /**
26172
+ * Parses `list_timeouts` input.
26173
+ */
26174
+ list(args) {
26175
+ if (args.includeFinished !== undefined && typeof args.includeFinished !== 'boolean') {
26176
+ throw new PipelineExecutionError(spaceTrim$1(`
26177
+ Timeout \`includeFinished\` must be a boolean when provided.
26178
+ `));
26179
+ }
26180
+ const parsedLimit = args.limit === undefined ? DEFAULT_LIST_TIMEOUTS_LIMIT : Math.floor(Number(args.limit));
26181
+ if (!Number.isFinite(parsedLimit) || parsedLimit <= 0) {
26182
+ throw new PipelineExecutionError(spaceTrim$1(`
26183
+ Timeout \`limit\` must be a positive number.
26184
+ `));
26185
+ }
26186
+ if (parsedLimit > MAX_LIST_TIMEOUTS_LIMIT) {
26187
+ throw new PipelineExecutionError(spaceTrim$1(`
26188
+ Timeout \`limit\` must be at most \`${MAX_LIST_TIMEOUTS_LIMIT}\`.
26189
+ `));
26190
+ }
26191
+ return {
26192
+ includeFinished: args.includeFinished === true,
26193
+ limit: parsedLimit,
26194
+ };
26195
+ },
28075
26196
  };
28076
26197
 
28077
26198
  /**
@@ -28082,6 +26203,7 @@ const parseTimeoutToolArgs = {
28082
26203
  const TimeoutToolNames = {
28083
26204
  set: 'set_timeout',
28084
26205
  cancel: 'cancel_timeout',
26206
+ list: 'list_timeouts',
28085
26207
  };
28086
26208
 
28087
26209
  /**
@@ -28181,6 +26303,35 @@ function createTimeoutToolFunctions() {
28181
26303
  return JSON.stringify(result);
28182
26304
  }
28183
26305
  },
26306
+ async [TimeoutToolNames.list](args) {
26307
+ const runtimeContext = resolveTimeoutRuntimeContext(args);
26308
+ const { adapter, disabledResult } = getTimeoutToolRuntimeAdapterOrDisabledResult('list', runtimeContext);
26309
+ if (!adapter || disabledResult) {
26310
+ return JSON.stringify(disabledResult);
26311
+ }
26312
+ try {
26313
+ const parsedArgs = parseTimeoutToolArgs.list(args);
26314
+ const listedTimeouts = await adapter.listTimeouts(parsedArgs, runtimeContext);
26315
+ const result = {
26316
+ action: 'list',
26317
+ status: 'listed',
26318
+ items: listedTimeouts.items,
26319
+ total: listedTimeouts.total,
26320
+ };
26321
+ return createToolExecutionEnvelope({
26322
+ assistantMessage: listedTimeouts.total === 1 ? 'Found 1 timeout.' : `Found ${listedTimeouts.total} timeouts.`,
26323
+ toolResult: result,
26324
+ });
26325
+ }
26326
+ catch (error) {
26327
+ const result = {
26328
+ action: 'list',
26329
+ status: 'error',
26330
+ message: error instanceof Error ? error.message : String(error),
26331
+ };
26332
+ return JSON.stringify(result);
26333
+ }
26334
+ },
28184
26335
  };
28185
26336
  }
28186
26337
 
@@ -28214,26 +26365,45 @@ function createTimeoutTools(existingTools = []) {
28214
26365
  if (!tools.some((tool) => tool.name === TimeoutToolNames.cancel)) {
28215
26366
  tools.push({
28216
26367
  name: TimeoutToolNames.cancel,
28217
- description: 'Cancel one previously scheduled timeout in the current chat thread.',
26368
+ description: 'Cancel one previously scheduled timeout within the same user+agent scope, even if it was set in another chat.',
28218
26369
  parameters: {
28219
26370
  type: 'object',
28220
26371
  properties: {
28221
26372
  timeoutId: {
28222
26373
  type: 'string',
28223
- description: 'Identifier returned earlier by `set_timeout`.',
26374
+ description: 'Identifier returned earlier by `set_timeout` or `list_timeouts`.',
28224
26375
  },
28225
26376
  },
28226
26377
  required: ['timeoutId'],
28227
26378
  },
28228
26379
  });
28229
26380
  }
26381
+ if (!tools.some((tool) => tool.name === TimeoutToolNames.list)) {
26382
+ tools.push({
26383
+ name: TimeoutToolNames.list,
26384
+ description: 'List scheduled timeouts across all chats for this same user+agent scope so they can be reviewed or cancelled.',
26385
+ parameters: {
26386
+ type: 'object',
26387
+ properties: {
26388
+ includeFinished: {
26389
+ type: 'boolean',
26390
+ description: 'When true, include completed, failed, and cancelled rows in addition to active timeouts.',
26391
+ },
26392
+ limit: {
26393
+ type: 'number',
26394
+ description: 'Maximum number of rows to return (default 20, max 100).',
26395
+ },
26396
+ },
26397
+ },
26398
+ });
26399
+ }
28230
26400
  return tools;
28231
26401
  }
28232
26402
 
28233
26403
  /**
28234
26404
  * `USE TIMEOUT` commitment definition.
28235
26405
  *
28236
- * The `USE TIMEOUT` commitment enables thread-scoped timers that wake the same chat later.
26406
+ * The `USE TIMEOUT` commitment enables timeout wake-ups and scoped timeout management.
28237
26407
  *
28238
26408
  * @private [🪔] Maybe export the commitments through some package
28239
26409
  */
@@ -28248,7 +26418,7 @@ class UseTimeoutCommitmentDefinition extends BaseCommitmentDefinition {
28248
26418
  * Short one-line description of `USE TIMEOUT`.
28249
26419
  */
28250
26420
  get description() {
28251
- return 'Enable thread-scoped timers that can wake the same chat in the future.';
26421
+ return 'Enable timeout wake-ups plus scoped timeout listing/cancellation across chats.';
28252
26422
  }
28253
26423
  /**
28254
26424
  * Icon for this commitment.
@@ -28263,14 +26433,15 @@ class UseTimeoutCommitmentDefinition extends BaseCommitmentDefinition {
28263
26433
  return spaceTrim$1(`
28264
26434
  # USE TIMEOUT
28265
26435
 
28266
- Enables the agent to schedule thread-scoped timeout wake-ups.
26436
+ Enables timeout wake-ups and timeout management for the same user+agent scope.
28267
26437
 
28268
26438
  ## Key aspects
28269
26439
 
28270
26440
  - The agent uses \`set_timeout\` to schedule a future wake-up in the same chat thread.
28271
26441
  - The tool returns immediately while the timeout is stored and executed by the runtime later.
28272
26442
  - The wake-up arrives as a new user-like timeout message in the same conversation.
28273
- - The agent can cancel an existing timeout by \`timeoutId\` via \`cancel_timeout\`.
26443
+ - The agent can inspect known timeouts via \`list_timeouts\`.
26444
+ - The agent can cancel an existing timeout by \`timeoutId\` via \`cancel_timeout\`, including timeouts created in another chat.
28274
26445
  - Commitment content is treated as optional timeout policy instructions.
28275
26446
 
28276
26447
  ## Examples
@@ -28299,6 +26470,7 @@ class UseTimeoutCommitmentDefinition extends BaseCommitmentDefinition {
28299
26470
  return {
28300
26471
  [TimeoutToolNames.set]: 'Set timer',
28301
26472
  [TimeoutToolNames.cancel]: 'Cancel timer',
26473
+ [TimeoutToolNames.list]: 'List timers',
28302
26474
  };
28303
26475
  }
28304
26476
  /**
@@ -29230,7 +27402,7 @@ class JavascriptEvalExecutionTools {
29230
27402
  }
29231
27403
  // Note: [💎]
29232
27404
  // Note: Using direct eval, following variables are in same scope as eval call so they are accessible from inside the evaluated script:
29233
- const spaceTrim = (_) => spaceTrim$2(_);
27405
+ const spaceTrim = (_) => _spaceTrim(_);
29234
27406
  $preserve(spaceTrim);
29235
27407
  const removeQuotes$1 = removeQuotes;
29236
27408
  $preserve(removeQuotes$1);
@@ -29321,7 +27493,7 @@ class JavascriptEvalExecutionTools {
29321
27493
  .join('\n');
29322
27494
  // script = templateParameters(script, parameters);
29323
27495
  // <- TODO: [🧠][🥳] Should be this is one of two variants how to use parameters in script
29324
- const statementToEvaluate = spaceTrim$2((block) => `
27496
+ const statementToEvaluate = _spaceTrim((block) => `
29325
27497
 
29326
27498
  // Build-in functions:
29327
27499
  ${block(buildinFunctionsStatement)}
@@ -29336,7 +27508,7 @@ class JavascriptEvalExecutionTools {
29336
27508
  (async ()=>{ ${script} })()
29337
27509
  `);
29338
27510
  if (this.options.isVerbose) {
29339
- console.info(spaceTrim$2((block) => `
27511
+ console.info(_spaceTrim((block) => `
29340
27512
  🚀 Evaluating ${scriptLanguage} script:
29341
27513
 
29342
27514
  ${block(statementToEvaluate)}`));
@@ -29345,7 +27517,7 @@ class JavascriptEvalExecutionTools {
29345
27517
  try {
29346
27518
  result = await eval(statementToEvaluate);
29347
27519
  if (this.options.isVerbose) {
29348
- console.info(spaceTrim$2((block) => `
27520
+ console.info(_spaceTrim((block) => `
29349
27521
  🚀 Script evaluated successfully, result:
29350
27522
  ${block(valueToString(result))}
29351
27523
  `));
@@ -29364,7 +27536,7 @@ class JavascriptEvalExecutionTools {
29364
27536
  To: [PipelineExecutionError: Parameter `{thing}` is not defined],
29365
27537
  */
29366
27538
  if (!statementToEvaluate.includes(undefinedName + '(')) {
29367
- throw new PipelineExecutionError(spaceTrim$2((block) => `
27539
+ throw new PipelineExecutionError(_spaceTrim((block) => `
29368
27540
 
29369
27541
  Parameter \`{${undefinedName}}\` is not defined
29370
27542
 
@@ -29386,7 +27558,7 @@ class JavascriptEvalExecutionTools {
29386
27558
  `));
29387
27559
  }
29388
27560
  else {
29389
- throw new PipelineExecutionError(spaceTrim$2((block) => `
27561
+ throw new PipelineExecutionError(_spaceTrim((block) => `
29390
27562
  Function ${undefinedName}() is not defined
29391
27563
 
29392
27564
  - Make sure that the function is one of built-in functions
@@ -29639,7 +27811,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
29639
27811
  catch (error) {
29640
27812
  assertsError(error);
29641
27813
  // TODO: [7] DRY
29642
- const wrappedErrorMessage = spaceTrim$2((block) => `
27814
+ const wrappedErrorMessage = spaceTrim$1((block) => `
29643
27815
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
29644
27816
 
29645
27817
  Original error message:
@@ -29674,7 +27846,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
29674
27846
  pipeline = { ...pipeline, pipelineUrl };
29675
27847
  }
29676
27848
  else if (!pipeline.pipelineUrl.startsWith(rootUrl)) {
29677
- throw new PipelineUrlError(spaceTrim$2(`
27849
+ throw new PipelineUrlError(spaceTrim$1(`
29678
27850
  Pipeline with URL ${pipeline.pipelineUrl} is not a child of the root URL ${rootUrl} 🍏
29679
27851
 
29680
27852
  File:
@@ -29712,7 +27884,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
29712
27884
  }
29713
27885
  else {
29714
27886
  const existing = collection.get(pipeline.pipelineUrl);
29715
- throw new PipelineUrlError(spaceTrim$2(`
27887
+ throw new PipelineUrlError(spaceTrim$1(`
29716
27888
  Pipeline with URL ${pipeline.pipelineUrl} is already in the collection 🍏
29717
27889
 
29718
27890
  Conflicting files:
@@ -29730,7 +27902,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
29730
27902
  catch (error) {
29731
27903
  assertsError(error);
29732
27904
  // TODO: [7] DRY
29733
- const wrappedErrorMessage = spaceTrim$2((block) => `
27905
+ const wrappedErrorMessage = spaceTrim$1((block) => `
29734
27906
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
29735
27907
 
29736
27908
  Original error message:
@@ -29865,7 +28037,7 @@ function usageToHuman(usage) {
29865
28037
  // Note: For negligible usage, we report at least something
29866
28038
  reportItems.push('Negligible');
29867
28039
  }
29868
- return spaceTrim$2((block) => `
28040
+ return spaceTrim$1((block) => `
29869
28041
  Usage:
29870
28042
  ${block(reportItems.map((item) => `- ${item}`).join('\n'))}
29871
28043
  `);
@@ -29905,7 +28077,7 @@ async function $provideScriptingForNode(options) {
29905
28077
  */
29906
28078
  function $initializeMakeCommand(program) {
29907
28079
  const makeCommand = program.command('make');
29908
- makeCommand.description(spaceTrim$2(`
28080
+ makeCommand.description(spaceTrim$1(`
29909
28081
  Makes a new pipeline collection in given folder
29910
28082
  `));
29911
28083
  makeCommand.alias('compile');
@@ -29917,7 +28089,7 @@ function $initializeMakeCommand(program) {
29917
28089
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
29918
28090
  makeCommand.option('--project-name', `Name of the project for whom collection is`, 'Untitled Promptbook project');
29919
28091
  makeCommand.option('--root-url <url>', `Root URL of all pipelines to make`, undefined);
29920
- makeCommand.option('-f, --format <format>', spaceTrim$2(`
28092
+ makeCommand.option('-f, --format <format>', spaceTrim$1(`
29921
28093
  Output format of builded collection "bookc", "javascript", "typescript" or "json"
29922
28094
 
29923
28095
  Note: You can use multiple formats separated by comma
@@ -29925,14 +28097,14 @@ function $initializeMakeCommand(program) {
29925
28097
  makeCommand.option('--no-validation', `Do not validate logic of pipelines in collection`, true);
29926
28098
  makeCommand.option('--validation', `Types of validations separated by comma (options "logic","imports")`, 'logic,imports');
29927
28099
  makeCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
29928
- makeCommand.option('-o, --output <path>', spaceTrim$2(`
28100
+ makeCommand.option('-o, --output <path>', spaceTrim$1(`
29929
28101
  Where to save the builded collection
29930
28102
 
29931
28103
  Note: If you keep it "${DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME}" it will be saved in the root of the promptbook directory
29932
28104
  If you set it to a path, it will be saved in that path
29933
28105
  BUT you can use only one format and set correct extension
29934
28106
  `), DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME);
29935
- makeCommand.option('-fn, --function-name <functionName>', spaceTrim$2(`
28107
+ makeCommand.option('-fn, --function-name <functionName>', spaceTrim$1(`
29936
28108
  Name of the function to get pipeline collection
29937
28109
 
29938
28110
  Note: This can be used only with "javascript" or "typescript" format
@@ -30015,7 +28187,7 @@ function $initializeMakeCommand(program) {
30015
28187
  if (lastChar !== ']') {
30016
28188
  throw new UnexpectedError(`Last character of serialized collection should be "]" not "${lastChar}"`);
30017
28189
  }
30018
- return spaceTrim$2(collectionJsonString.substring(1, collectionJsonString.length - 1));
28190
+ return spaceTrim$1(collectionJsonString.substring(1, collectionJsonString.length - 1));
30019
28191
  })();
30020
28192
  const saveFile = async (extension, content) => {
30021
28193
  const filename = output !== DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME
@@ -30046,7 +28218,7 @@ function $initializeMakeCommand(program) {
30046
28218
  }
30047
28219
  if (formats.includes('javascript') || formats.includes('js')) {
30048
28220
  formats = formats.filter((format) => format !== 'javascript' && format !== 'js');
30049
- (await saveFile('js', spaceTrim$2((block) => `
28221
+ (await saveFile('js', spaceTrim$1((block) => `
30050
28222
  // ${block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI)}
30051
28223
 
30052
28224
  import { createPipelineCollectionFromJson } from '@promptbook/core';
@@ -30083,7 +28255,7 @@ function $initializeMakeCommand(program) {
30083
28255
  }
30084
28256
  if (formats.includes('typescript') || formats.includes('ts')) {
30085
28257
  formats = formats.filter((format) => format !== 'typescript' && format !== 'ts');
30086
- await saveFile('ts', spaceTrim$2((block) => `
28258
+ await saveFile('ts', spaceTrim$1((block) => `
30087
28259
  // ${block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI)}
30088
28260
 
30089
28261
  import { createPipelineCollectionFromJson } from '@promptbook/core';
@@ -30228,7 +28400,7 @@ async function prettifyPipelineString(pipelineString, options) {
30228
28400
  */
30229
28401
  function $initializePrettifyCommand(program) {
30230
28402
  const prettifyCommand = program.command('prettify');
30231
- prettifyCommand.description(spaceTrim$2(`
28403
+ prettifyCommand.description(spaceTrim$1(`
30232
28404
  Iterates over \`.book.md\` files and does multiple enhancing operations on them:
30233
28405
 
30234
28406
  1) Adds Mermaid graph
@@ -30684,7 +28856,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
30684
28856
  // console.log(`Strategy 3️⃣`);
30685
28857
  const response = await fetch(pipelineSource);
30686
28858
  if (response.status >= 300) {
30687
- throw new NotFoundError(spaceTrim$2((block) => `
28859
+ throw new NotFoundError(spaceTrim$1((block) => `
30688
28860
  Book not found on URL:
30689
28861
  ${block(pipelineSource)}
30690
28862
 
@@ -30694,7 +28866,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
30694
28866
  const pipelineString = await response.text();
30695
28867
  // console.log({ pipelineString });
30696
28868
  if (!isValidPipelineString(pipelineString)) {
30697
- throw new NotFoundError(spaceTrim$2((block) => `
28869
+ throw new NotFoundError(spaceTrim$1((block) => `
30698
28870
  Book not found on URL:
30699
28871
  ${block(pipelineSource)}
30700
28872
 
@@ -30716,7 +28888,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
30716
28888
  });
30717
28889
  return pipelineJson;
30718
28890
  } /* not else */
30719
- throw new NotFoundError(spaceTrim$2((block) => `
28891
+ throw new NotFoundError(spaceTrim$1((block) => `
30720
28892
  Book not found:
30721
28893
  ${block(pipelineSource)}
30722
28894
 
@@ -30763,7 +28935,7 @@ async function runInteractiveChatbot(options) {
30763
28935
  const initialMessage = (((_a = pipeline.parameters.find(({ name }) => name === 'chatbotResponse')) === null || _a === void 0 ? void 0 : _a.exampleValues) || [])[0];
30764
28936
  if (initialMessage) {
30765
28937
  console.info(`\n`);
30766
- console.info(spaceTrim$2((block) => `
28938
+ console.info(spaceTrim$1((block) => `
30767
28939
 
30768
28940
  ${colors.bold(colors.green('Chatbot:'))}
30769
28941
  ${block(colors.green(initialMessage))}
@@ -30786,7 +28958,7 @@ async function runInteractiveChatbot(options) {
30786
28958
  type: 'text',
30787
28959
  name: 'userMessage',
30788
28960
  message: 'User message',
30789
- hint: spaceTrim$2((block) => `
28961
+ hint: spaceTrim$1((block) => `
30790
28962
  Type "exit" to exit,
30791
28963
 
30792
28964
  previousTitle
@@ -30802,7 +28974,7 @@ async function runInteractiveChatbot(options) {
30802
28974
  return process.exit(0);
30803
28975
  }
30804
28976
  console.info(`\n`);
30805
- console.info(spaceTrim$2((block) => `
28977
+ console.info(spaceTrim$1((block) => `
30806
28978
 
30807
28979
  ${colors.bold(colors.blue('User:'))}
30808
28980
  ${block(colors.blue(userMessage))}
@@ -30815,7 +28987,7 @@ async function runInteractiveChatbot(options) {
30815
28987
  };
30816
28988
  const result = await pipelineExecutor(inputParameters).asPromise({ isCrashedOnError: true });
30817
28989
  console.info(`\n`);
30818
- console.info(spaceTrim$2((block) => `
28990
+ console.info(spaceTrim$1((block) => `
30819
28991
 
30820
28992
  ${colors.bold(colors.green('Chatbot:'))}
30821
28993
  ${block(colors.green(result.outputParameters.chatbotResponse))}
@@ -30846,7 +29018,7 @@ async function runInteractiveChatbot(options) {
30846
29018
  */
30847
29019
  function $initializeRunCommand(program) {
30848
29020
  const runCommand = program.command('run', { isDefault: true });
30849
- runCommand.description(spaceTrim$2(`
29021
+ runCommand.description(spaceTrim$1(`
30850
29022
  Runs a pipeline
30851
29023
  `));
30852
29024
  runCommand.alias('execute');
@@ -30889,7 +29061,7 @@ function $initializeRunCommand(program) {
30889
29061
  if (!error.message.includes('No LLM tools')) {
30890
29062
  throw error;
30891
29063
  }
30892
- console.error(colors.red(spaceTrim$2((block) => `
29064
+ console.error(colors.red(spaceTrim$1((block) => `
30893
29065
  You need to configure LLM tools first
30894
29066
 
30895
29067
  1) Create .env file at the root of your project
@@ -30957,7 +29129,7 @@ function $initializeRunCommand(program) {
30957
29129
  if (!(error instanceof ParseError)) {
30958
29130
  throw error;
30959
29131
  }
30960
- console.error(colors.red(spaceTrim$2((block) => `
29132
+ console.error(colors.red(spaceTrim$1((block) => `
30961
29133
  ${block(error.message)}
30962
29134
 
30963
29135
  in ${pipelineSource}
@@ -31009,7 +29181,7 @@ function $initializeRunCommand(program) {
31009
29181
  };
31010
29182
  });
31011
29183
  if (isInteractive === false && questions.length !== 0) {
31012
- console.error(colors.red(spaceTrim$2((block) => `
29184
+ console.error(colors.red(spaceTrim$1((block) => `
31013
29185
  When using --no-interactive you need to pass all the input parameters through --json
31014
29186
 
31015
29187
  You are missing:
@@ -31141,7 +29313,7 @@ function $initializeStartAgentsServerCommand(program) {
31141
29313
  'Path to agents directory', DEFAULT_AGENTS_DIRNAME);
31142
29314
  startServerCommand.option('--port <port>', `Port to start the server on`, '4440');
31143
29315
  startServerCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
31144
- startServerCommand.description(spaceTrim$2(`
29316
+ startServerCommand.description(spaceTrim$1(`
31145
29317
  Starts a Promptbook agents server
31146
29318
  `));
31147
29319
  startServerCommand.alias('start');
@@ -32448,7 +30620,7 @@ function $initializeStartPipelinesServerCommand(program) {
32448
30620
  // <- TODO: [🧟‍♂️] Unite path to promptbook collection argument
32449
30621
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
32450
30622
  startServerCommand.option('--port <port>', `Port to start the server on`, '4460');
32451
- startServerCommand.option('-u, --url <url>', spaceTrim$2(`
30623
+ startServerCommand.option('-u, --url <url>', spaceTrim$1(`
32452
30624
  Public root url of the server
32453
30625
  It is used for following purposes:
32454
30626
 
@@ -32458,7 +30630,7 @@ function $initializeStartPipelinesServerCommand(program) {
32458
30630
  startServerCommand.option('--allow-anonymous', `Is anonymous mode allowed`, false);
32459
30631
  startServerCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
32460
30632
  startServerCommand.option('--no-rich-ui', `Disable rich UI`, true);
32461
- startServerCommand.description(spaceTrim$2(`
30633
+ startServerCommand.description(spaceTrim$1(`
32462
30634
  Starts a remote server to execute books
32463
30635
 
32464
30636
  Note: You want probably to use "ptbk start-agents-server" to start agents server instead of pipelines server
@@ -32549,7 +30721,7 @@ function $initializeStartPipelinesServerCommand(program) {
32549
30721
  */
32550
30722
  function $initializeTestCommand(program) {
32551
30723
  const testCommand = program.command('test');
32552
- testCommand.description(spaceTrim$2(`
30724
+ testCommand.description(spaceTrim$1(`
32553
30725
  Iterates over \`.book.md\` and \`.bookc\` and checks if they are parsable and logically valid
32554
30726
  `));
32555
30727
  testCommand.argument('<filesGlob>',
@@ -32789,7 +30961,7 @@ function pricing(value) {
32789
30961
  /**
32790
30962
  * List of available Anthropic Claude models with pricing
32791
30963
  *
32792
- * Note: Synced with official API docs at 2025-11-19
30964
+ * Note: Synced with official API docs at 2026-03-22
32793
30965
  *
32794
30966
  * @see https://docs.anthropic.com/en/docs/models-overview
32795
30967
  * @public exported from `@promptbook/anthropic-claude`
@@ -32797,6 +30969,26 @@ function pricing(value) {
32797
30969
  const ANTHROPIC_CLAUDE_MODELS = exportJson({
32798
30970
  name: 'ANTHROPIC_CLAUDE_MODELS',
32799
30971
  value: [
30972
+ {
30973
+ modelVariant: 'CHAT',
30974
+ modelTitle: 'Claude Opus 4.6',
30975
+ modelName: 'claude-opus-4-6',
30976
+ modelDescription: "Anthropic's most capable model for advanced coding, complex reasoning, and agentic workflows with 1M token context window.",
30977
+ pricing: {
30978
+ prompt: pricing(`$5.00 / 1M tokens`),
30979
+ output: pricing(`$25.00 / 1M tokens`),
30980
+ },
30981
+ },
30982
+ {
30983
+ modelVariant: 'CHAT',
30984
+ modelTitle: 'Claude Sonnet 4.6',
30985
+ modelName: 'claude-sonnet-4-6',
30986
+ modelDescription: 'Best speed and intelligence balance for production-ready workloads with 1M token context window. Ideal for high-performance, lower-latency applications.',
30987
+ pricing: {
30988
+ prompt: pricing(`$3.00 / 1M tokens`),
30989
+ output: pricing(`$15.00 / 1M tokens`),
30990
+ },
30991
+ },
32800
30992
  {
32801
30993
  modelVariant: 'CHAT',
32802
30994
  modelTitle: 'Claude Sonnet 4.5',
@@ -33198,7 +31390,7 @@ class AnthropicClaudeExecutionTools {
33198
31390
  getDefaultModel(defaultModelName) {
33199
31391
  const model = ANTHROPIC_CLAUDE_MODELS.find(({ modelName }) => modelName.startsWith(defaultModelName));
33200
31392
  if (model === undefined) {
33201
- throw new UnexpectedError(spaceTrim$2((block) => `
31393
+ throw new UnexpectedError(spaceTrim$1((block) => `
33202
31394
  Cannot find model in Anthropic Claude models with name "${defaultModelName}" which should be used as default.
33203
31395
 
33204
31396
  Available models:
@@ -33355,7 +31547,7 @@ const _AzureOpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
33355
31547
  /**
33356
31548
  * List of available OpenAI models with pricing
33357
31549
  *
33358
- * Note: Synced with official API docs at 2025-11-19
31550
+ * Note: Synced with official API docs at 2026-03-22
33359
31551
  *
33360
31552
  * @see https://platform.openai.com/docs/models/
33361
31553
  * @see https://openai.com/api/pricing/
@@ -33477,8 +31669,8 @@ const OPENAI_MODELS = exportJson({
33477
31669
  modelName: 'gpt-4.1',
33478
31670
  modelDescription: 'Smartest non-reasoning model with 128K context window. Enhanced version of GPT-4 with improved instruction following, better factual accuracy, and reduced hallucinations. Features advanced function calling capabilities and superior performance on coding tasks. Ideal for applications requiring high intelligence without reasoning overhead.',
33479
31671
  pricing: {
33480
- prompt: pricing(`$3.00 / 1M tokens`),
33481
- output: pricing(`$12.00 / 1M tokens`),
31672
+ prompt: pricing(`$2.00 / 1M tokens`),
31673
+ output: pricing(`$8.00 / 1M tokens`),
33482
31674
  },
33483
31675
  },
33484
31676
  /**/
@@ -33489,8 +31681,8 @@ const OPENAI_MODELS = exportJson({
33489
31681
  modelName: 'gpt-4.1-mini',
33490
31682
  modelDescription: 'Smaller, faster version of GPT-4.1 with 128K context window. Balances intelligence and efficiency with 3x faster inference than base GPT-4.1. Maintains strong capabilities across text generation, reasoning, and coding while offering better cost-performance ratio for most applications.',
33491
31683
  pricing: {
33492
- prompt: pricing(`$0.80 / 1M tokens`),
33493
- output: pricing(`$3.20 / 1M tokens`),
31684
+ prompt: pricing(`$0.40 / 1M tokens`),
31685
+ output: pricing(`$1.60 / 1M tokens`),
33494
31686
  },
33495
31687
  },
33496
31688
  /**/
@@ -33501,8 +31693,8 @@ const OPENAI_MODELS = exportJson({
33501
31693
  modelName: 'gpt-4.1-nano',
33502
31694
  modelDescription: 'Fastest, most cost-efficient version of GPT-4.1 with 128K context window. Optimized for high-throughput applications requiring good quality at minimal cost. Features 5x faster inference than GPT-4.1 while maintaining adequate performance for most general-purpose tasks.',
33503
31695
  pricing: {
33504
- prompt: pricing(`$0.20 / 1M tokens`),
33505
- output: pricing(`$0.80 / 1M tokens`),
31696
+ prompt: pricing(`$0.10 / 1M tokens`),
31697
+ output: pricing(`$0.40 / 1M tokens`),
33506
31698
  },
33507
31699
  },
33508
31700
  /**/
@@ -33513,8 +31705,8 @@ const OPENAI_MODELS = exportJson({
33513
31705
  modelName: 'o3',
33514
31706
  modelDescription: 'Advanced reasoning model with 128K context window specializing in complex logical, mathematical, and analytical tasks. Successor to o1 with enhanced step-by-step problem-solving capabilities and superior performance on STEM-focused problems. Ideal for professional applications requiring deep analytical thinking and precise reasoning.',
33515
31707
  pricing: {
33516
- prompt: pricing(`$15.00 / 1M tokens`),
33517
- output: pricing(`$60.00 / 1M tokens`),
31708
+ prompt: pricing(`$2.00 / 1M tokens`),
31709
+ output: pricing(`$8.00 / 1M tokens`),
33518
31710
  },
33519
31711
  },
33520
31712
  /**/
@@ -33525,8 +31717,8 @@ const OPENAI_MODELS = exportJson({
33525
31717
  modelName: 'o3-pro',
33526
31718
  modelDescription: 'Enhanced version of o3 with more compute allocated for better responses on the most challenging problems. Features extended reasoning time and improved accuracy on complex analytical tasks. Designed for applications where maximum reasoning quality is more important than response speed.',
33527
31719
  pricing: {
33528
- prompt: pricing(`$30.00 / 1M tokens`),
33529
- output: pricing(`$120.00 / 1M tokens`),
31720
+ prompt: pricing(`$20.00 / 1M tokens`),
31721
+ output: pricing(`$80.00 / 1M tokens`),
33530
31722
  },
33531
31723
  },
33532
31724
  /**/
@@ -33537,8 +31729,8 @@ const OPENAI_MODELS = exportJson({
33537
31729
  modelName: 'o4-mini',
33538
31730
  modelDescription: 'Fast, cost-efficient reasoning model with 128K context window. Successor to o1-mini with improved analytical capabilities while maintaining speed advantages. Features enhanced mathematical reasoning and logical problem-solving at significantly lower cost than full reasoning models.',
33539
31731
  pricing: {
33540
- prompt: pricing(`$4.00 / 1M tokens`),
33541
- output: pricing(`$16.00 / 1M tokens`),
31732
+ prompt: pricing(`$1.10 / 1M tokens`),
31733
+ output: pricing(`$4.40 / 1M tokens`),
33542
31734
  },
33543
31735
  },
33544
31736
  /**/
@@ -33896,8 +32088,8 @@ const OPENAI_MODELS = exportJson({
33896
32088
  modelName: 'gpt-4o-2024-05-13',
33897
32089
  modelDescription: 'May 2024 version of GPT-4o with 128K context window. Features enhanced multimodal capabilities including superior image understanding (up to 20MP), audio processing, and improved reasoning. Optimized for 2x lower latency than GPT-4 Turbo while maintaining high performance. Includes knowledge up to October 2023. Ideal for production applications requiring reliable multimodal capabilities.',
33898
32090
  pricing: {
33899
- prompt: pricing(`$5.00 / 1M tokens`),
33900
- output: pricing(`$15.00 / 1M tokens`),
32091
+ prompt: pricing(`$2.50 / 1M tokens`),
32092
+ output: pricing(`$10.00 / 1M tokens`),
33901
32093
  },
33902
32094
  },
33903
32095
  /**/
@@ -33908,8 +32100,8 @@ const OPENAI_MODELS = exportJson({
33908
32100
  modelName: 'gpt-4o',
33909
32101
  modelDescription: "OpenAI's most advanced general-purpose multimodal model with 128K context window. Optimized for balanced performance, speed, and cost with 2x faster responses than GPT-4 Turbo. Features excellent vision processing, audio understanding, reasoning, and text generation quality. Represents optimal balance of capability and efficiency for most advanced applications.",
33910
32102
  pricing: {
33911
- prompt: pricing(`$5.00 / 1M tokens`),
33912
- output: pricing(`$15.00 / 1M tokens`),
32103
+ prompt: pricing(`$2.50 / 1M tokens`),
32104
+ output: pricing(`$10.00 / 1M tokens`),
33913
32105
  },
33914
32106
  },
33915
32107
  /**/
@@ -33980,8 +32172,8 @@ const OPENAI_MODELS = exportJson({
33980
32172
  modelName: 'o3-mini',
33981
32173
  modelDescription: 'Cost-effective reasoning model with 128K context window optimized for academic and scientific problem-solving. Features efficient performance on STEM tasks with specialized capabilities in mathematics, physics, chemistry, and computer science. Offers 80% of O1 performance on technical domains at significantly lower cost. Ideal for educational applications and research support.',
33982
32174
  pricing: {
33983
- prompt: pricing(`$3.00 / 1M tokens`),
33984
- output: pricing(`$12.00 / 1M tokens`),
32175
+ prompt: pricing(`$1.10 / 1M tokens`),
32176
+ output: pricing(`$4.40 / 1M tokens`),
33985
32177
  },
33986
32178
  },
33987
32179
  /**/
@@ -34496,7 +32688,7 @@ function createExecutionToolsFromVercelProvider(options) {
34496
32688
  const modelName = modelRequirements.modelName ||
34497
32689
  ((_a = availableModels.find(({ modelVariant }) => modelVariant === 'CHAT')) === null || _a === void 0 ? void 0 : _a.modelName);
34498
32690
  if (!modelName) {
34499
- throw new PipelineExecutionError(spaceTrim$2(`
32691
+ throw new PipelineExecutionError(spaceTrim$1(`
34500
32692
  Can not determine which model to use.
34501
32693
 
34502
32694
  You need to provide at least one of:
@@ -34611,7 +32803,7 @@ function createExecutionToolsFromVercelProvider(options) {
34611
32803
  /**
34612
32804
  * List of available Deepseek models with descriptions
34613
32805
  *
34614
- * Note: Synced with official API docs at 2025-08-20
32806
+ * Note: Synced with official API docs at 2026-03-22
34615
32807
  *
34616
32808
  * @see https://www.deepseek.com/models
34617
32809
  * @public exported from `@promptbook/deepseek`
@@ -34625,8 +32817,8 @@ const DEEPSEEK_MODELS = exportJson({
34625
32817
  modelName: 'deepseek-chat',
34626
32818
  modelDescription: 'Latest flagship general-purpose model with 128K context window. Features exceptional reasoning capabilities, advanced code generation, and strong performance across diverse domains. Offers competitive performance with leading models while maintaining cost efficiency. Ideal for complex reasoning, coding, and knowledge-intensive tasks.',
34627
32819
  pricing: {
34628
- prompt: pricing(`$0.14 / 1M tokens`),
34629
- output: pricing(`$0.28 / 1M tokens`),
32820
+ prompt: pricing(`$0.28 / 1M tokens`),
32821
+ output: pricing(`$0.42 / 1M tokens`),
34630
32822
  },
34631
32823
  },
34632
32824
  {
@@ -34892,7 +33084,7 @@ const _GoogleMetadataRegistration = $llmToolsMetadataRegister.register({
34892
33084
  /**
34893
33085
  * List of available Google models with descriptions
34894
33086
  *
34895
- * Note: Synced with official API docs at 2025-11-19
33087
+ * Note: Synced with official API docs at 2026-03-22
34896
33088
  *
34897
33089
  * @see https://ai.google.dev/models/gemini
34898
33090
  * @public exported from `@promptbook/google`
@@ -34913,8 +33105,8 @@ const GOOGLE_MODELS = exportJson({
34913
33105
  modelName: 'gemini-2.5-pro',
34914
33106
  modelDescription: 'State-of-the-art thinking model with 1M token context window capable of reasoning over complex problems in code, math, and STEM. Features enhanced thinking capabilities, advanced multimodal understanding, and superior performance on analytical tasks. Ideal for complex enterprise applications requiring maximum intelligence and reasoning.',
34915
33107
  pricing: {
34916
- prompt: pricing(`$7.00 / 1M tokens`),
34917
- output: pricing(`$21.00 / 1M tokens`),
33108
+ prompt: pricing(`$1.25 / 1M tokens`),
33109
+ output: pricing(`$10.00 / 1M tokens`),
34918
33110
  },
34919
33111
  },
34920
33112
  {
@@ -34923,8 +33115,8 @@ const GOOGLE_MODELS = exportJson({
34923
33115
  modelName: 'gemini-2.5-flash',
34924
33116
  modelDescription: 'Best model in terms of price-performance with 1M token context window offering well-rounded capabilities. Features adaptive thinking, cost efficiency, and enhanced reasoning for large-scale processing. Ideal for low-latency, high-volume tasks that require thinking and agentic use cases.',
34925
33117
  pricing: {
34926
- prompt: pricing(`$0.35 / 1M tokens`),
34927
- output: pricing(`$1.05 / 1M tokens`),
33118
+ prompt: pricing(`$0.30 / 1M tokens`),
33119
+ output: pricing(`$2.50 / 1M tokens`),
34928
33120
  },
34929
33121
  },
34930
33122
  {
@@ -34933,8 +33125,8 @@ const GOOGLE_MODELS = exportJson({
34933
33125
  modelName: 'gemini-2.5-flash-lite',
34934
33126
  modelDescription: 'Cost-efficient Gemini 2.5 Flash model optimized for high throughput with 1M token context window. Features thinking capabilities while maintaining the most cost-efficient pricing. Perfect for real-time, low-latency use cases requiring good quality at scale.',
34935
33127
  pricing: {
34936
- prompt: pricing(`$0.20 / 1M tokens`),
34937
- output: pricing(`$0.60 / 1M tokens`),
33128
+ prompt: pricing(`$0.10 / 1M tokens`),
33129
+ output: pricing(`$0.40 / 1M tokens`),
34938
33130
  },
34939
33131
  },
34940
33132
  {
@@ -35413,53 +33605,6 @@ resultContent, rawResponse, duration = ZERO_VALUE) {
35413
33605
  * TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
35414
33606
  */
35415
33607
 
35416
- /**
35417
- * Maps Promptbook tools to OpenAI tools.
35418
- *
35419
- * @private
35420
- */
35421
- function mapToolsToOpenAi(tools) {
35422
- return tools.map((tool) => ({
35423
- type: 'function',
35424
- function: {
35425
- name: tool.name,
35426
- description: tool.description,
35427
- parameters: tool.parameters,
35428
- },
35429
- }));
35430
- }
35431
-
35432
- /**
35433
- * Builds a tool invocation script that injects hidden runtime context into tool args.
35434
- *
35435
- * @private utility of OpenAI tool execution wrappers
35436
- */
35437
- function buildToolInvocationScript(options) {
35438
- const { functionName, functionArgsExpression } = options;
35439
- return `
35440
- const args = ${functionArgsExpression};
35441
- const runtimeContextRaw =
35442
- typeof ${TOOL_RUNTIME_CONTEXT_PARAMETER} === 'undefined'
35443
- ? undefined
35444
- : ${TOOL_RUNTIME_CONTEXT_PARAMETER};
35445
-
35446
- if (runtimeContextRaw !== undefined && args && typeof args === 'object' && !Array.isArray(args)) {
35447
- args.${TOOL_RUNTIME_CONTEXT_ARGUMENT} = runtimeContextRaw;
35448
- }
35449
-
35450
- const toolProgressTokenRaw =
35451
- typeof ${TOOL_PROGRESS_TOKEN_PARAMETER} === 'undefined'
35452
- ? undefined
35453
- : ${TOOL_PROGRESS_TOKEN_PARAMETER};
35454
-
35455
- if (toolProgressTokenRaw !== undefined && args && typeof args === 'object' && !Array.isArray(args)) {
35456
- args.${TOOL_PROGRESS_TOKEN_ARGUMENT} = toolProgressTokenRaw;
35457
- }
35458
-
35459
- return await ${functionName}(args);
35460
- `;
35461
- }
35462
-
35463
33608
  /**
35464
33609
  * Parses an OpenAI error message to identify which parameter is unsupported
35465
33610
  *
@@ -35516,6 +33661,53 @@ function isUnsupportedParameterError(error) {
35516
33661
  errorMessage.includes('does not support'));
35517
33662
  }
35518
33663
 
33664
+ /**
33665
+ * Builds a tool invocation script that injects hidden runtime context into tool args.
33666
+ *
33667
+ * @private utility of OpenAI tool execution wrappers
33668
+ */
33669
+ function buildToolInvocationScript(options) {
33670
+ const { functionName, functionArgsExpression } = options;
33671
+ return `
33672
+ const args = ${functionArgsExpression};
33673
+ const runtimeContextRaw =
33674
+ typeof ${TOOL_RUNTIME_CONTEXT_PARAMETER} === 'undefined'
33675
+ ? undefined
33676
+ : ${TOOL_RUNTIME_CONTEXT_PARAMETER};
33677
+
33678
+ if (runtimeContextRaw !== undefined && args && typeof args === 'object' && !Array.isArray(args)) {
33679
+ args.${TOOL_RUNTIME_CONTEXT_ARGUMENT} = runtimeContextRaw;
33680
+ }
33681
+
33682
+ const toolProgressTokenRaw =
33683
+ typeof ${TOOL_PROGRESS_TOKEN_PARAMETER} === 'undefined'
33684
+ ? undefined
33685
+ : ${TOOL_PROGRESS_TOKEN_PARAMETER};
33686
+
33687
+ if (toolProgressTokenRaw !== undefined && args && typeof args === 'object' && !Array.isArray(args)) {
33688
+ args.${TOOL_PROGRESS_TOKEN_ARGUMENT} = toolProgressTokenRaw;
33689
+ }
33690
+
33691
+ return await ${functionName}(args);
33692
+ `;
33693
+ }
33694
+
33695
+ /**
33696
+ * Maps Promptbook tools to OpenAI tools.
33697
+ *
33698
+ * @private
33699
+ */
33700
+ function mapToolsToOpenAi(tools) {
33701
+ return tools.map((tool) => ({
33702
+ type: 'function',
33703
+ function: {
33704
+ name: tool.name,
33705
+ description: tool.description,
33706
+ parameters: tool.parameters,
33707
+ },
33708
+ }));
33709
+ }
33710
+
35519
33711
  /**
35520
33712
  * Provides access to the structured clone implementation when available.
35521
33713
  */
@@ -36482,7 +34674,7 @@ class OpenAiCompatibleExecutionTools {
36482
34674
  // Note: Match exact or prefix for model families
36483
34675
  const model = this.HARDCODED_MODELS.find(({ modelName }) => modelName === defaultModelName || modelName.startsWith(defaultModelName));
36484
34676
  if (model === undefined) {
36485
- throw new PipelineExecutionError(spaceTrim$2((block) => `
34677
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
36486
34678
  Cannot find model in ${this.title} models with name "${defaultModelName}" which should be used as default.
36487
34679
 
36488
34680
  Available models:
@@ -38239,7 +36431,7 @@ class OpenAiAssistantExecutionTools extends OpenAiVectorStoreHandler {
38239
36431
  assertsError(error);
38240
36432
  const serializedError = serializeError(error);
38241
36433
  errors = [serializedError];
38242
- functionResponse = spaceTrim$2((block) => `
36434
+ functionResponse = spaceTrim$1((block) => `
38243
36435
 
38244
36436
  The invoked tool \`${functionName}\` failed with error:
38245
36437
 
@@ -38968,7 +37160,7 @@ class BoilerplateScraper {
38968
37160
  await $execCommand(command);
38969
37161
  // Note: [0]
38970
37162
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
38971
- throw new UnexpectedError(spaceTrim$2((block) => `
37163
+ throw new UnexpectedError(spaceTrim$1((block) => `
38972
37164
  File that was supposed to be created by Pandoc does not exist for unknown reason
38973
37165
 
38974
37166
  Expected file:
@@ -39132,7 +37324,7 @@ class DocumentScraper {
39132
37324
  await $execCommand(command);
39133
37325
  // Note: [0]
39134
37326
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
39135
- throw new UnexpectedError(spaceTrim$2((block) => `
37327
+ throw new UnexpectedError(spaceTrim$1((block) => `
39136
37328
  File that was supposed to be created by Pandoc does not exist for unknown reason
39137
37329
 
39138
37330
  Expected file:
@@ -39283,7 +37475,7 @@ class LegacyDocumentScraper {
39283
37475
  await $execCommand(command);
39284
37476
  const files = await readdir(documentSourceOutdirPathForLibreOffice);
39285
37477
  if (files.length !== 1) {
39286
- throw new UnexpectedError(spaceTrim$2((block) => `
37478
+ throw new UnexpectedError(spaceTrim$1((block) => `
39287
37479
  Expected exactly 1 file in the LibreOffice output directory, got ${files.length}
39288
37480
 
39289
37481
  The temporary folder:
@@ -39297,7 +37489,7 @@ class LegacyDocumentScraper {
39297
37489
  await rename(join(documentSourceOutdirPathForLibreOffice, file), cacheFilehandler.filename);
39298
37490
  await rmdir(documentSourceOutdirPathForLibreOffice);
39299
37491
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
39300
- throw new UnexpectedError(spaceTrim$2((block) => `
37492
+ throw new UnexpectedError(spaceTrim$1((block) => `
39301
37493
  File that was supposed to be created by LibreOffice does not exist for unknown reason
39302
37494
 
39303
37495
  Expected file:
@@ -40564,7 +38756,7 @@ function computeAgentHash(agentSource) {
40564
38756
  * @public exported from `@promptbook/core`
40565
38757
  */
40566
38758
  function normalizeAgentName(rawAgentName) {
40567
- return titleToName(spaceTrim$2(rawAgentName));
38759
+ return titleToName(spaceTrim$1(rawAgentName));
40568
38760
  }
40569
38761
 
40570
38762
  /**
@@ -40739,7 +38931,7 @@ function parseAgentSource(agentSource) {
40739
38931
  continue;
40740
38932
  }
40741
38933
  if (commitment.type === 'FROM') {
40742
- const content = spaceTrim$2(commitment.content).split(/\r?\n/)[0] || '';
38934
+ const content = spaceTrim$1(commitment.content).split(/\r?\n/)[0] || '';
40743
38935
  if (content === 'Adam' || content === '' /* <- Note: Adam is implicit */) {
40744
38936
  continue;
40745
38937
  }
@@ -40762,7 +38954,7 @@ function parseAgentSource(agentSource) {
40762
38954
  continue;
40763
38955
  }
40764
38956
  if (commitment.type === 'IMPORT') {
40765
- const content = spaceTrim$2(commitment.content).split(/\r?\n/)[0] || '';
38957
+ const content = spaceTrim$1(commitment.content).split(/\r?\n/)[0] || '';
40766
38958
  let label = content;
40767
38959
  let iconName = 'ExternalLink'; // Import remote
40768
38960
  try {
@@ -40800,7 +38992,7 @@ function parseAgentSource(agentSource) {
40800
38992
  continue;
40801
38993
  }
40802
38994
  if (commitment.type === 'KNOWLEDGE') {
40803
- const content = spaceTrim$2(commitment.content);
38995
+ const content = spaceTrim$1(commitment.content);
40804
38996
  const extractedUrls = extractUrlsFromText(content);
40805
38997
  let label = content;
40806
38998
  let iconName = 'Book';
@@ -40859,7 +39051,7 @@ function parseAgentSource(agentSource) {
40859
39051
  continue;
40860
39052
  }
40861
39053
  if (commitment.type === 'META LINK') {
40862
- const linkValue = spaceTrim$2(commitment.content);
39054
+ const linkValue = spaceTrim$1(commitment.content);
40863
39055
  links.push(linkValue);
40864
39056
  meta.link = linkValue;
40865
39057
  continue;
@@ -40869,11 +39061,11 @@ function parseAgentSource(agentSource) {
40869
39061
  continue;
40870
39062
  }
40871
39063
  if (commitment.type === 'META IMAGE') {
40872
- meta.image = spaceTrim$2(commitment.content);
39064
+ meta.image = spaceTrim$1(commitment.content);
40873
39065
  continue;
40874
39066
  }
40875
39067
  if (commitment.type === 'META DESCRIPTION') {
40876
- meta.description = spaceTrim$2(commitment.content);
39068
+ meta.description = spaceTrim$1(commitment.content);
40877
39069
  continue;
40878
39070
  }
40879
39071
  if (commitment.type === 'META DISCLAIMER') {
@@ -40881,7 +39073,7 @@ function parseAgentSource(agentSource) {
40881
39073
  continue;
40882
39074
  }
40883
39075
  if (commitment.type === 'META INPUT PLACEHOLDER') {
40884
- meta.inputPlaceholder = spaceTrim$2(commitment.content);
39076
+ meta.inputPlaceholder = spaceTrim$1(commitment.content);
40885
39077
  continue;
40886
39078
  }
40887
39079
  if (commitment.type === 'MESSAGE SUFFIX') {
@@ -40897,7 +39089,7 @@ function parseAgentSource(agentSource) {
40897
39089
  continue;
40898
39090
  }
40899
39091
  if (commitment.type === 'META VOICE') {
40900
- meta.voice = spaceTrim$2(commitment.content);
39092
+ meta.voice = spaceTrim$1(commitment.content);
40901
39093
  continue;
40902
39094
  }
40903
39095
  if (commitment.type !== 'META') {
@@ -40906,10 +39098,10 @@ function parseAgentSource(agentSource) {
40906
39098
  // Parse META commitments - format is "META TYPE content"
40907
39099
  const metaTypeRaw = commitment.content.split(' ')[0] || 'NONE';
40908
39100
  if (metaTypeRaw === 'LINK') {
40909
- links.push(spaceTrim$2(commitment.content.substring(metaTypeRaw.length)));
39101
+ links.push(spaceTrim$1(commitment.content.substring(metaTypeRaw.length)));
40910
39102
  }
40911
39103
  const metaType = normalizeTo_camelCase(metaTypeRaw);
40912
- meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
39104
+ meta[metaType] = spaceTrim$1(commitment.content.substring(metaTypeRaw.length));
40913
39105
  }
40914
39106
  // Generate fullname fallback if no meta fullname specified
40915
39107
  if (!meta.fullname) {
@@ -40940,7 +39132,7 @@ function parseAgentSource(agentSource) {
40940
39132
  * @returns The content with normalized separators
40941
39133
  */
40942
39134
  function normalizeSeparator(content) {
40943
- const trimmed = spaceTrim$2(content);
39135
+ const trimmed = spaceTrim$1(content);
40944
39136
  if (trimmed.includes(',')) {
40945
39137
  return trimmed;
40946
39138
  }
@@ -40953,7 +39145,7 @@ function normalizeSeparator(content) {
40953
39145
  * @returns Normalized domain or a trimmed fallback.
40954
39146
  */
40955
39147
  function normalizeMetaDomain(content) {
40956
- const trimmed = spaceTrim$2(content);
39148
+ const trimmed = spaceTrim$1(content);
40957
39149
  return normalizeDomainForMatching(trimmed) || trimmed.toLowerCase();
40958
39150
  }
40959
39151
  /**
@@ -41091,7 +39283,7 @@ const OpenAiSdkTranspiler = {
41091
39283
  }
41092
39284
  const KNOWLEDGE_THRESHOLD = 1000;
41093
39285
  if (directKnowledge.join('\n').length > KNOWLEDGE_THRESHOLD || knowledgeSources.length > 0) {
41094
- return spaceTrim$2((block) => `
39286
+ return spaceTrim$1((block) => `
41095
39287
  #!/usr/bin/env node
41096
39288
 
41097
39289
  import * as dotenv from 'dotenv';
@@ -41166,7 +39358,7 @@ const OpenAiSdkTranspiler = {
41166
39358
 
41167
39359
  if (context) {
41168
39360
  question = spaceTrim(\`
41169
- ${block(spaceTrim$2(`
39361
+ ${block(spaceTrim$1(`
41170
39362
  Here is some additional context to help you answer the question:
41171
39363
  \${context}
41172
39364
 
@@ -41247,7 +39439,7 @@ const OpenAiSdkTranspiler = {
41247
39439
  })();
41248
39440
  `);
41249
39441
  }
41250
- const source = spaceTrim$2((block) => `
39442
+ const source = spaceTrim$1((block) => `
41251
39443
 
41252
39444
  #!/usr/bin/env node
41253
39445
 
@@ -41437,12 +39629,7 @@ const EMOJIS_OF_SINGLE_PICTOGRAM = new Set(Array.from(EMOJIS).filter((emoji) =>
41437
39629
  * Note: [💞] Ignore a discrepancy between file name and entity name
41438
39630
  */
41439
39631
 
41440
- // find-fresh-emoji-tag.ts
41441
- dotenv.config({ path: '.env' });
41442
- if (process.cwd() !== join(__dirname, '../..')) {
41443
- console.error(colors.red(`CWD must be root of the project`));
41444
- process.exit(1);
41445
- }
39632
+ // find-fresh-emoji-tags.ts
41446
39633
  // Note: When run as a standalone script, call the exported function
41447
39634
  if (require.main === module) {
41448
39635
  findFreshEmojiTag()
@@ -41455,12 +39642,31 @@ if (require.main === module) {
41455
39642
  process.exit(0);
41456
39643
  });
41457
39644
  }
39645
+ /**
39646
+ * Initializes environment and validates repository context for this script.
39647
+ *
39648
+ * @private utility for `findFreshEmojiTag`
39649
+ */
39650
+ function initializeFindFreshEmojiTagRun() {
39651
+ dotenv.config({ path: '.env' });
39652
+ if (process.cwd() !== join(__dirname, '../..')) {
39653
+ console.error(colors.red(spaceTrim$1(`
39654
+ CWD must be root of the project
39655
+
39656
+ Script: find-fresh-emoji-tag.ts
39657
+ Current CWD: ${process.cwd()}
39658
+ Expected CWD: ${join(__dirname, '../..')}
39659
+ `)));
39660
+ process.exit(1);
39661
+ }
39662
+ }
41458
39663
  /**
41459
39664
  * Finds fresh emoji tags that are not yet used in the codebase.
41460
39665
  *
41461
39666
  * @public exported from `@promptbook/cli`
41462
39667
  */
41463
39668
  async function findFreshEmojiTag() {
39669
+ initializeFindFreshEmojiTagRun();
41464
39670
  console.info(`🤪 Find fresh emoji tag`);
41465
39671
  const allFiles = await glob('**/*.{ts,tsx,js,jsx,json,md,txt}', {
41466
39672
  ignore: '**/node_modules/**', // <- TODO: [🚰] Ignore also hidden folders like *(`.promptbook`, `.next`, `.git`,...)*
@@ -41500,7 +39706,7 @@ async function findFreshEmojiTag() {
41500
39706
  * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
41501
39707
  */
41502
39708
 
41503
- var findFreshEmojiTag$1 = /*#__PURE__*/Object.freeze({
39709
+ var findFreshEmojiTags = /*#__PURE__*/Object.freeze({
41504
39710
  __proto__: null,
41505
39711
  findFreshEmojiTag: findFreshEmojiTag
41506
39712
  });
@@ -41729,11 +39935,6 @@ const PROMPT_SLUG_MAX_LENGTH = 80;
41729
39935
  * Note: [?] Code in this file should never be published in any package
41730
39936
  */
41731
39937
 
41732
- dotenv.config({ path: '.env' });
41733
- if (process.cwd() !== join(__dirname, '../..')) {
41734
- console.error(colors.red(`CWD must be root of the project`));
41735
- process.exit(1);
41736
- }
41737
39938
  if (require.main === module) {
41738
39939
  findRefactorCandidates()
41739
39940
  .catch((error) => {
@@ -41746,12 +39947,31 @@ if (require.main === module) {
41746
39947
  process.exit(0);
41747
39948
  });
41748
39949
  }
39950
+ /**
39951
+ * Initializes environment and validates repository context for this script.
39952
+ *
39953
+ * @private utility for `findRefactorCandidates`
39954
+ */
39955
+ function initializeFindRefactorCandidatesRun() {
39956
+ dotenv.config({ path: '.env' });
39957
+ if (process.cwd() !== join(__dirname, '../..')) {
39958
+ console.error(colors.red(spaceTrim$1(`
39959
+ CWD must be root of the project
39960
+
39961
+ Script: find-refactor-candidates.ts
39962
+ Current CWD: ${process.cwd()}
39963
+ Expected CWD: ${join(__dirname, '../..')}
39964
+ `)));
39965
+ process.exit(1);
39966
+ }
39967
+ }
41749
39968
  /**
41750
39969
  * Orchestrates scanning for refactor candidates and generating prompts.
41751
39970
  *
41752
39971
  * @public exported from `@promptbook/cli`
41753
39972
  */
41754
39973
  async function findRefactorCandidates() {
39974
+ initializeFindRefactorCandidatesRun();
41755
39975
  console.info(colors.cyan('?? Find refactor candidates'));
41756
39976
  const rootDir = process.cwd();
41757
39977
  const promptsDir = join(rootDir, PROMPTS_DIR_NAME);
@@ -41841,7 +40061,7 @@ async function findRefactorCandidates() {
41841
40061
  function buildPromptContent(candidate, emojiTag) {
41842
40062
  const fileName = basename(candidate.relativePath);
41843
40063
  const guidanceLines = buildPromptGuidance(candidate);
41844
- return spaceTrim$2((block) => `
40064
+ return spaceTrim$1((block) => `
41845
40065
 
41846
40066
  [ ]
41847
40067
 
@@ -42731,7 +40951,7 @@ async function pushCommittedChanges(agentEnv) {
42731
40951
  }
42732
40952
  const currentBranch = await readCurrentBranchName(agentEnv);
42733
40953
  if (currentBranch === 'HEAD') {
42734
- throw new GitPushFailedError(spaceTrim$2(`
40954
+ throw new GitPushFailedError(spaceTrim$1(`
42735
40955
  Failed to push coding-agent commit because Git is in detached HEAD mode.
42736
40956
 
42737
40957
  Actionable hint:
@@ -42811,7 +41031,7 @@ async function resolveDefaultRemoteName(currentBranch, agentEnv) {
42811
41031
  return remotes[0];
42812
41032
  }
42813
41033
  if (remotes.length > 1) {
42814
- throw new GitPushFailedError(spaceTrim$2(`
41034
+ throw new GitPushFailedError(spaceTrim$1(`
42815
41035
  Failed to push coding-agent commit because no default remote is configured.
42816
41036
 
42817
41037
  Available remotes: ${remotes.join(', ')}
@@ -42820,7 +41040,7 @@ async function resolveDefaultRemoteName(currentBranch, agentEnv) {
42820
41040
  - Configure \`remote.pushDefault\` or \`branch.${currentBranch}.remote\`, then rerun the coding script.
42821
41041
  `));
42822
41042
  }
42823
- throw new GitPushFailedError(spaceTrim$2(`
41043
+ throw new GitPushFailedError(spaceTrim$1(`
42824
41044
  Failed to push coding-agent commit because no Git remote is configured.
42825
41045
 
42826
41046
  Actionable hint:
@@ -42865,7 +41085,7 @@ function buildPushFailureMessage(command, error) {
42865
41085
  const details = stringifyUnknownError(error).trim() || '(No Git output)';
42866
41086
  const hints = buildPushFailureHints(details);
42867
41087
  const hintsMarkdown = hints.map((hint) => `- ${hint}`).join('\n');
42868
- return spaceTrim$2(`
41088
+ return spaceTrim$1(`
42869
41089
  Failed to push coding-agent commit to the remote repository.
42870
41090
 
42871
41091
  Command:
@@ -42963,7 +41183,7 @@ async function isWorkingTreeClean(path) {
42963
41183
  async function ensureWorkingTreeClean() {
42964
41184
  const isClean = await isWorkingTreeClean(process.cwd());
42965
41185
  if (!isClean) {
42966
- throw new Error(spaceTrim$2(`
41186
+ throw new Error(spaceTrim$1(`
42967
41187
  Git working tree is not clean.
42968
41188
 
42969
41189
  Please commit or stash your changes before running this script
@@ -43081,7 +41301,7 @@ const SERVER_REGISTRY_TABLE_NAME = '_Server';
43081
41301
  function parseServerRecord(rawRow, label = 'row') {
43082
41302
  const rawEnvironment = typeof rawRow.environment === 'string' ? rawRow.environment.trim().toUpperCase() : '';
43083
41303
  if (!isServerEnvironment(rawEnvironment)) {
43084
- throw new DatabaseError(spaceTrim$2(`
41304
+ throw new DatabaseError(spaceTrim$1(`
43085
41305
  Invalid \`${SERVER_REGISTRY_TABLE_NAME}\` ${label}.
43086
41306
 
43087
41307
  Field \`environment\` must be one of \`${SERVER_ENVIRONMENT.PRODUCTION}\`, \`${SERVER_ENVIRONMENT.PREVIEW}\`, \`${SERVER_ENVIRONMENT.LTS}\` or \`${SERVER_ENVIRONMENT.LIVE}\`.
@@ -43090,7 +41310,7 @@ function parseServerRecord(rawRow, label = 'row') {
43090
41310
  const domain = typeof rawRow.domain === 'string' ? rawRow.domain.trim().toLowerCase() : '';
43091
41311
  const normalizedDomain = normalizeServerDomain(domain);
43092
41312
  if (!normalizedDomain) {
43093
- throw new DatabaseError(spaceTrim$2(`
41313
+ throw new DatabaseError(spaceTrim$1(`
43094
41314
  Invalid \`${SERVER_REGISTRY_TABLE_NAME}\` ${label}.
43095
41315
 
43096
41316
  Field \`domain\` must contain a valid host or URL-like domain string.
@@ -43104,7 +41324,7 @@ function parseServerRecord(rawRow, label = 'row') {
43104
41324
  const updatedAt = typeof rawRow.updatedAt === 'string' ? rawRow.updatedAt : '';
43105
41325
  const id = typeof rawRow.id === 'number' ? rawRow.id : Number(rawRow.id);
43106
41326
  if (!name || !hasTablePrefix /*|| !createdAt || !updatedAt ||*/ || !Number.isFinite(id)) {
43107
- throw new DatabaseError(spaceTrim$2(`
41327
+ throw new DatabaseError(spaceTrim$1(`
43108
41328
  Invalid \`${SERVER_REGISTRY_TABLE_NAME}\` ${label}.
43109
41329
 
43110
41330
  Fields \`id\`, \`name\`, \`tablePrefix\`, \`createdAt\`, and \`updatedAt\` are required.
@@ -43224,7 +41444,7 @@ async function listRegisteredServersFromDatabase(client) {
43224
41444
  if (isMissingServerRegistryError(error)) {
43225
41445
  return [];
43226
41446
  }
43227
- throw new DatabaseError(spaceTrim$2((block) => `
41447
+ throw new DatabaseError(spaceTrim$1((block) => `
43228
41448
  Failed to query global server registry table \`_Server\`.
43229
41449
 
43230
41450
  ${block(error instanceof Error ? error.message : String(error))}
@@ -43409,7 +41629,7 @@ function selectPrefixesForMigration(configuredPrefixes, registeredServers, onlyT
43409
41629
  invalidTargets.push(onlyTarget);
43410
41630
  }
43411
41631
  if (invalidTargets.length > 0) {
43412
- throw new DatabaseError(spaceTrim$2(`
41632
+ throw new DatabaseError(spaceTrim$1(`
43413
41633
  Invalid migration targets specified in \`--only\`: ${invalidTargets
43414
41634
  .map((target) => `\`${target}\``)
43415
41635
  .join(', ')}.
@@ -43517,7 +41737,7 @@ const DATABASE_CONNECTION_ENV_NAMES = ['POSTGRES_URL', 'DATABASE_URL'];
43517
41737
  async function resolveDatabaseMigrationRuntimeConfiguration(logger = console) {
43518
41738
  const connectionString = resolveDatabaseMigrationConnectionStringFromEnvironment();
43519
41739
  if (!connectionString) {
43520
- throw new DatabaseError(spaceTrim$2(`
41740
+ throw new DatabaseError(spaceTrim$1(`
43521
41741
  ${DATABASE_CONNECTION_ENV_NAMES.join(' or ')} is not defined.
43522
41742
  `));
43523
41743
  }
@@ -43879,7 +42099,7 @@ function createDestructiveAutoMigrationBlockedError(findings) {
43879
42099
  .map((match) => `${getReadableRuleName(match.rule)}: ${createSqlStatementPreview(match.statement)}`)
43880
42100
  .join(' | ')})`)
43881
42101
  .join('\n');
43882
- return new DatabaseError(spaceTrim$2((block) => `
42102
+ return new DatabaseError(spaceTrim$1((block) => `
43883
42103
  Auto-migration blocked because pending testing-server migrations contain potentially destructive SQL.
43884
42104
 
43885
42105
  Review these migration statements:
@@ -45643,7 +43863,7 @@ function getRunnerMetadata(options, actualModel) {
45643
43863
  async function runCodexPrompts(providedOptions) {
45644
43864
  const options = providedOptions !== null && providedOptions !== void 0 ? providedOptions : parseRunOptions(process.argv.slice(2));
45645
43865
  if (options.allowDestructiveAutoMigrate && !options.autoMigrate) {
45646
- throw new DatabaseError(spaceTrim$2(`
43866
+ throw new DatabaseError(spaceTrim$1(`
45647
43867
  Flag \`--allow-destructive-auto-migrate\` requires \`--auto-migrate\`.
45648
43868
  `));
45649
43869
  }
@@ -46297,7 +44517,7 @@ function validateBook(source) {
46297
44517
  * @deprecated Use `$generateBookBoilerplate` instead
46298
44518
  * @public exported from `@promptbook/core`
46299
44519
  */
46300
- padBook(validateBook(spaceTrim$2(`
44520
+ padBook(validateBook(spaceTrim$1(`
46301
44521
  AI Avatar
46302
44522
 
46303
44523
  PERSONA A friendly AI assistant that helps you with your tasks
@@ -46324,7 +44544,7 @@ function book(strings, ...values) {
46324
44544
  const bookString = prompt(strings, ...values).toString();
46325
44545
  if (!isValidPipelineString(bookString)) {
46326
44546
  // TODO: Make the CustomError for this
46327
- throw new Error(spaceTrim$2(`
44547
+ throw new Error(spaceTrim$1(`
46328
44548
  The string is not a valid pipeline string
46329
44549
 
46330
44550
  book\`
@@ -46334,7 +44554,7 @@ function book(strings, ...values) {
46334
44554
  }
46335
44555
  if (!isValidBook(bookString)) {
46336
44556
  // TODO: Make the CustomError for this
46337
- throw new Error(spaceTrim$2(`
44557
+ throw new Error(spaceTrim$1(`
46338
44558
  The string is not a valid book
46339
44559
 
46340
44560
  book\`
@@ -47260,7 +45480,7 @@ function promptbookifyAiText(text) {
47260
45480
  * TODO: [🧠][✌️] Make some Promptbook-native token system
47261
45481
  */
47262
45482
 
47263
- const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5-mini-2025-08-07';
45483
+ const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.4-nano';
47264
45484
  /**
47265
45485
  * Creates one structured log entry for streamed tool-call updates.
47266
45486
  *
@@ -47755,7 +45975,7 @@ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
47755
45975
  }),
47756
45976
  ],
47757
45977
  };
47758
- const errorMessage = spaceTrim$2((block) => `
45978
+ const errorMessage = spaceTrim$1((block) => `
47759
45979
 
47760
45980
  The invoked tool \`${functionName}\` failed with error:
47761
45981
 
@@ -48705,7 +46925,7 @@ class SelfLearningManager {
48705
46925
  if (isJsonSchemaResponseFormat(responseFormat)) {
48706
46926
  const jsonSchema = responseFormat.json_schema;
48707
46927
  const schemaJson = JSON.stringify(jsonSchema, null, 4);
48708
- userMessageContent = spaceTrim$2((block) => `
46928
+ userMessageContent = spaceTrim$1((block) => `
48709
46929
  ${block(prompt.content)}
48710
46930
 
48711
46931
  NOTE Request was made through OpenAI Compatible API with \`response_format\` of type \`json_schema\` with the following schema:
@@ -48736,12 +46956,12 @@ class SelfLearningManager {
48736
46956
  const formattedAgentMessage = formatAgentMessageForJsonMode(result.content, usesJsonSchemaMode);
48737
46957
  const teacherInstructions = extractOpenTeacherInstructions(agentSource);
48738
46958
  const teacherInstructionsSection = teacherInstructions
48739
- ? spaceTrim$2((block) => `
46959
+ ? spaceTrim$1((block) => `
48740
46960
  **Teacher instructions:**
48741
46961
  ${block(teacherInstructions)}
48742
46962
  `)
48743
46963
  : '';
48744
- const teacherPromptContent = spaceTrim$2((block) => `
46964
+ const teacherPromptContent = spaceTrim$1((block) => `
48745
46965
 
48746
46966
  You are a teacher agent helping another agent to learn from its interactions.
48747
46967
 
@@ -48774,7 +46994,7 @@ class SelfLearningManager {
48774
46994
  ? '- This interaction used JSON mode, so the agent answer should stay as a formatted JSON code block.'
48775
46995
  : ''}
48776
46996
  ${block(isInitialMessageMissing
48777
- ? spaceTrim$2(`
46997
+ ? spaceTrim$1(`
48778
46998
  - The agent source does not have an INITIAL MESSAGE defined, generate one.
48779
46999
  - The INITIAL MESSAGE should be welcoming, informative about the agent capabilities and also should give some quick options to start the conversation with the agent.
48780
47000
  - The quick option looks like \`[👋 Hello](?message=Hello, how are you?)\`
@@ -48817,7 +47037,7 @@ class SelfLearningManager {
48817
47037
  */
48818
47038
  appendToAgentSource(section) {
48819
47039
  const currentSource = this.options.getAgentSource();
48820
- const newSource = padBook(validateBook(spaceTrim$2(currentSource) + section));
47040
+ const newSource = padBook(validateBook(spaceTrim$1(currentSource) + section));
48821
47041
  this.options.updateAgentSource(newSource);
48822
47042
  }
48823
47043
  }
@@ -48845,13 +47065,13 @@ function formatAgentMessageForJsonMode(content, isJsonMode) {
48845
47065
  }
48846
47066
  const parsedJson = tryParseJson(content);
48847
47067
  if (parsedJson === null) {
48848
- return spaceTrim$2((block) => `
47068
+ return spaceTrim$1((block) => `
48849
47069
  \`\`\`json
48850
47070
  ${block(content)}
48851
47071
  \`\`\`
48852
47072
  `);
48853
47073
  }
48854
- return spaceTrim$2((block) => `
47074
+ return spaceTrim$1((block) => `
48855
47075
  \`\`\`json
48856
47076
  ${block(JSON.stringify(parsedJson, null, 4))}
48857
47077
  \`\`\`
@@ -48883,7 +47103,7 @@ function formatSelfLearningSample(options) {
48883
47103
  const internalMessagesSection = options.internalMessages
48884
47104
  .map((internalMessage) => formatInternalLearningMessage(internalMessage))
48885
47105
  .join('\n\n');
48886
- return spaceTrim$2((block) => `
47106
+ return spaceTrim$1((block) => `
48887
47107
 
48888
47108
  USER MESSAGE
48889
47109
  ${block(options.userMessageContent)}
@@ -48901,7 +47121,7 @@ function formatSelfLearningSample(options) {
48901
47121
  * @private function of Agent
48902
47122
  */
48903
47123
  function formatInternalLearningMessage(internalMessage) {
48904
- return spaceTrim$2((block) => `
47124
+ return spaceTrim$1((block) => `
48905
47125
  INTERNAL MESSAGE
48906
47126
  ${block(stringifyInternalLearningPayload(internalMessage))}
48907
47127
  `);
@@ -49367,7 +47587,7 @@ function buildRemoteAgentSource(profile, meta) {
49367
47587
  .filter((line) => Boolean(line))
49368
47588
  .join('\n');
49369
47589
  const personaBlock = profile.personaDescription
49370
- ? spaceTrim$2((block) => `
47590
+ ? spaceTrim$1((block) => `
49371
47591
  PERSONA
49372
47592
  ${block(profile.personaDescription || '')}
49373
47593
  `)
@@ -49403,7 +47623,7 @@ class RemoteAgent extends Agent {
49403
47623
  // <- TODO: [🐱‍🚀] What about closed-source agents?
49404
47624
  // <- TODO: [🐱‍🚀] Maybe use promptbookFetch
49405
47625
  if (!profileResponse.ok) {
49406
- throw new Error(spaceTrim$2((block) => `
47626
+ throw new Error(spaceTrim$1((block) => `
49407
47627
  Failed to fetch remote agent profile:
49408
47628
 
49409
47629
  Agent URL: