@promptbook/remote-server 0.106.0-0 → 0.108.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/esm/index.es.js +1190 -141
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/src/_packages/components.index.d.ts +4 -0
  4. package/esm/typings/src/_packages/markdown-utils.index.d.ts +2 -0
  5. package/esm/typings/src/_packages/types.index.d.ts +15 -1
  6. package/esm/typings/src/_packages/utils.index.d.ts +2 -2
  7. package/esm/typings/src/book-components/BookEditor/BookEditor.d.ts +26 -2
  8. package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +10 -2
  9. package/esm/typings/src/book-components/Chat/utils/getChatMessageTimingDisplay.d.ts +26 -0
  10. package/esm/typings/src/book-components/Chat/utils/{getToolCallChipletText.d.ts → getToolCallChipletInfo.d.ts} +8 -8
  11. package/esm/typings/src/types/ToolCall.d.ts +76 -1
  12. package/esm/typings/src/utils/linguistic-hash/LinguisticHashLanguage.d.ts +41 -0
  13. package/esm/typings/src/utils/linguistic-hash/linguisticHash.d.ts +37 -0
  14. package/esm/typings/src/utils/linguistic-hash/linguisticHashTypes.d.ts +19 -0
  15. package/esm/typings/src/utils/linguistic-hash/linguisticHashWords.cs.d.ts +10 -0
  16. package/esm/typings/src/utils/linguistic-hash/linguisticHashWords.en.d.ts +10 -0
  17. package/esm/typings/src/utils/markdown/humanizeAiTextSources.d.ts +13 -0
  18. package/esm/typings/src/version.d.ts +1 -1
  19. package/package.json +2 -2
  20. package/umd/index.umd.js +1190 -141
  21. package/umd/index.umd.js.map +1 -1
  22. package/esm/typings/src/utils/misc/linguisticHash.d.ts +0 -9
  23. /package/esm/typings/src/utils/{misc → linguistic-hash}/linguisticHash.test.d.ts +0 -0
package/esm/index.es.js CHANGED
@@ -39,7 +39,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
39
39
  * @generated
40
40
  * @see https://github.com/webgptorg/promptbook
41
41
  */
42
- const PROMPTBOOK_ENGINE_VERSION = '0.106.0-0';
42
+ const PROMPTBOOK_ENGINE_VERSION = '0.108.0-0';
43
43
  /**
44
44
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
45
45
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -8192,13 +8192,125 @@ function escapePromptParameterValue(value, options) {
8192
8192
  return value.replace(pattern, '\\$&');
8193
8193
  }
8194
8194
  /**
8195
- * Builds the parameter name used in prompt placeholders.
8195
+ * Builds numeric parameter name used in prompt placeholders.
8196
8196
  *
8197
8197
  * @param index Zero-based parameter index.
8198
8198
  */
8199
- function buildParameterName(index) {
8199
+ function buildNumericParameterName(index) {
8200
8200
  return `${index + 1}`;
8201
8201
  }
8202
+ /**
8203
+ * Builds alphabetic parameter name used in prompt placeholders.
8204
+ *
8205
+ * @param index Zero-based parameter index.
8206
+ */
8207
+ function buildAlphabeticParameterName(index) {
8208
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz';
8209
+ let result = '';
8210
+ let remaining = index;
8211
+ while (remaining >= 0) {
8212
+ result = alphabet[remaining % alphabet.length] + result;
8213
+ remaining = Math.floor(remaining / alphabet.length) - 1;
8214
+ }
8215
+ return result;
8216
+ }
8217
+ /**
8218
+ * Converts a positive integer into a Roman numeral string.
8219
+ *
8220
+ * @param value Positive integer value.
8221
+ */
8222
+ function toRomanNumeral(value) {
8223
+ const romanTable = [
8224
+ { symbol: 'M', value: 1000 },
8225
+ { symbol: 'CM', value: 900 },
8226
+ { symbol: 'D', value: 500 },
8227
+ { symbol: 'CD', value: 400 },
8228
+ { symbol: 'C', value: 100 },
8229
+ { symbol: 'XC', value: 90 },
8230
+ { symbol: 'L', value: 50 },
8231
+ { symbol: 'XL', value: 40 },
8232
+ { symbol: 'X', value: 10 },
8233
+ { symbol: 'IX', value: 9 },
8234
+ { symbol: 'V', value: 5 },
8235
+ { symbol: 'IV', value: 4 },
8236
+ { symbol: 'I', value: 1 },
8237
+ ];
8238
+ let remaining = Math.max(1, Math.floor(value));
8239
+ let result = '';
8240
+ for (const entry of romanTable) {
8241
+ while (remaining >= entry.value) {
8242
+ result += entry.symbol;
8243
+ remaining -= entry.value;
8244
+ }
8245
+ }
8246
+ return result;
8247
+ }
8248
+ /**
8249
+ * Builds Roman numeral parameter name used in prompt placeholders.
8250
+ *
8251
+ * @param index Zero-based parameter index.
8252
+ */
8253
+ function buildRomanParameterName(index) {
8254
+ return toRomanNumeral(index + 1);
8255
+ }
8256
+ /**
8257
+ * Creates a parameter name builder that prefixes another builder.
8258
+ *
8259
+ * @param prefix Prefix to add.
8260
+ * @param builder Base builder to wrap.
8261
+ */
8262
+ function buildPrefixedParameterName(prefix, builder) {
8263
+ return (index) => `${prefix}${builder(index)}`;
8264
+ }
8265
+ /**
8266
+ * Ordered list of strategies for parameter naming.
8267
+ */
8268
+ const PARAMETER_NAME_STRATEGIES = [
8269
+ { buildName: buildNumericParameterName },
8270
+ { buildName: buildAlphabeticParameterName },
8271
+ { buildName: buildRomanParameterName },
8272
+ { buildName: buildPrefixedParameterName('p', buildNumericParameterName) },
8273
+ { buildName: buildPrefixedParameterName('p', buildAlphabeticParameterName) },
8274
+ ];
8275
+ /**
8276
+ * Collects bracketed tokens from parameter values to avoid placeholder collisions.
8277
+ *
8278
+ * @param values Parameter values to scan.
8279
+ */
8280
+ function collectBracketedParameterTokens(values) {
8281
+ const tokens = new Set();
8282
+ for (const value of values) {
8283
+ const pattern = /{(\w+)}/g;
8284
+ let match;
8285
+ while ((match = pattern.exec(value)) !== null) {
8286
+ const token = match[1];
8287
+ if (token) {
8288
+ tokens.add(token);
8289
+ }
8290
+ }
8291
+ }
8292
+ return tokens;
8293
+ }
8294
+ /**
8295
+ * Builds parameter names used in prompt placeholders while avoiding collisions.
8296
+ *
8297
+ * @param values Parameter values to scan for conflicting tokens.
8298
+ */
8299
+ function buildParameterNames(values) {
8300
+ const count = values.length;
8301
+ if (count === 0) {
8302
+ return [];
8303
+ }
8304
+ const conflicts = collectBracketedParameterTokens(values);
8305
+ for (const strategy of PARAMETER_NAME_STRATEGIES) {
8306
+ const names = Array.from({ length: count }, (_, index) => strategy.buildName(index));
8307
+ const hasConflict = names.some((name) => conflicts.has(name));
8308
+ if (!hasConflict) {
8309
+ return names;
8310
+ }
8311
+ }
8312
+ return Array.from({ length: count }, (_, index) => `${REPLACING_NONCE}${index + 1}`);
8313
+ }
8202
8314
  /**
8203
8315
  * Formats the placeholder used in the prompt body for a parameter.
8204
8316
  *
@@ -8253,26 +8365,40 @@ function prompt(strings, ...values) {
8253
8365
  return new PromptString(spaceTrim$2(strings.join('')));
8254
8366
  }
8255
8367
  const stringsWithHiddenParameters = strings.map((stringsItem) => hideBrackets(stringsItem));
8256
- const parameterEntries = values.map((value, index) => {
8257
- const name = buildParameterName(index);
8368
+ const parameterMetadata = values.map((value) => {
8258
8369
  const isPrompt = isPromptString(value);
8259
8370
  const stringValue = isPrompt ? value.toString() : valueToString(value);
8260
8371
  const isInline = isPrompt ? true : shouldInlineParameterValue(stringValue);
8261
8372
  const jsonValue = !isPrompt && !isInline ? normalizeJsonString(stringValue) : null;
8373
+ return { isPrompt, stringValue, isInline, jsonValue };
8374
+ });
8375
+ const parameterNames = buildParameterNames(parameterMetadata.map((entry) => entry.stringValue));
8376
+ const parameterEntries = parameterMetadata.map((entry, index) => {
8377
+ var _a;
8378
+ const name = (_a = parameterNames[index]) !== null && _a !== void 0 ? _a : buildNumericParameterName(index);
8262
8379
  const promptMarker = `${REPLACING_NONCE}prompt-${index}`;
8263
8380
  const parameterMarker = `${REPLACING_NONCE}parameter-${index}`;
8264
- const templateValue = isPrompt
8381
+ const templateValue = entry.isPrompt
8265
8382
  ? promptMarker
8266
- : isInline
8267
- ? escapePromptParameterValue(stringValue, { includeBraces: false })
8383
+ : entry.isInline
8384
+ ? escapePromptParameterValue(entry.stringValue, { includeBraces: false })
8268
8385
  : parameterMarker;
8269
- return { name, stringValue, jsonValue, isPrompt, isInline, promptMarker, parameterMarker, templateValue };
8386
+ return {
8387
+ name,
8388
+ stringValue: entry.stringValue,
8389
+ jsonValue: entry.jsonValue,
8390
+ isPrompt: entry.isPrompt,
8391
+ isInline: entry.isInline,
8392
+ promptMarker,
8393
+ parameterMarker,
8394
+ templateValue,
8395
+ };
8270
8396
  });
8271
8397
  const parameters = Object.fromEntries(parameterEntries.map((entry) => [entry.name, entry.templateValue]));
8272
- const parameterNames = parameterEntries.map((entry) => entry.name);
8398
+ const parameterNamesOrdered = parameterEntries.map((entry) => entry.name);
8273
8399
  // Combine strings and values
8274
8400
  let pipelineString = stringsWithHiddenParameters.reduce((result, stringsItem, i) => {
8275
- const parameterName = parameterNames[i];
8401
+ const parameterName = parameterNamesOrdered[i];
8276
8402
  return parameterName === undefined
8277
8403
  ? `${result}${stringsItem}`
8278
8404
  : `${result}${stringsItem}${formatParameterPlaceholder(parameterName)}`;
@@ -8285,7 +8411,7 @@ function prompt(strings, ...values) {
8285
8411
  if (!(error instanceof PipelineExecutionError)) {
8286
8412
  throw error;
8287
8413
  }
8288
- console.error({ pipelineString, parameters, parameterNames, error });
8414
+ console.error({ pipelineString, parameters, parameterNames: parameterNamesOrdered, error });
8289
8415
  throw new UnexpectedError(spaceTrim$2((block) => `
8290
8416
  Internal error in prompt template literal
8291
8417
 
@@ -8300,9 +8426,7 @@ function prompt(strings, ...values) {
8300
8426
  continue;
8301
8427
  }
8302
8428
  if (!entry.isInline) {
8303
- pipelineString = pipelineString
8304
- .split(entry.parameterMarker)
8305
- .join(formatParameterPlaceholder(entry.name));
8429
+ pipelineString = pipelineString.split(entry.parameterMarker).join(formatParameterPlaceholder(entry.name));
8306
8430
  }
8307
8431
  }
8308
8432
  const structuredParameters = parameterEntries.filter((entry) => !entry.isPrompt && !entry.isInline);
@@ -8322,18 +8446,6 @@ function prompt(strings, ...values) {
8322
8446
  * Note: [💞] Ignore a discrepancy between file name and entity name
8323
8447
  */
8324
8448
 
8325
- /**
8326
- * Simple wrapper `new Date().toISOString()`
8327
- *
8328
- * Note: `$` is used to indicate that this function is not a pure function - it is not deterministic because it depends on the current time
8329
- *
8330
- * @returns string_date branded type
8331
- * @public exported from `@promptbook/utils`
8332
- */
8333
- function $getCurrentDate() {
8334
- return new Date().toISOString();
8335
- }
8336
-
8337
8449
  /**
8338
8450
  * Computes SHA-256 hash of the given object
8339
8451
  *
@@ -8346,103 +8458,564 @@ function computeHash(value) {
8346
8458
  * TODO: [🥬][🥬] Use this ACRY
8347
8459
  */
8348
8460
 
8461
+ // spell-checker: disable
8349
8462
  /**
8350
- * Creates a human-readable hash as a short story sentence.
8463
+ * @@@
8351
8464
  *
8352
- * @public exported from `@promptbook/utils`
8353
- */
8354
- async function linguisticHash(input) {
8355
- const hash = computeHash(input);
8356
- return capitalize(createStorySentence(hash));
8357
- }
8358
- const HASH_SEGMENT_LENGTH = 8;
8359
- const STORY_OPENERS = [
8360
- 'once',
8361
- 'long ago',
8362
- 'at dawn',
8363
- 'at dusk',
8364
- 'suddenly',
8365
- 'quietly',
8366
- 'meanwhile',
8367
- 'today',
8368
- 'tonight',
8369
- 'in the end',
8370
- 'before long',
8371
- 'for a moment',
8465
+ * @private utility of `linguisticHash`
8466
+ */
8467
+ const ADJECTIVES$1 = [
8468
+ 'červený',
8469
+ 'modrý',
8470
+ 'zelený',
8471
+ 'žlutý',
8472
+ 'rychlý',
8473
+ 'pomalý',
8474
+ 'jasný',
8475
+ 'temný',
8476
+ 'veselý',
8477
+ 'smutný',
8478
+ 'statečný',
8479
+ 'klidný',
8480
+ 'chytrý',
8481
+ 'bystrý',
8482
+ 'dychtivý',
8483
+ 'honosný',
8484
+ 'velkolepý',
8485
+ 'hravý',
8486
+ 'laskavý',
8487
+ 'šťastný',
8488
+ 'hrdý',
8489
+ 'pošetilý',
8490
+ 'moudrý',
8491
+ 'mladý',
8492
+ 'starý',
8493
+ 'veliký',
8494
+ 'malý',
8495
+ 'drobný',
8496
+ 'obrovský',
8497
+ 'krátký',
8498
+ 'dlouhý',
8499
+ 'blízký',
8500
+ 'vzdálený',
8501
+ 'vnitřní',
8502
+ 'vnější',
8503
+ 'trpělivý',
8504
+ 'stálý',
8505
+ 'ušlechtilý',
8506
+ 'čistý',
8507
+ 'špinavý',
8508
+ 'čerstvý',
8509
+ 'zvětralý',
8510
+ 'ostrý',
8511
+ 'tupý',
8512
+ 'tlustý',
8513
+ 'tenký',
8514
+ 'široký',
8515
+ 'úzký',
8516
+ 'hluboký',
8517
+ 'mělký',
8518
+ 'mocný',
8519
+ 'jemný',
8520
+ 'divoký',
8521
+ 'tichý',
8522
+ 'hlučný',
8523
+ 'pokojný',
8524
+ 'rušný',
8525
+ 'prázdný',
8526
+ 'plný',
8527
+ 'kulatý',
8528
+ 'hranatý',
8529
+ 'plochý',
8530
+ 'křivý',
8531
+ 'tvrdý',
8532
+ 'měkký',
8533
+ 'teplý',
8534
+ 'chladný',
8535
+ 'sladký',
8536
+ 'kyselý',
8537
+ 'hořký',
8538
+ 'slaný',
8539
+ 'silný',
8540
+ 'slabý',
8541
+ 'pevný',
8542
+ 'pružný',
8543
+ 'křehký',
8544
+ 'houževnatý',
8545
+ 'lesklý',
8546
+ 'matný',
8547
+ 'kluzký',
8548
+ 'lepkavý',
8549
+ 'svěží',
8550
+ 'vybledlý',
8551
+ 'mlhavý',
8552
+ 'bouřlivý',
8553
+ 'slunný',
8554
+ 'větrný',
8555
+ 'deštivý',
8556
+ 'mrazivý',
8557
+ 'zlatý',
8558
+ 'stříbrný',
8559
+ 'ledový',
8560
+ 'žhavý',
8561
+ 'prastarý',
8562
+ 'moderní',
8563
+ 'skrytý',
8564
+ 'ztracený',
8565
+ 'nalezený',
8566
+ 'magický',
8567
+ 'tajemný',
8568
+ 'kosmický',
8569
+ 'hvězdný',
8570
+ 'měsíční',
8571
+ 'sluneční',
8572
+ 'mlžný',
8573
+ 'ranní',
8574
+ 'večerní',
8575
+ 'noční',
8576
+ 'denní',
8577
+ 'osamělý',
8578
+ 'společenský',
8579
+ 'soukromý',
8580
+ 'veřejný',
8581
+ 'tajný',
8582
+ 'slavný',
8583
+ 'jistý',
8584
+ 'neurčitý',
8585
+ 'prostý',
8586
+ 'snadný',
8587
+ 'krotký',
8588
+ 'mírný',
8589
+ 'horký',
8590
+ 'suchý',
8591
+ 'mokrý',
8592
+ 'vlhký',
8593
+ 'promočený',
8594
+ 'vyprahlý',
8595
+ 'hladový',
8596
+ 'žíznivý',
8597
+ 'ospalý',
8598
+ 'bdělý',
8599
+ 'unavený',
8600
+ 'líný',
8601
+ 'neklidný',
8602
+ 'nestálý',
8603
+ 'odvážný',
8604
+ 'bázlivý',
8605
+ 'upřímný',
8606
+ 'věrný',
8607
+ 'pravý',
8608
+ 'falešný',
8609
+ 'spravedlivý',
8610
+ 'jednoduchý',
8611
+ 'složitý',
8612
+ 'přirozený',
8613
+ 'umělý',
8614
+ 'živý',
8615
+ 'mrtvý',
8616
+ 'zvídavý',
8617
+ 'zvláštní',
8618
+ 'běžný',
8619
+ 'vzácný',
8620
+ 'jedinečný',
8621
+ 'základní',
8622
+ 'prvotní',
8623
+ 'hbitý',
8372
8624
  ];
8373
- const STORY_CONNECTORS = ['while', 'as', 'when', 'because', 'and', 'just as', 'after', 'before'];
8374
- const STORY_PREPOSITIONS = [
8375
- 'near',
8376
- 'beside',
8377
- 'under',
8378
- 'within',
8379
- 'beyond',
8380
- 'around',
8381
- 'behind',
8382
- 'across',
8383
- 'above',
8384
- 'beneath',
8385
- 'over',
8386
- 'inside',
8387
- 'outside',
8388
- 'along',
8625
+ const NOUNS$1 = [
8626
+ 'jablko',
8627
+ 'nebe',
8628
+ 'strom',
8629
+ 'liška',
8630
+ 'kočka',
8631
+ 'pták',
8632
+ 'pes',
8633
+ 'řeka',
8634
+ 'hora',
8635
+ 'les',
8636
+ 'oceán',
8637
+ 'hvězda',
8638
+ 'měsíc',
8639
+ 'slunce',
8640
+ 'mrak',
8641
+ 'květ',
8642
+ 'list',
8643
+ 'kámen',
8644
+ 'vítr',
8645
+ 'déšť',
8646
+ 'oheň',
8647
+ 'led',
8648
+ 'kniha',
8649
+ 'sen',
8650
+ 'píseň',
8651
+ 'cesta',
8652
+ 'brána',
8653
+ 'klíč',
8654
+ 'lampa',
8655
+ 'mapa',
8656
+ 'dům',
8657
+ 'město',
8658
+ 'most',
8659
+ 'pole',
8660
+ 'zahrada',
8661
+ 'jezero',
8662
+ 'pláž',
8663
+ 'ostrov',
8664
+ 'údolí',
8665
+ 'poušť',
8666
+ 'svět',
8667
+ 'duch',
8668
+ 'srdce',
8669
+ 'mysl',
8670
+ 'duše',
8671
+ 'život',
8672
+ 'čas',
8673
+ 'prostor',
8674
+ 'světlo',
8675
+ 'stín',
8676
+ 'zvuk',
8677
+ 'hudba',
8678
+ 'hlas',
8679
+ 'slovo',
8680
+ 'stránka',
8681
+ 'příběh',
8682
+ 'perla',
8683
+ 'zlato',
8684
+ 'stříbro',
8685
+ 'krystal',
8686
+ 'diamant',
8687
+ 'smaragd',
8688
+ 'rubín',
8689
+ 'stezka',
8690
+ 'vrchol',
8691
+ 'břeh',
8692
+ 'vlna',
8693
+ 'příliv',
8694
+ 'plamen',
8695
+ 'jiskra',
8696
+ 'paprsek',
8697
+ 'semínko',
8698
+ 'kořen',
8699
+ 'větev',
8700
+ 'pupen',
8701
+ 'trn',
8702
+ 'kůra',
8703
+ 'skořápka',
8704
+ 'pírko',
8705
+ 'křídlo',
8706
+ 'dráp',
8707
+ 'tlapa',
8708
+ 'hnízdo',
8709
+ 'jeskyně',
8710
+ 'hájek',
8711
+ 'věž',
8712
+ 'hrad',
8713
+ 'koruna',
8714
+ 'meč',
8715
+ 'štít',
8716
+ 'mince',
8717
+ 'drahokam',
8718
+ 'prsten',
8719
+ 'zvonek',
8720
+ 'hodiny',
8721
+ 'kompas',
8722
+ 'kotva',
8723
+ 'pochodeň',
8724
+ 'flétna',
8725
+ 'harfa',
8726
+ 'buben',
8727
+ 'čočka',
8728
+ 'sklo',
8729
+ 'písek',
8730
+ 'prach',
8731
+ 'mlha',
8732
+ 'rosa',
8733
+ 'svítání',
8734
+ 'soumrak',
8735
+ 'noc',
8736
+ 'den',
8737
+ 'rok',
8738
+ 'věk',
8739
+ 'blesk',
8740
+ 'kapka',
8741
+ 'bouře',
8742
+ 'sníh',
8743
+ 'kroupa',
8744
+ 'kouř',
8745
+ 'pára',
8746
+ 'plyn',
8747
+ 'kov',
8748
+ 'skála',
8749
+ 'hlína',
8750
+ 'sůl',
8751
+ 'cukr',
8752
+ 'dřevo',
8753
+ 'kost',
8754
+ 'kůže',
8755
+ 'tělo',
8756
+ 'krev',
8757
+ 'buňka',
8758
+ 'atom',
8759
+ 'tep',
8760
+ 'dech',
8761
+ 'vzdech',
8762
+ 'jméno',
8763
+ 'ozvěna',
8764
+ 'obraz',
8765
+ 'vize',
8766
+ 'myšlenka',
8767
+ 'nápad',
8768
+ 'plán',
8769
+ 'cíl',
8770
+ 'přání',
8771
+ 'naděje',
8772
+ 'strach',
8773
+ 'radost',
8774
+ 'láska',
8775
+ 'nenávist',
8776
+ 'vůle',
8777
+ 'síla',
8778
+ 'energie',
8779
+ 'pohyb',
8780
+ 'rychlost',
8781
+ 'místo',
8782
+ 'bod',
8783
+ 'linie',
8784
+ 'tvar',
8785
+ 'forma',
8786
+ 'velikost',
8787
+ 'hmota',
8788
+ 'váha',
8789
+ 'teplo',
8790
+ 'chlad',
8791
+ 'barva',
8792
+ 'tón',
8793
+ 'rytmus',
8794
+ 'nálada',
8795
+ 'stav',
8796
+ 'krok',
8797
+ 'pád',
8798
+ 'skok',
8799
+ 'běh',
8800
+ 'let',
8801
+ 'klid',
8802
+ 'úkol',
8803
+ 'práce',
8804
+ 'hra',
8805
+ 'sport',
8806
+ 'umění',
8807
+ 'řemeslo',
8808
+ 'nástroj',
8809
+ 'loď',
8810
+ 'člun',
8811
+ 'auto',
8812
+ 'kolo',
8813
+ 'vlak',
8814
+ 'letadlo',
8815
+ 'uzel',
8816
+ 'síť',
8817
+ 'krabice',
8818
+ 'taška',
8819
+ 'dóza',
8820
+ 'hrnek',
8821
+ 'miska',
8822
+ 'talíř',
8823
+ 'lžíce',
8824
+ 'vidlička',
8825
+ 'nůž',
8826
+ 'pánev',
8827
+ 'hrnec',
8828
+ 'postel',
8829
+ 'stůl',
8830
+ 'židle',
8831
+ 'dveře',
8832
+ 'stěna',
8833
+ 'střecha',
8834
+ 'podlaha',
8835
+ 'okno',
8836
+ 'chodba',
8389
8837
  ];
8390
- const STORY_TEMPLATES = [
8391
- (parts) => `${parts.opener}, the ${parts.adjective1} ${parts.noun1} was ${parts.verb1} ${parts.connector} the ${parts.adjective2} ${parts.noun2} was ${parts.verb2} ${parts.preposition} the ${parts.adjective3} ${parts.noun3}.`,
8392
- (parts) => `${parts.opener}, the ${parts.adjective1} ${parts.noun1} was ${parts.verb1} ${parts.preposition} the ${parts.adjective2} ${parts.noun2}, and the ${parts.adjective3} ${parts.noun3} was ${parts.verb2}.`,
8393
- (parts) => `${parts.opener}, the ${parts.adjective1} ${parts.noun1} was ${parts.verb1}, and the ${parts.adjective2} ${parts.noun2} was ${parts.verb2} ${parts.preposition} the ${parts.adjective3} ${parts.noun3}.`,
8394
- (parts) => `${parts.opener}, the ${parts.adjective1} ${parts.noun1} was ${parts.verb1} ${parts.connector} the ${parts.adjective2} ${parts.noun2} was ${parts.verb2}, ${parts.preposition} the ${parts.adjective3} ${parts.noun3}.`,
8838
+ const VERBS$1 = [
8839
+ 'skáče',
8840
+ 'tančí',
8841
+ 'letí',
8842
+ 'běží',
8843
+ 'zpívá',
8844
+ 'svítí',
8845
+ 'roste',
8846
+ 'plyne',
8847
+ 'padá',
8848
+ 'stoupá',
8849
+ 'spí',
8850
+ 'kráčí',
8851
+ 'mluví',
8852
+ 'myslí',
8853
+ 'sní',
8854
+ 'hledá',
8855
+ 'nachází',
8856
+ 'dává',
8857
+ 'bere',
8858
+ 'tvoří',
8859
+ 'hoří',
8860
+ 'mrzne',
8861
+ 'taje',
8862
+ 'dýchá',
8863
+ 'pulzuje',
8864
+ 'bije',
8865
+ 'žije',
8866
+ 'učí',
8867
+ 'ví',
8868
+ 'skrývá',
8869
+ 'ukazuje',
8870
+ 'láme',
8871
+ 'opravuje',
8872
+ 'ztrácí',
8873
+ 'nalézá',
8874
+ 'začíná',
8875
+ 'končí',
8876
+ 'plave',
8877
+ 'pluje',
8878
+ 'klouže',
8879
+ 'točí',
8880
+ 'mění',
8881
+ 'bledne',
8882
+ 'mizí',
8883
+ 'rodí',
8884
+ 'hučí',
8885
+ 'pláče',
8886
+ 'závodí',
8887
+ 'plíží',
8888
+ 'sleduje',
8889
+ 'slyší',
8890
+ 'cítí',
8891
+ 'touží',
8892
+ 'doufá',
8893
+ 'miluje',
8894
+ 'bloudí',
8895
+ 'putuje',
8896
+ 'cestuje',
8897
+ 'překračuje',
8898
+ 'potkává',
8899
+ 'drží',
8900
+ 'sdílí',
8901
+ 'jiskří',
8902
+ 'plápolá',
8903
+ 'léčí',
8904
+ 'řeší',
8905
+ 'otevírá',
8906
+ 'zavírá',
8907
+ 'zvedá',
8908
+ 'táhne',
8909
+ 'tlačí',
8910
+ 'hází',
8911
+ 'chytá',
8912
+ 'dělá',
8913
+ 'vidí',
8914
+ 'chutná',
8915
+ 'voní',
8916
+ 'spěchá',
8917
+ 'zastaví',
8918
+ 'jde',
8919
+ 'přichází',
8920
+ 'odchází',
8921
+ 'jedná',
8922
+ 'existuje',
8923
+ 'zmenšuje',
8924
+ 'rozšiřuje',
8925
+ 'zužuje',
8926
+ 'hřeje',
8927
+ 'chladí',
8928
+ 'suší',
8929
+ 'máčí',
8930
+ 'plní',
8931
+ 'vyprazdňuje',
8932
+ 'pouští',
8933
+ 'získává',
8934
+ 'vítězí',
8935
+ 'selhává',
8936
+ 'zkouší',
8937
+ 'používá',
8938
+ 'dostává',
8939
+ 'měří',
8940
+ 'stojí',
8941
+ 'dosahuje',
8942
+ 'míjí',
8943
+ 'udeří',
8944
+ 'vede',
8945
+ 'následuje',
8946
+ 'pomáhá',
8947
+ 'slouží',
8948
+ 'trénuje',
8949
+ 'kóduje',
8950
+ 'píše',
8951
+ 'čte',
8952
+ 'kreslí',
8953
+ 'maluje',
8954
+ 'tvaruje',
8955
+ 'spojuje',
8956
+ 'dělí',
8957
+ 'váže',
8958
+ 'zraňuje',
8959
+ 'chrání',
8960
+ 'bojuje',
8961
+ 'brání',
8962
+ 'útočí',
8963
+ 'uniká',
8964
+ 'lapá',
8965
+ 'osvobozuje',
8966
+ 'poutá',
8967
+ 'spřádá',
8968
+ 'tká',
8969
+ 'vrhá',
8970
+ 'nese',
8971
+ 'přenáší',
8972
+ 'vrací',
8973
+ 'zrychluje',
8974
+ 'zpomaluje',
8975
+ 'probouzí',
8976
+ 'uspává',
8977
+ 'šeptá',
8978
+ 'volá',
8979
+ 'hledí',
8980
+ 'čeká',
8981
+ 'bdí',
8982
+ 'rozkvétá',
8983
+ 'klíčí',
8984
+ 'zraje',
8985
+ 'chvěje',
8986
+ 'třpytí',
8987
+ 'shromažďuje',
8988
+ 'rozhazuje',
8989
+ 'tápe',
8990
+ 'žhne',
8991
+ 'vibruje',
8992
+ 'šumí',
8993
+ 'stéká',
8994
+ 'vypráví',
8995
+ 'plánuje',
8996
+ 'počítá',
8997
+ 'váhá',
8998
+ 'riskuje',
8395
8999
  ];
8396
9000
  /**
8397
- * Extracts a deterministic numeric seed from a SHA-256 hash.
8398
- */
8399
- function getHashSeed(hash, segmentIndex) {
8400
- const expandedHash = `${hash}${hash}`;
8401
- const start = (segmentIndex * HASH_SEGMENT_LENGTH + segmentIndex) % hash.length;
8402
- return parseInt(expandedHash.substring(start, start + HASH_SEGMENT_LENGTH), 16);
8403
- }
8404
- /**
8405
- * Picks a deterministic item from a list based on the hash seed.
8406
- */
8407
- function pickFromHash(hash, segmentIndex, list) {
8408
- const seed = getHashSeed(hash, segmentIndex);
8409
- return list[seed % list.length];
8410
- }
8411
- /**
8412
- * Index constants for story part selection to avoid magic numbers.
8413
- */
8414
- const ADJECTIVE3_INDEX = 9;
8415
- const NOUN3_INDEX = 10;
8416
- /**
8417
- * Creates the deterministic story parts used by the sentence templates.
9001
+ * Czech word lists used by the linguistic hash.
9002
+ *
9003
+ * @private utility of `linguisticHash`
8418
9004
  */
8419
- function createStoryParts(hash) {
8420
- return {
8421
- opener: pickFromHash(hash, 0, STORY_OPENERS),
8422
- connector: pickFromHash(hash, 1, STORY_CONNECTORS),
8423
- preposition: pickFromHash(hash, 2, STORY_PREPOSITIONS),
8424
- adjective1: pickFromHash(hash, 3, ADJECTIVES),
8425
- noun1: pickFromHash(hash, 4, NOUNS),
8426
- verb1: pickFromHash(hash, 5, VERBS),
8427
- adjective2: pickFromHash(hash, 6, ADJECTIVES),
8428
- noun2: pickFromHash(hash, 7, NOUNS),
8429
- verb2: pickFromHash(hash, 8, VERBS),
8430
- adjective3: pickFromHash(hash, ADJECTIVE3_INDEX, ADJECTIVES),
8431
- noun3: pickFromHash(hash, NOUN3_INDEX, NOUNS),
8432
- };
8433
- }
9005
+ const LINGUISTIC_HASH_WORD_LISTS_CS = {
9006
+ adjective: ADJECTIVES$1,
9007
+ noun: NOUNS$1,
9008
+ verb: VERBS$1,
9009
+ };
8434
9010
  /**
8435
- * Index constant for story template selection to avoid magic numbers.
9011
+ * Note: [💞] Ignore a discrepancy between file name and entity name
8436
9012
  */
8437
- const STORY_TEMPLATE_INDEX = 11;
9013
+
8438
9014
  /**
8439
- * Builds a short, memorable story sentence from the hash.
9015
+ * @@@
9016
+ *
9017
+ * @private utility of `linguisticHash`
8440
9018
  */
8441
- function createStorySentence(hash) {
8442
- const parts = createStoryParts(hash);
8443
- const template = pickFromHash(hash, STORY_TEMPLATE_INDEX, STORY_TEMPLATES);
8444
- return template(parts).trim();
8445
- }
8446
9019
  const ADJECTIVES = [
8447
9020
  'red',
8448
9021
  'blue',
@@ -9117,8 +9690,215 @@ const VERBS = [
9117
9690
  'spinning',
9118
9691
  ];
9119
9692
  /**
9120
- * TODO: Prompt: Extract number constants and word list to a separate file for reuse.
9693
+ * English word lists used by the linguistic hash.
9694
+ *
9695
+ * @private utility of `linguisticHash`
9696
+ */
9697
+ const LINGUISTIC_HASH_WORD_LISTS_EN = {
9698
+ adjective: ADJECTIVES,
9699
+ noun: NOUNS,
9700
+ verb: VERBS,
9701
+ };
9702
+ /**
9703
+ * Note: [💞] Ignore a discrepancy between file name and entity name
9704
+ */
9705
+
9706
+ /**
9707
+ * Default language used for linguistic hashes.
9708
+ *
9709
+ * @private utility of `linguisticHash`
9710
+ */
9711
+ const DEFAULT_LINGUISTIC_HASH_LANGUAGE = 'en';
9712
+ /**
9713
+ * @@@
9714
+ *
9715
+ * @private utility of `linguisticHash`
9716
+ */
9717
+ const LANGUAGE_CONFIGS = {
9718
+ en: {
9719
+ language: 'en',
9720
+ label: 'English',
9721
+ wordLists: LINGUISTIC_HASH_WORD_LISTS_EN,
9722
+ },
9723
+ cs: {
9724
+ language: 'cs',
9725
+ label: 'Czech',
9726
+ wordLists: LINGUISTIC_HASH_WORD_LISTS_CS,
9727
+ },
9728
+ };
9729
+ /**
9730
+ * Normalizes a requested language to a supported linguistic hash language.
9731
+ *
9732
+ * @private utility of `linguisticHash`
9733
+ */
9734
+ function normalizeLinguisticHashLanguage(language) {
9735
+ if (typeof language !== 'string') {
9736
+ return DEFAULT_LINGUISTIC_HASH_LANGUAGE;
9737
+ }
9738
+ const normalized = language.trim().toLowerCase();
9739
+ if (normalized === 'cs') {
9740
+ return 'cs';
9741
+ }
9742
+ if (normalized === 'en') {
9743
+ return 'en';
9744
+ }
9745
+ return DEFAULT_LINGUISTIC_HASH_LANGUAGE;
9746
+ }
9747
+ /**
9748
+ * Returns the language configuration for linguistic hash generation.
9749
+ *
9750
+ * @private utility of `linguisticHash`
9751
+ */
9752
+ function getLinguisticHashLanguageConfig(language) {
9753
+ const normalized = normalizeLinguisticHashLanguage(language);
9754
+ return LANGUAGE_CONFIGS[normalized];
9755
+ }
9756
+
9757
+ // <- TODO: !!!! Remove re-exports
9758
+ /**
9759
+ * Creates a human-readable hash as a short, story-like phrase.
9760
+ *
9761
+ * @param wordCount how many words to include (defaults to {@link DEFAULT_LINGUISTIC_HASH_WORD_COUNT}, clamped to
9762
+ * {@link MIN_LINGUISTIC_HASH_WORD_COUNT}..{@link MAX_LINGUISTIC_HASH_WORD_COUNT})
9763
+ * @param language optional language code (defaults to {@link DEFAULT_LINGUISTIC_HASH_LANGUAGE})
9764
+ *
9765
+ * @public exported from `@promptbook/utils`
9766
+ */
9767
+ async function linguisticHash(input, wordCount, language) {
9768
+ const hash = computeHash(input);
9769
+ const normalizedWordCount = normalizeLinguisticHashWordCount(wordCount);
9770
+ const languageConfig = getLinguisticHashLanguageConfig(language);
9771
+ const words = createLinguisticHashWords(hash, normalizedWordCount, languageConfig.wordLists);
9772
+ return capitalize(words.join(' '));
9773
+ }
9774
+ /**
9775
+ * @@@
9776
+ *
9777
+ * @private utility of `linguisticHash`
9778
+ */
9779
+ const HASH_SEGMENT_LENGTH = 8;
9780
+ /**
9781
+ * The minimum number of words for a linguistic hash.
9782
+ *
9783
+ * @private utility of `linguisticHash`
9784
+ */
9785
+ const MIN_LINGUISTIC_HASH_WORD_COUNT = 1;
9786
+ /**
9787
+ * The default number of words for a linguistic hash.
9788
+ *
9789
+ * @private utility of `linguisticHash`
9790
+ */
9791
+ const DEFAULT_LINGUISTIC_HASH_WORD_COUNT = 7;
9792
+ /**
9793
+ * Extracts a deterministic numeric seed from a SHA-256 hash.
9794
+ *
9795
+ * @private utility of `linguisticHash`
9796
+ */
9797
+ function getHashSeed(hash, segmentIndex) {
9798
+ const expandedHash = `${hash}${hash}`;
9799
+ const start = (segmentIndex * HASH_SEGMENT_LENGTH + segmentIndex) % hash.length;
9800
+ return parseInt(expandedHash.substring(start, start + HASH_SEGMENT_LENGTH), 16);
9801
+ }
9802
+ /**
9803
+ * Picks a deterministic item from a list based on the hash seed.
9804
+ *
9805
+ * @private utility of `linguisticHash`
9806
+ */
9807
+ function pickFromHash(hash, segmentIndex, list) {
9808
+ const seed = getHashSeed(hash, segmentIndex);
9809
+ return list[seed % list.length];
9810
+ }
9811
+ /**
9812
+ * Ordered word kinds used to build the linguistic hash output.
9813
+ *
9814
+ * @private utility of `linguisticHash`
9815
+ */
9816
+ const WORD_SEQUENCE = [
9817
+ 'adjective',
9818
+ 'noun',
9819
+ 'verb',
9820
+ 'adjective',
9821
+ 'noun',
9822
+ 'verb',
9823
+ 'adjective',
9824
+ 'noun',
9825
+ 'verb',
9826
+ 'adjective',
9827
+ 'noun',
9828
+ 'verb',
9829
+ 'adjective',
9830
+ 'noun',
9831
+ 'verb',
9832
+ 'adjective',
9833
+ 'noun',
9834
+ 'verb',
9835
+ 'adjective',
9836
+ 'noun',
9837
+ ];
9838
+ /**
9839
+ * The maximum number of words for a linguistic hash.
9840
+ *
9841
+ * @private utility of `linguisticHash`
9842
+ */
9843
+ const MAX_LINGUISTIC_HASH_WORD_COUNT = WORD_SEQUENCE.length;
9844
+ /**
9845
+ * Index of the noun used for single-word hashes.
9846
+ *
9847
+ * @private utility of `linguisticHash`
9848
+ */
9849
+ const SINGLE_WORD_INDEX = 1;
9850
+ /**
9851
+ * Normalizes the word count to a supported integer range.
9852
+ *
9853
+ * @private utility of `linguisticHash`
9854
+ */
9855
+ function normalizeLinguisticHashWordCount(wordCount) {
9856
+ if (typeof wordCount !== 'number' || !Number.isFinite(wordCount)) {
9857
+ return DEFAULT_LINGUISTIC_HASH_WORD_COUNT;
9858
+ }
9859
+ const rounded = Math.round(wordCount);
9860
+ return Math.min(MAX_LINGUISTIC_HASH_WORD_COUNT, Math.max(MIN_LINGUISTIC_HASH_WORD_COUNT, rounded));
9861
+ }
9862
+ /**
9863
+ * Picks a deterministic word from the hash by kind.
9864
+ *
9865
+ * @private utility of `linguisticHash`
9866
+ */
9867
+ function pickWordFromHash(hash, segmentIndex, wordKind, wordLists) {
9868
+ return pickFromHash(hash, segmentIndex, wordLists[wordKind]);
9869
+ }
9870
+ /**
9871
+ * Creates the deterministic word sequence used for the linguistic hash output.
9872
+ *
9873
+ * @private utility of `linguisticHash`
9121
9874
  */
9875
+ function createLinguisticHashWordSequence(hash, wordLists) {
9876
+ return WORD_SEQUENCE.map((wordKind, index) => pickWordFromHash(hash, index, wordKind, wordLists));
9877
+ }
9878
+ /**
9879
+ * Selects the requested number of words from the hash output.
9880
+ *
9881
+ * @private utility of `linguisticHash`
9882
+ */
9883
+ function createLinguisticHashWords(hash, wordCount, wordLists) {
9884
+ const words = createLinguisticHashWordSequence(hash, wordLists);
9885
+ if (wordCount === 1) {
9886
+ return [words[SINGLE_WORD_INDEX]];
9887
+ }
9888
+ return words.slice(0, wordCount);
9889
+ }
9890
+
9891
+ /**
9892
+ * Simple wrapper `new Date().toISOString()`
9893
+ *
9894
+ * Note: `$` is used to indicate that this function is not a pure function - it is not deterministic because it depends on the current time
9895
+ *
9896
+ * @returns string_date branded type
9897
+ * @public exported from `@promptbook/utils`
9898
+ */
9899
+ function $getCurrentDate() {
9900
+ return new Date().toISOString();
9901
+ }
9122
9902
 
9123
9903
  /**
9124
9904
  * Makes first letter of a string lowercase
@@ -16610,6 +17390,21 @@ function book(strings, ...values) {
16610
17390
  * Note: [💞] Ignore a discrepancy between file name and entity name
16611
17391
  */
16612
17392
 
17393
+ /**
17394
+ * Tool call name emitted while preparing a GPT assistant for an agent.
17395
+ *
17396
+ * @public exported from `@promptbook/types`
17397
+ */
17398
+ const ASSISTANT_PREPARATION_TOOL_CALL_NAME = 'assistant_preparation';
17399
+ /**
17400
+ * Checks whether a tool call is the assistant preparation marker.
17401
+ *
17402
+ * @public exported from `@promptbook/types`
17403
+ */
17404
+ function isAssistantPreparationToolCall(toolCall) {
17405
+ return toolCall.name === ASSISTANT_PREPARATION_TOOL_CALL_NAME;
17406
+ }
17407
+
16613
17408
  /*! *****************************************************************************
16614
17409
  Copyright (c) Microsoft Corporation.
16615
17410
 
@@ -17735,14 +18530,27 @@ function humanizeAiTextEmdashed(aiText) {
17735
18530
  * @public exported from `@promptbook/markdown-utils`
17736
18531
  */
17737
18532
  function humanizeAiTextQuotes(aiText) {
17738
- return aiText
17739
- .replace(/[“”„‟«»❝❞〝〞〟"]/g, '"')
17740
- .replace(/[‚‘’‛‹›❛❜'ʼ]/g, "'");
18533
+ return aiText.replace(/[“”„‟«»❝❞〝〞〟"]/g, '"').replace(/[‚‘’‛‹›❛❜'ʼ]/g, "'");
17741
18534
  }
17742
18535
  /**
17743
18536
  * Note: [🏂] This function is not tested by itself but together with other cleanup functions with `humanizeAiText`
17744
18537
  */
17745
18538
 
18539
+ /**
18540
+ * Remove bracketed source citation artifacts like `\u30105:1\u2020source\u3011`.
18541
+ *
18542
+ * Note: [??] This function is idempotent.
18543
+ * Tip: If you want to do the full cleanup, look for `humanizeAiText` exported `@promptbook/markdown-utils`
18544
+ *
18545
+ * @public exported from `@promptbook/markdown-utils`
18546
+ */
18547
+ function humanizeAiTextSources(aiText) {
18548
+ return aiText.replace(/[ \t]*\u3010\s*\d+(?:\s*:\s*\d+)?\s*\u2020source\s*\u3011/g, '');
18549
+ }
18550
+ /**
18551
+ * Note: [??] This function is not tested by itself but together with other cleanup functions with `humanizeAiText`
18552
+ */
18553
+
17746
18554
  /**
17747
18555
  * Change unprintable hard spaces to regular spaces and drop zero-width spaces
17748
18556
  *
@@ -17752,9 +18560,7 @@ function humanizeAiTextQuotes(aiText) {
17752
18560
  * @public exported from `@promptbook/markdown-utils`
17753
18561
  */
17754
18562
  function humanizeAiTextWhitespace(aiText) {
17755
- return aiText
17756
- .replace(/[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g, ' ')
17757
- .replace(/[\u200B\uFEFF\u2060]/g, '');
18563
+ return aiText.replace(/[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g, ' ').replace(/[\u200B\uFEFF\u2060]/g, '');
17758
18564
  }
17759
18565
  /**
17760
18566
  * Note: [🏂] This function is not tested by itself but together with other cleanup functions with `humanizeAiText`
@@ -17773,6 +18579,7 @@ function humanizeAiText(aiText) {
17773
18579
  cleanedText = humanizeAiTextEllipsis(cleanedText);
17774
18580
  cleanedText = humanizeAiTextEmdashed(cleanedText);
17775
18581
  cleanedText = humanizeAiTextQuotes(cleanedText);
18582
+ cleanedText = humanizeAiTextSources(cleanedText);
17776
18583
  cleanedText = humanizeAiTextWhitespace(cleanedText);
17777
18584
  return cleanedText;
17778
18585
  }
@@ -20263,17 +21070,32 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20263
21070
  });
20264
21071
  }
20265
21072
  async createNewAssistant(options) {
21073
+ var _a, _b, _c;
20266
21074
  if (!this.isCreatingNewAssistantsAllowed) {
20267
21075
  throw new NotAllowed(`Creating new assistants is not allowed. Set \`isCreatingNewAssistantsAllowed: true\` in options to enable this feature.`);
20268
21076
  }
20269
21077
  // await this.playground();
20270
21078
  const { name, instructions, knowledgeSources, tools } = options;
21079
+ const preparationStartedAtMs = Date.now();
21080
+ const knowledgeSourcesCount = (_a = knowledgeSources === null || knowledgeSources === void 0 ? void 0 : knowledgeSources.length) !== null && _a !== void 0 ? _a : 0;
21081
+ const toolsCount = (_b = tools === null || tools === void 0 ? void 0 : tools.length) !== null && _b !== void 0 ? _b : 0;
21082
+ if (this.options.isVerbose) {
21083
+ console.info('[🤰]', 'Starting OpenAI assistant creation', {
21084
+ name,
21085
+ knowledgeSourcesCount,
21086
+ toolsCount,
21087
+ instructionsLength: instructions.length,
21088
+ });
21089
+ }
20271
21090
  const client = await this.getClient();
20272
21091
  let vectorStoreId;
20273
21092
  // If knowledge sources are provided, create a vector store with them
20274
21093
  if (knowledgeSources && knowledgeSources.length > 0) {
20275
21094
  if (this.options.isVerbose) {
20276
- console.info(`📚 Creating vector store with ${knowledgeSources.length} knowledge sources...`);
21095
+ console.info('[🤰]', 'Creating vector store with knowledge sources', {
21096
+ name,
21097
+ knowledgeSourcesCount,
21098
+ });
20277
21099
  }
20278
21100
  // Create a vector store
20279
21101
  const vectorStore = await client.beta.vectorStores.create({
@@ -20281,12 +21103,22 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20281
21103
  });
20282
21104
  vectorStoreId = vectorStore.id;
20283
21105
  if (this.options.isVerbose) {
20284
- console.info(`✅ Vector store created: ${vectorStoreId}`);
21106
+ console.info('[🤰]', 'Vector store created', {
21107
+ vectorStoreId,
21108
+ });
20285
21109
  }
20286
21110
  // Upload files from knowledge sources to the vector store
20287
21111
  const fileStreams = [];
20288
- for (const source of knowledgeSources) {
21112
+ for (const [index, source] of knowledgeSources.entries()) {
20289
21113
  try {
21114
+ if (this.options.isVerbose) {
21115
+ console.info('[🤰]', 'Processing knowledge source', {
21116
+ index: index + 1,
21117
+ total: knowledgeSources.length,
21118
+ source,
21119
+ sourceType: source.startsWith('http') || source.startsWith('https') ? 'url' : 'file',
21120
+ });
21121
+ }
20290
21122
  // Check if it's a URL
20291
21123
  if (source.startsWith('http://') || source.startsWith('https://')) {
20292
21124
  // Download the file
@@ -20331,7 +21163,10 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20331
21163
  files: fileStreams,
20332
21164
  });
20333
21165
  if (this.options.isVerbose) {
20334
- console.info(`✅ Uploaded ${fileStreams.length} files to vector store`);
21166
+ console.info('[🤰]', 'Uploaded files to vector store', {
21167
+ vectorStoreId,
21168
+ fileCount: fileStreams.length,
21169
+ });
20335
21170
  }
20336
21171
  }
20337
21172
  catch (error) {
@@ -20359,8 +21194,21 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20359
21194
  },
20360
21195
  };
20361
21196
  }
21197
+ if (this.options.isVerbose) {
21198
+ console.info('[🤰]', 'Creating OpenAI assistant', {
21199
+ name,
21200
+ model: assistantConfig.model,
21201
+ toolCount: (_c = assistantConfig === null || assistantConfig === void 0 ? void 0 : assistantConfig.tools) === null || _c === void 0 ? void 0 : _c.length,
21202
+ hasVectorStore: Boolean(vectorStoreId),
21203
+ });
21204
+ }
20362
21205
  const assistant = await client.beta.assistants.create(assistantConfig);
20363
- console.log(`✅ Assistant created: ${assistant.id}`);
21206
+ if (this.options.isVerbose) {
21207
+ console.info('[🤰]', 'OpenAI assistant created', {
21208
+ assistantId: assistant.id,
21209
+ elapsedMs: Date.now() - preparationStartedAtMs,
21210
+ });
21211
+ }
20364
21212
  // TODO: [🐱‍🚀] Try listing existing assistants
20365
21213
  // TODO: [🐱‍🚀] Try marking existing assistants by DISCRIMINANT
20366
21214
  // TODO: [🐱‍🚀] Allow to update and reconnect to existing assistants
@@ -20371,17 +21219,34 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20371
21219
  });
20372
21220
  }
20373
21221
  async updateAssistant(options) {
21222
+ var _a, _b, _c, _d;
20374
21223
  if (!this.isCreatingNewAssistantsAllowed) {
20375
21224
  throw new NotAllowed(`Updating assistants is not allowed. Set \`isCreatingNewAssistantsAllowed: true\` in options to enable this feature.`);
20376
21225
  }
20377
21226
  const { assistantId, name, instructions, knowledgeSources, tools } = options;
21227
+ const preparationStartedAtMs = Date.now();
21228
+ const knowledgeSourcesCount = (_a = knowledgeSources === null || knowledgeSources === void 0 ? void 0 : knowledgeSources.length) !== null && _a !== void 0 ? _a : 0;
21229
+ const toolsCount = (_b = tools === null || tools === void 0 ? void 0 : tools.length) !== null && _b !== void 0 ? _b : 0;
21230
+ if (this.options.isVerbose) {
21231
+ console.info('[🤰]', 'Starting OpenAI assistant update', {
21232
+ assistantId,
21233
+ name,
21234
+ knowledgeSourcesCount,
21235
+ toolsCount,
21236
+ instructionsLength: (_c = instructions === null || instructions === void 0 ? void 0 : instructions.length) !== null && _c !== void 0 ? _c : 0,
21237
+ });
21238
+ }
20378
21239
  const client = await this.getClient();
20379
21240
  let vectorStoreId;
20380
21241
  // If knowledge sources are provided, create a vector store with them
20381
21242
  // TODO: [🧠] Reuse vector store creation logic from createNewAssistant
20382
21243
  if (knowledgeSources && knowledgeSources.length > 0) {
20383
21244
  if (this.options.isVerbose) {
20384
- console.info(`📚 Creating vector store for update with ${knowledgeSources.length} knowledge sources...`);
21245
+ console.info('[🤰]', 'Creating vector store for assistant update', {
21246
+ assistantId,
21247
+ name,
21248
+ knowledgeSourcesCount,
21249
+ });
20385
21250
  }
20386
21251
  // Create a vector store
20387
21252
  const vectorStore = await client.beta.vectorStores.create({
@@ -20389,12 +21254,22 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20389
21254
  });
20390
21255
  vectorStoreId = vectorStore.id;
20391
21256
  if (this.options.isVerbose) {
20392
- console.info(`✅ Vector store created: ${vectorStoreId}`);
21257
+ console.info('[🤰]', 'Vector store created for assistant update', {
21258
+ vectorStoreId,
21259
+ });
20393
21260
  }
20394
21261
  // Upload files from knowledge sources to the vector store
20395
21262
  const fileStreams = [];
20396
- for (const source of knowledgeSources) {
21263
+ for (const [index, source] of knowledgeSources.entries()) {
20397
21264
  try {
21265
+ if (this.options.isVerbose) {
21266
+ console.info('[🤰]', 'Processing knowledge source for update', {
21267
+ index: index + 1,
21268
+ total: knowledgeSources.length,
21269
+ source,
21270
+ sourceType: source.startsWith('http') || source.startsWith('https') ? 'url' : 'file',
21271
+ });
21272
+ }
20398
21273
  // Check if it's a URL
20399
21274
  if (source.startsWith('http://') || source.startsWith('https://')) {
20400
21275
  // Download the file
@@ -20439,7 +21314,10 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20439
21314
  files: fileStreams,
20440
21315
  });
20441
21316
  if (this.options.isVerbose) {
20442
- console.info(`✅ Uploaded ${fileStreams.length} files to vector store`);
21317
+ console.info('[🤰]', 'Uploaded files to vector store for update', {
21318
+ vectorStoreId,
21319
+ fileCount: fileStreams.length,
21320
+ });
20443
21321
  }
20444
21322
  }
20445
21323
  catch (error) {
@@ -20463,9 +21341,20 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20463
21341
  },
20464
21342
  };
20465
21343
  }
21344
+ if (this.options.isVerbose) {
21345
+ console.info('[🤰]', 'Updating OpenAI assistant', {
21346
+ assistantId,
21347
+ name,
21348
+ toolCount: (_d = assistantUpdate === null || assistantUpdate === void 0 ? void 0 : assistantUpdate.tools) === null || _d === void 0 ? void 0 : _d.length,
21349
+ hasVectorStore: Boolean(vectorStoreId),
21350
+ });
21351
+ }
20466
21352
  const assistant = await client.beta.assistants.update(assistantId, assistantUpdate);
20467
21353
  if (this.options.isVerbose) {
20468
- console.log(`✅ Assistant updated: ${assistant.id}`);
21354
+ console.info('[🤰]', 'OpenAI assistant updated', {
21355
+ assistantId: assistant.id,
21356
+ elapsedMs: Date.now() - preparationStartedAtMs,
21357
+ });
20469
21358
  }
20470
21359
  return new OpenAiAssistantExecutionTools({
20471
21360
  ...this.options,
@@ -20503,6 +21392,33 @@ const DISCRIMINANT = 'OPEN_AI_ASSISTANT_V1';
20503
21392
  * TODO: [🧠][🌰] Allow to pass `title` for tracking purposes
20504
21393
  */
20505
21394
 
21395
+ /**
21396
+ * Emits a progress update to signal assistant preparation before long setup work.
21397
+ */
21398
+ function emitAssistantPreparationProgress(options) {
21399
+ const startedAt = $getCurrentDate();
21400
+ options.onProgress({
21401
+ content: '',
21402
+ modelName: options.modelName,
21403
+ timing: {
21404
+ start: startedAt,
21405
+ complete: startedAt,
21406
+ },
21407
+ usage: UNCERTAIN_USAGE,
21408
+ rawPromptContent: options.prompt.content,
21409
+ rawRequest: null,
21410
+ rawResponse: {
21411
+ status: 'assistant_preparation',
21412
+ },
21413
+ toolCalls: [
21414
+ {
21415
+ name: ASSISTANT_PREPARATION_TOOL_CALL_NAME,
21416
+ arguments: options.phase ? { phase: options.phase } : {},
21417
+ createdAt: startedAt,
21418
+ },
21419
+ ],
21420
+ });
21421
+ }
20506
21422
  /**
20507
21423
  * Execution Tools for calling LLM models with a predefined agent "soul"
20508
21424
  * This wraps underlying LLM execution tools and applies agent-specific system prompts and requirements
@@ -20561,10 +21477,32 @@ class AgentLlmExecutionTools {
20561
21477
  */
20562
21478
  async getModelRequirements() {
20563
21479
  if (this._cachedModelRequirements === null) {
21480
+ const preparationStartedAtMs = Date.now();
21481
+ if (this.options.isVerbose) {
21482
+ console.info('[🤰]', 'Preparing agent model requirements', {
21483
+ agent: this.title,
21484
+ });
21485
+ }
20564
21486
  // Get available models from underlying LLM tools for best model selection
21487
+ const availableModelsStartedAtMs = Date.now();
20565
21488
  const availableModels = await this.options.llmTools.listModels();
21489
+ if (this.options.isVerbose) {
21490
+ console.info('[🤰]', 'Available models resolved for agent', {
21491
+ agent: this.title,
21492
+ modelCount: availableModels.length,
21493
+ elapsedMs: Date.now() - availableModelsStartedAtMs,
21494
+ });
21495
+ }
21496
+ const requirementsStartedAtMs = Date.now();
20566
21497
  this._cachedModelRequirements = await createAgentModelRequirements(this.options.agentSource, undefined, // Let the function pick the best model
20567
21498
  availableModels);
21499
+ if (this.options.isVerbose) {
21500
+ console.info('[🤰]', 'Agent model requirements ready', {
21501
+ agent: this.title,
21502
+ elapsedMs: Date.now() - requirementsStartedAtMs,
21503
+ totalElapsedMs: Date.now() - preparationStartedAtMs,
21504
+ });
21505
+ }
20568
21506
  }
20569
21507
  return this._cachedModelRequirements;
20570
21508
  }
@@ -20718,14 +21656,26 @@ class AgentLlmExecutionTools {
20718
21656
  if (cached) {
20719
21657
  if (cached.requirementsHash === requirementsHash) {
20720
21658
  if (this.options.isVerbose) {
20721
- console.log(`1️⃣ Using cached OpenAI Assistant for agent ${this.title}...`);
21659
+ console.info('[🤰]', 'Using cached OpenAI Assistant', {
21660
+ agent: this.title,
21661
+ assistantId: cached.assistantId,
21662
+ });
20722
21663
  }
20723
21664
  assistant = this.options.llmTools.getAssistant(cached.assistantId);
20724
21665
  }
20725
21666
  else {
20726
21667
  if (this.options.isVerbose) {
20727
- console.log(`1️⃣ Updating OpenAI Assistant for agent ${this.title}...`);
21668
+ console.info('[🤰]', 'Updating OpenAI Assistant', {
21669
+ agent: this.title,
21670
+ assistantId: cached.assistantId,
21671
+ });
20728
21672
  }
21673
+ emitAssistantPreparationProgress({
21674
+ onProgress,
21675
+ prompt,
21676
+ modelName: this.modelName,
21677
+ phase: 'Updating assistant',
21678
+ });
20729
21679
  assistant = await this.options.llmTools.updateAssistant({
20730
21680
  assistantId: cached.assistantId,
20731
21681
  name: this.title,
@@ -20741,9 +21691,17 @@ class AgentLlmExecutionTools {
20741
21691
  }
20742
21692
  else {
20743
21693
  if (this.options.isVerbose) {
20744
- console.log(`1️⃣ Creating new OpenAI Assistant for agent ${this.title}...`);
21694
+ console.info('[🤰]', 'Creating new OpenAI Assistant', {
21695
+ agent: this.title,
21696
+ });
20745
21697
  }
20746
21698
  // <- TODO: [🐱‍🚀] Check also `isCreatingNewAssistantsAllowed` and warn about it
21699
+ emitAssistantPreparationProgress({
21700
+ onProgress,
21701
+ prompt,
21702
+ modelName: this.modelName,
21703
+ phase: 'Creating assistant',
21704
+ });
20747
21705
  assistant = await this.options.llmTools.createNewAssistant({
20748
21706
  name: this.title,
20749
21707
  instructions: modelRequirements.systemMessage,
@@ -20816,6 +21774,58 @@ AgentLlmExecutionTools.vectorStoreCache = new Map();
20816
21774
  */
20817
21775
 
20818
21776
  var _Agent_instances, _Agent_selfLearnNonce, _Agent_selfLearnSamples, _Agent_selfLearnTeacher;
21777
+ /**
21778
+ * Creates an empty commitment breakdown for self-learning summaries.
21779
+ */
21780
+ function createEmptySelfLearningCommitmentCounts() {
21781
+ return {
21782
+ total: 0,
21783
+ knowledge: 0,
21784
+ rule: 0,
21785
+ persona: 0,
21786
+ other: 0,
21787
+ };
21788
+ }
21789
+ /**
21790
+ * Summarizes teacher commitments into user-friendly counts for self-learning.
21791
+ */
21792
+ function summarizeTeacherCommitments(commitments) {
21793
+ var _a, _b;
21794
+ const counts = createEmptySelfLearningCommitmentCounts();
21795
+ const lines = commitments
21796
+ .split(/\r?\n/)
21797
+ .map((line) => line.trim())
21798
+ .filter((line) => line.length > 0 && line !== '---' && !line.startsWith('```'));
21799
+ for (const line of lines) {
21800
+ const keyword = (_b = (_a = line.split(/\s+/)[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== null && _b !== void 0 ? _b : '';
21801
+ if (!/^[A-Z][A-Z_-]*$/.test(keyword)) {
21802
+ continue;
21803
+ }
21804
+ counts.total += 1;
21805
+ if (keyword === 'KNOWLEDGE') {
21806
+ counts.knowledge += 1;
21807
+ }
21808
+ else if (keyword === 'RULE') {
21809
+ counts.rule += 1;
21810
+ }
21811
+ else if (keyword === 'PERSONA') {
21812
+ counts.persona += 1;
21813
+ }
21814
+ else {
21815
+ counts.other += 1;
21816
+ }
21817
+ }
21818
+ return counts;
21819
+ }
21820
+ /**
21821
+ * Builds the teacher summary payload for the self-learning tool call.
21822
+ */
21823
+ function buildTeacherSummary(commitments, used) {
21824
+ return {
21825
+ used,
21826
+ commitmentTypes: summarizeTeacherCommitments(commitments),
21827
+ };
21828
+ }
20819
21829
  /**
20820
21830
  * Represents one AI Agent
20821
21831
  *
@@ -20990,16 +22000,29 @@ class Agent extends AgentLlmExecutionTools {
20990
22000
  // Note: [2] Do the append of the samples
20991
22001
  await __classPrivateFieldGet(this, _Agent_instances, "m", _Agent_selfLearnSamples).call(this, prompt, result);
20992
22002
  // Note: [3] Asynchronously call the teacher agent and invoke the silver link. When the teacher fails, keep just the samples
20993
- await __classPrivateFieldGet(this, _Agent_instances, "m", _Agent_selfLearnTeacher).call(this, prompt, result).catch((error) => {
22003
+ let teacherSummary = null;
22004
+ try {
22005
+ teacherSummary = await __classPrivateFieldGet(this, _Agent_instances, "m", _Agent_selfLearnTeacher).call(this, prompt, result);
22006
+ }
22007
+ catch (error) {
20994
22008
  // !!!!! if (this.options.isVerbose) {
20995
22009
  console.error(colors.bgCyan('[Self-learning]') + colors.red(' Failed to learn from teacher agent'));
20996
22010
  console.error(error);
20997
22011
  // }
20998
- });
22012
+ teacherSummary = this.teacherAgent ? buildTeacherSummary('', true) : null;
22013
+ }
20999
22014
  // Note: [4] Notify end of self-learning
22015
+ const completedAt = new Date().toISOString();
22016
+ const selfLearningResult = {
22017
+ success: true,
22018
+ startedAt: selfLearningToolCall.createdAt,
22019
+ completedAt,
22020
+ samplesAdded: 1,
22021
+ teacher: teacherSummary || undefined,
22022
+ };
21000
22023
  const completedSelfLearningToolCall = {
21001
22024
  ...selfLearningToolCall,
21002
- result: { success: true },
22025
+ result: selfLearningResult,
21003
22026
  };
21004
22027
  const finalResult = {
21005
22028
  ...result,
@@ -21048,7 +22071,7 @@ async function _Agent_selfLearnNonce() {
21048
22071
  async function _Agent_selfLearnTeacher(prompt, result) {
21049
22072
  // [1] Call the teacher agent // <- !!!!! Emojis
21050
22073
  if (this.teacherAgent === null) {
21051
- return;
22074
+ return null;
21052
22075
  }
21053
22076
  console.info(colors.bgCyan('[Self-learning]') + colors.cyan(' Teacher'));
21054
22077
  const teacherResult = await this.teacherAgent.callChatModel({
@@ -21103,7 +22126,7 @@ async function _Agent_selfLearnTeacher(prompt, result) {
21103
22126
  if (teacherCommitments === '') {
21104
22127
  console.info(colors.bgCyan('[Self-learning]') +
21105
22128
  colors.cyan(' Teacher agent did not provide new commitments to learn'));
21106
- return;
22129
+ return buildTeacherSummary('', true);
21107
22130
  }
21108
22131
  // [2] Append to the current source
21109
22132
  const currentSource = this.agentSource.value;
@@ -21111,6 +22134,7 @@ async function _Agent_selfLearnTeacher(prompt, result) {
21111
22134
  // <- TODO: [🈲] Use some object-based way how to append on book (with sections `---`)
21112
22135
  // [3] Update the source
21113
22136
  this.agentSource.next(newSource);
22137
+ return buildTeacherSummary(teacherCommitments, true);
21114
22138
  };
21115
22139
  /**
21116
22140
  * TODO: [🧠][😰]Agent is not working with the parameters, should it be?
@@ -21274,6 +22298,8 @@ class RemoteAgent extends Agent {
21274
22298
  // <- TODO: [🐱‍🚀] Maybe use promptbookFetch
21275
22299
  let content = '';
21276
22300
  const toolCalls = [];
22301
+ const preparationToolCalls = [];
22302
+ let hasReceivedModelOutput = false;
21277
22303
  const normalizeToolCall = (toolCall) => {
21278
22304
  if (toolCall.createdAt) {
21279
22305
  return toolCall;
@@ -21320,6 +22346,17 @@ class RemoteAgent extends Agent {
21320
22346
  const upsertToolCalls = (incomingToolCalls) => {
21321
22347
  for (const toolCall of incomingToolCalls) {
21322
22348
  const normalized = normalizeToolCall(toolCall);
22349
+ if (isAssistantPreparationToolCall(normalized)) {
22350
+ if (hasReceivedModelOutput) {
22351
+ continue;
22352
+ }
22353
+ preparationToolCalls.length = 0;
22354
+ preparationToolCalls.push(normalized);
22355
+ continue;
22356
+ }
22357
+ if (preparationToolCalls.length > 0) {
22358
+ preparationToolCalls.length = 0;
22359
+ }
21323
22360
  const key = getToolCallKey(normalized);
21324
22361
  const existingIndex = toolCalls.findIndex((existing) => getToolCallKey(existing) === key);
21325
22362
  if (existingIndex === -1) {
@@ -21330,6 +22367,10 @@ class RemoteAgent extends Agent {
21330
22367
  }
21331
22368
  }
21332
22369
  };
22370
+ /**
22371
+ * Builds the tool call list including any preparation marker still active.
22372
+ */
22373
+ const getActiveToolCalls = () => preparationToolCalls.length > 0 ? [...preparationToolCalls, ...toolCalls] : toolCalls;
21333
22374
  if (!bookResponse.body) {
21334
22375
  content = await bookResponse.text();
21335
22376
  }
@@ -21366,7 +22407,7 @@ class RemoteAgent extends Agent {
21366
22407
  rawPromptContent: {},
21367
22408
  rawRequest: {},
21368
22409
  rawResponse: {},
21369
- toolCalls: normalizedToolCalls,
22410
+ toolCalls: getActiveToolCalls(),
21370
22411
  });
21371
22412
  sawToolCalls = true;
21372
22413
  isToolCallLine = true;
@@ -21394,6 +22435,10 @@ class RemoteAgent extends Agent {
21394
22435
  // console.debug('RemoteAgent chunk:', textChunk);
21395
22436
  content += textChunk;
21396
22437
  }
22438
+ if (!hasReceivedModelOutput && content.trim().length > 0) {
22439
+ hasReceivedModelOutput = true;
22440
+ preparationToolCalls.length = 0;
22441
+ }
21397
22442
  onProgress({
21398
22443
  content,
21399
22444
  modelName: this.modelName,
@@ -21402,7 +22447,7 @@ class RemoteAgent extends Agent {
21402
22447
  rawPromptContent: {},
21403
22448
  rawRequest: {},
21404
22449
  rawResponse: {},
21405
- toolCalls,
22450
+ toolCalls: getActiveToolCalls(),
21406
22451
  });
21407
22452
  }
21408
22453
  }
@@ -21410,6 +22455,10 @@ class RemoteAgent extends Agent {
21410
22455
  const lastChunk = decoder.decode();
21411
22456
  if (lastChunk) {
21412
22457
  content += lastChunk;
22458
+ if (!hasReceivedModelOutput && content.trim().length > 0) {
22459
+ hasReceivedModelOutput = true;
22460
+ preparationToolCalls.length = 0;
22461
+ }
21413
22462
  onProgress({
21414
22463
  content: lastChunk,
21415
22464
  modelName: this.modelName,
@@ -21418,7 +22467,7 @@ class RemoteAgent extends Agent {
21418
22467
  rawPromptContent: {},
21419
22468
  rawRequest: {},
21420
22469
  rawResponse: {},
21421
- toolCalls,
22470
+ toolCalls: getActiveToolCalls(),
21422
22471
  });
21423
22472
  }
21424
22473
  }