@promptbook/browser 0.106.0-0 → 0.107.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm/index.es.js CHANGED
@@ -28,7 +28,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
28
28
  * @generated
29
29
  * @see https://github.com/webgptorg/promptbook
30
30
  */
31
- const PROMPTBOOK_ENGINE_VERSION = '0.106.0-0';
31
+ const PROMPTBOOK_ENGINE_VERSION = '0.107.0-0';
32
32
  /**
33
33
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
34
34
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -3900,18 +3900,6 @@ const CountUtils = {
3900
3900
  * Note: [💞] Ignore a discrepancy between file name and entity name
3901
3901
  */
3902
3902
 
3903
- /**
3904
- * Simple wrapper `new Date().toISOString()`
3905
- *
3906
- * Note: `$` is used to indicate that this function is not a pure function - it is not deterministic because it depends on the current time
3907
- *
3908
- * @returns string_date branded type
3909
- * @public exported from `@promptbook/utils`
3910
- */
3911
- function $getCurrentDate() {
3912
- return new Date().toISOString();
3913
- }
3914
-
3915
3903
  /**
3916
3904
  * Computes SHA-256 hash of the given object
3917
3905
  *
@@ -3935,103 +3923,564 @@ function capitalize(word) {
3935
3923
  return word.substring(0, 1).toUpperCase() + word.substring(1);
3936
3924
  }
3937
3925
 
3926
+ // spell-checker: disable
3938
3927
  /**
3939
- * Creates a human-readable hash as a short story sentence.
3928
+ * @@@
3940
3929
  *
3941
- * @public exported from `@promptbook/utils`
3942
- */
3943
- async function linguisticHash(input) {
3944
- const hash = computeHash(input);
3945
- return capitalize(createStorySentence(hash));
3946
- }
3947
- const HASH_SEGMENT_LENGTH = 8;
3948
- const STORY_OPENERS = [
3949
- 'once',
3950
- 'long ago',
3951
- 'at dawn',
3952
- 'at dusk',
3953
- 'suddenly',
3954
- 'quietly',
3955
- 'meanwhile',
3956
- 'today',
3957
- 'tonight',
3958
- 'in the end',
3959
- 'before long',
3960
- 'for a moment',
3930
+ * @private utility of `linguisticHash`
3931
+ */
3932
+ const ADJECTIVES$1 = [
3933
+ 'červený',
3934
+ 'modrý',
3935
+ 'zelený',
3936
+ 'žlutý',
3937
+ 'rychlý',
3938
+ 'pomalý',
3939
+ 'jasný',
3940
+ 'temný',
3941
+ 'veselý',
3942
+ 'smutný',
3943
+ 'statečný',
3944
+ 'klidný',
3945
+ 'chytrý',
3946
+ 'bystrý',
3947
+ 'dychtivý',
3948
+ 'honosný',
3949
+ 'velkolepý',
3950
+ 'hravý',
3951
+ 'laskavý',
3952
+ 'šťastný',
3953
+ 'hrdý',
3954
+ 'pošetilý',
3955
+ 'moudrý',
3956
+ 'mladý',
3957
+ 'starý',
3958
+ 'veliký',
3959
+ 'malý',
3960
+ 'drobný',
3961
+ 'obrovský',
3962
+ 'krátký',
3963
+ 'dlouhý',
3964
+ 'blízký',
3965
+ 'vzdálený',
3966
+ 'vnitřní',
3967
+ 'vnější',
3968
+ 'trpělivý',
3969
+ 'stálý',
3970
+ 'ušlechtilý',
3971
+ 'čistý',
3972
+ 'špinavý',
3973
+ 'čerstvý',
3974
+ 'zvětralý',
3975
+ 'ostrý',
3976
+ 'tupý',
3977
+ 'tlustý',
3978
+ 'tenký',
3979
+ 'široký',
3980
+ 'úzký',
3981
+ 'hluboký',
3982
+ 'mělký',
3983
+ 'mocný',
3984
+ 'jemný',
3985
+ 'divoký',
3986
+ 'tichý',
3987
+ 'hlučný',
3988
+ 'pokojný',
3989
+ 'rušný',
3990
+ 'prázdný',
3991
+ 'plný',
3992
+ 'kulatý',
3993
+ 'hranatý',
3994
+ 'plochý',
3995
+ 'křivý',
3996
+ 'tvrdý',
3997
+ 'měkký',
3998
+ 'teplý',
3999
+ 'chladný',
4000
+ 'sladký',
4001
+ 'kyselý',
4002
+ 'hořký',
4003
+ 'slaný',
4004
+ 'silný',
4005
+ 'slabý',
4006
+ 'pevný',
4007
+ 'pružný',
4008
+ 'křehký',
4009
+ 'houževnatý',
4010
+ 'lesklý',
4011
+ 'matný',
4012
+ 'kluzký',
4013
+ 'lepkavý',
4014
+ 'svěží',
4015
+ 'vybledlý',
4016
+ 'mlhavý',
4017
+ 'bouřlivý',
4018
+ 'slunný',
4019
+ 'větrný',
4020
+ 'deštivý',
4021
+ 'mrazivý',
4022
+ 'zlatý',
4023
+ 'stříbrný',
4024
+ 'ledový',
4025
+ 'žhavý',
4026
+ 'prastarý',
4027
+ 'moderní',
4028
+ 'skrytý',
4029
+ 'ztracený',
4030
+ 'nalezený',
4031
+ 'magický',
4032
+ 'tajemný',
4033
+ 'kosmický',
4034
+ 'hvězdný',
4035
+ 'měsíční',
4036
+ 'sluneční',
4037
+ 'mlžný',
4038
+ 'ranní',
4039
+ 'večerní',
4040
+ 'noční',
4041
+ 'denní',
4042
+ 'osamělý',
4043
+ 'společenský',
4044
+ 'soukromý',
4045
+ 'veřejný',
4046
+ 'tajný',
4047
+ 'slavný',
4048
+ 'jistý',
4049
+ 'neurčitý',
4050
+ 'prostý',
4051
+ 'snadný',
4052
+ 'krotký',
4053
+ 'mírný',
4054
+ 'horký',
4055
+ 'suchý',
4056
+ 'mokrý',
4057
+ 'vlhký',
4058
+ 'promočený',
4059
+ 'vyprahlý',
4060
+ 'hladový',
4061
+ 'žíznivý',
4062
+ 'ospalý',
4063
+ 'bdělý',
4064
+ 'unavený',
4065
+ 'líný',
4066
+ 'neklidný',
4067
+ 'nestálý',
4068
+ 'odvážný',
4069
+ 'bázlivý',
4070
+ 'upřímný',
4071
+ 'věrný',
4072
+ 'pravý',
4073
+ 'falešný',
4074
+ 'spravedlivý',
4075
+ 'jednoduchý',
4076
+ 'složitý',
4077
+ 'přirozený',
4078
+ 'umělý',
4079
+ 'živý',
4080
+ 'mrtvý',
4081
+ 'zvídavý',
4082
+ 'zvláštní',
4083
+ 'běžný',
4084
+ 'vzácný',
4085
+ 'jedinečný',
4086
+ 'základní',
4087
+ 'prvotní',
4088
+ 'hbitý',
3961
4089
  ];
3962
- const STORY_CONNECTORS = ['while', 'as', 'when', 'because', 'and', 'just as', 'after', 'before'];
3963
- const STORY_PREPOSITIONS = [
3964
- 'near',
3965
- 'beside',
3966
- 'under',
3967
- 'within',
3968
- 'beyond',
3969
- 'around',
3970
- 'behind',
3971
- 'across',
3972
- 'above',
3973
- 'beneath',
3974
- 'over',
3975
- 'inside',
3976
- 'outside',
3977
- 'along',
4090
+ const NOUNS$1 = [
4091
+ 'jablko',
4092
+ 'nebe',
4093
+ 'strom',
4094
+ 'liška',
4095
+ 'kočka',
4096
+ 'pták',
4097
+ 'pes',
4098
+ 'řeka',
4099
+ 'hora',
4100
+ 'les',
4101
+ 'oceán',
4102
+ 'hvězda',
4103
+ 'měsíc',
4104
+ 'slunce',
4105
+ 'mrak',
4106
+ 'květ',
4107
+ 'list',
4108
+ 'kámen',
4109
+ 'vítr',
4110
+ 'déšť',
4111
+ 'oheň',
4112
+ 'led',
4113
+ 'kniha',
4114
+ 'sen',
4115
+ 'píseň',
4116
+ 'cesta',
4117
+ 'brána',
4118
+ 'klíč',
4119
+ 'lampa',
4120
+ 'mapa',
4121
+ 'dům',
4122
+ 'město',
4123
+ 'most',
4124
+ 'pole',
4125
+ 'zahrada',
4126
+ 'jezero',
4127
+ 'pláž',
4128
+ 'ostrov',
4129
+ 'údolí',
4130
+ 'poušť',
4131
+ 'svět',
4132
+ 'duch',
4133
+ 'srdce',
4134
+ 'mysl',
4135
+ 'duše',
4136
+ 'život',
4137
+ 'čas',
4138
+ 'prostor',
4139
+ 'světlo',
4140
+ 'stín',
4141
+ 'zvuk',
4142
+ 'hudba',
4143
+ 'hlas',
4144
+ 'slovo',
4145
+ 'stránka',
4146
+ 'příběh',
4147
+ 'perla',
4148
+ 'zlato',
4149
+ 'stříbro',
4150
+ 'krystal',
4151
+ 'diamant',
4152
+ 'smaragd',
4153
+ 'rubín',
4154
+ 'stezka',
4155
+ 'vrchol',
4156
+ 'břeh',
4157
+ 'vlna',
4158
+ 'příliv',
4159
+ 'plamen',
4160
+ 'jiskra',
4161
+ 'paprsek',
4162
+ 'semínko',
4163
+ 'kořen',
4164
+ 'větev',
4165
+ 'pupen',
4166
+ 'trn',
4167
+ 'kůra',
4168
+ 'skořápka',
4169
+ 'pírko',
4170
+ 'křídlo',
4171
+ 'dráp',
4172
+ 'tlapa',
4173
+ 'hnízdo',
4174
+ 'jeskyně',
4175
+ 'hájek',
4176
+ 'věž',
4177
+ 'hrad',
4178
+ 'koruna',
4179
+ 'meč',
4180
+ 'štít',
4181
+ 'mince',
4182
+ 'drahokam',
4183
+ 'prsten',
4184
+ 'zvonek',
4185
+ 'hodiny',
4186
+ 'kompas',
4187
+ 'kotva',
4188
+ 'pochodeň',
4189
+ 'flétna',
4190
+ 'harfa',
4191
+ 'buben',
4192
+ 'čočka',
4193
+ 'sklo',
4194
+ 'písek',
4195
+ 'prach',
4196
+ 'mlha',
4197
+ 'rosa',
4198
+ 'svítání',
4199
+ 'soumrak',
4200
+ 'noc',
4201
+ 'den',
4202
+ 'rok',
4203
+ 'věk',
4204
+ 'blesk',
4205
+ 'kapka',
4206
+ 'bouře',
4207
+ 'sníh',
4208
+ 'kroupa',
4209
+ 'kouř',
4210
+ 'pára',
4211
+ 'plyn',
4212
+ 'kov',
4213
+ 'skála',
4214
+ 'hlína',
4215
+ 'sůl',
4216
+ 'cukr',
4217
+ 'dřevo',
4218
+ 'kost',
4219
+ 'kůže',
4220
+ 'tělo',
4221
+ 'krev',
4222
+ 'buňka',
4223
+ 'atom',
4224
+ 'tep',
4225
+ 'dech',
4226
+ 'vzdech',
4227
+ 'jméno',
4228
+ 'ozvěna',
4229
+ 'obraz',
4230
+ 'vize',
4231
+ 'myšlenka',
4232
+ 'nápad',
4233
+ 'plán',
4234
+ 'cíl',
4235
+ 'přání',
4236
+ 'naděje',
4237
+ 'strach',
4238
+ 'radost',
4239
+ 'láska',
4240
+ 'nenávist',
4241
+ 'vůle',
4242
+ 'síla',
4243
+ 'energie',
4244
+ 'pohyb',
4245
+ 'rychlost',
4246
+ 'místo',
4247
+ 'bod',
4248
+ 'linie',
4249
+ 'tvar',
4250
+ 'forma',
4251
+ 'velikost',
4252
+ 'hmota',
4253
+ 'váha',
4254
+ 'teplo',
4255
+ 'chlad',
4256
+ 'barva',
4257
+ 'tón',
4258
+ 'rytmus',
4259
+ 'nálada',
4260
+ 'stav',
4261
+ 'krok',
4262
+ 'pád',
4263
+ 'skok',
4264
+ 'běh',
4265
+ 'let',
4266
+ 'klid',
4267
+ 'úkol',
4268
+ 'práce',
4269
+ 'hra',
4270
+ 'sport',
4271
+ 'umění',
4272
+ 'řemeslo',
4273
+ 'nástroj',
4274
+ 'loď',
4275
+ 'člun',
4276
+ 'auto',
4277
+ 'kolo',
4278
+ 'vlak',
4279
+ 'letadlo',
4280
+ 'uzel',
4281
+ 'síť',
4282
+ 'krabice',
4283
+ 'taška',
4284
+ 'dóza',
4285
+ 'hrnek',
4286
+ 'miska',
4287
+ 'talíř',
4288
+ 'lžíce',
4289
+ 'vidlička',
4290
+ 'nůž',
4291
+ 'pánev',
4292
+ 'hrnec',
4293
+ 'postel',
4294
+ 'stůl',
4295
+ 'židle',
4296
+ 'dveře',
4297
+ 'stěna',
4298
+ 'střecha',
4299
+ 'podlaha',
4300
+ 'okno',
4301
+ 'chodba',
3978
4302
  ];
3979
- const STORY_TEMPLATES = [
3980
- (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}.`,
3981
- (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}.`,
3982
- (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}.`,
3983
- (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}.`,
4303
+ const VERBS$1 = [
4304
+ 'skáče',
4305
+ 'tančí',
4306
+ 'letí',
4307
+ 'běží',
4308
+ 'zpívá',
4309
+ 'svítí',
4310
+ 'roste',
4311
+ 'plyne',
4312
+ 'padá',
4313
+ 'stoupá',
4314
+ 'spí',
4315
+ 'kráčí',
4316
+ 'mluví',
4317
+ 'myslí',
4318
+ 'sní',
4319
+ 'hledá',
4320
+ 'nachází',
4321
+ 'dává',
4322
+ 'bere',
4323
+ 'tvoří',
4324
+ 'hoří',
4325
+ 'mrzne',
4326
+ 'taje',
4327
+ 'dýchá',
4328
+ 'pulzuje',
4329
+ 'bije',
4330
+ 'žije',
4331
+ 'učí',
4332
+ 'ví',
4333
+ 'skrývá',
4334
+ 'ukazuje',
4335
+ 'láme',
4336
+ 'opravuje',
4337
+ 'ztrácí',
4338
+ 'nalézá',
4339
+ 'začíná',
4340
+ 'končí',
4341
+ 'plave',
4342
+ 'pluje',
4343
+ 'klouže',
4344
+ 'točí',
4345
+ 'mění',
4346
+ 'bledne',
4347
+ 'mizí',
4348
+ 'rodí',
4349
+ 'hučí',
4350
+ 'pláče',
4351
+ 'závodí',
4352
+ 'plíží',
4353
+ 'sleduje',
4354
+ 'slyší',
4355
+ 'cítí',
4356
+ 'touží',
4357
+ 'doufá',
4358
+ 'miluje',
4359
+ 'bloudí',
4360
+ 'putuje',
4361
+ 'cestuje',
4362
+ 'překračuje',
4363
+ 'potkává',
4364
+ 'drží',
4365
+ 'sdílí',
4366
+ 'jiskří',
4367
+ 'plápolá',
4368
+ 'léčí',
4369
+ 'řeší',
4370
+ 'otevírá',
4371
+ 'zavírá',
4372
+ 'zvedá',
4373
+ 'táhne',
4374
+ 'tlačí',
4375
+ 'hází',
4376
+ 'chytá',
4377
+ 'dělá',
4378
+ 'vidí',
4379
+ 'chutná',
4380
+ 'voní',
4381
+ 'spěchá',
4382
+ 'zastaví',
4383
+ 'jde',
4384
+ 'přichází',
4385
+ 'odchází',
4386
+ 'jedná',
4387
+ 'existuje',
4388
+ 'zmenšuje',
4389
+ 'rozšiřuje',
4390
+ 'zužuje',
4391
+ 'hřeje',
4392
+ 'chladí',
4393
+ 'suší',
4394
+ 'máčí',
4395
+ 'plní',
4396
+ 'vyprazdňuje',
4397
+ 'pouští',
4398
+ 'získává',
4399
+ 'vítězí',
4400
+ 'selhává',
4401
+ 'zkouší',
4402
+ 'používá',
4403
+ 'dostává',
4404
+ 'měří',
4405
+ 'stojí',
4406
+ 'dosahuje',
4407
+ 'míjí',
4408
+ 'udeří',
4409
+ 'vede',
4410
+ 'následuje',
4411
+ 'pomáhá',
4412
+ 'slouží',
4413
+ 'trénuje',
4414
+ 'kóduje',
4415
+ 'píše',
4416
+ 'čte',
4417
+ 'kreslí',
4418
+ 'maluje',
4419
+ 'tvaruje',
4420
+ 'spojuje',
4421
+ 'dělí',
4422
+ 'váže',
4423
+ 'zraňuje',
4424
+ 'chrání',
4425
+ 'bojuje',
4426
+ 'brání',
4427
+ 'útočí',
4428
+ 'uniká',
4429
+ 'lapá',
4430
+ 'osvobozuje',
4431
+ 'poutá',
4432
+ 'spřádá',
4433
+ 'tká',
4434
+ 'vrhá',
4435
+ 'nese',
4436
+ 'přenáší',
4437
+ 'vrací',
4438
+ 'zrychluje',
4439
+ 'zpomaluje',
4440
+ 'probouzí',
4441
+ 'uspává',
4442
+ 'šeptá',
4443
+ 'volá',
4444
+ 'hledí',
4445
+ 'čeká',
4446
+ 'bdí',
4447
+ 'rozkvétá',
4448
+ 'klíčí',
4449
+ 'zraje',
4450
+ 'chvěje',
4451
+ 'třpytí',
4452
+ 'shromažďuje',
4453
+ 'rozhazuje',
4454
+ 'tápe',
4455
+ 'žhne',
4456
+ 'vibruje',
4457
+ 'šumí',
4458
+ 'stéká',
4459
+ 'vypráví',
4460
+ 'plánuje',
4461
+ 'počítá',
4462
+ 'váhá',
4463
+ 'riskuje',
3984
4464
  ];
3985
4465
  /**
3986
- * Extracts a deterministic numeric seed from a SHA-256 hash.
3987
- */
3988
- function getHashSeed(hash, segmentIndex) {
3989
- const expandedHash = `${hash}${hash}`;
3990
- const start = (segmentIndex * HASH_SEGMENT_LENGTH + segmentIndex) % hash.length;
3991
- return parseInt(expandedHash.substring(start, start + HASH_SEGMENT_LENGTH), 16);
3992
- }
3993
- /**
3994
- * Picks a deterministic item from a list based on the hash seed.
3995
- */
3996
- function pickFromHash(hash, segmentIndex, list) {
3997
- const seed = getHashSeed(hash, segmentIndex);
3998
- return list[seed % list.length];
3999
- }
4000
- /**
4001
- * Index constants for story part selection to avoid magic numbers.
4002
- */
4003
- const ADJECTIVE3_INDEX = 9;
4004
- const NOUN3_INDEX = 10;
4005
- /**
4006
- * Creates the deterministic story parts used by the sentence templates.
4466
+ * Czech word lists used by the linguistic hash.
4467
+ *
4468
+ * @private utility of `linguisticHash`
4007
4469
  */
4008
- function createStoryParts(hash) {
4009
- return {
4010
- opener: pickFromHash(hash, 0, STORY_OPENERS),
4011
- connector: pickFromHash(hash, 1, STORY_CONNECTORS),
4012
- preposition: pickFromHash(hash, 2, STORY_PREPOSITIONS),
4013
- adjective1: pickFromHash(hash, 3, ADJECTIVES),
4014
- noun1: pickFromHash(hash, 4, NOUNS),
4015
- verb1: pickFromHash(hash, 5, VERBS),
4016
- adjective2: pickFromHash(hash, 6, ADJECTIVES),
4017
- noun2: pickFromHash(hash, 7, NOUNS),
4018
- verb2: pickFromHash(hash, 8, VERBS),
4019
- adjective3: pickFromHash(hash, ADJECTIVE3_INDEX, ADJECTIVES),
4020
- noun3: pickFromHash(hash, NOUN3_INDEX, NOUNS),
4021
- };
4022
- }
4470
+ const LINGUISTIC_HASH_WORD_LISTS_CS = {
4471
+ adjective: ADJECTIVES$1,
4472
+ noun: NOUNS$1,
4473
+ verb: VERBS$1,
4474
+ };
4023
4475
  /**
4024
- * Index constant for story template selection to avoid magic numbers.
4476
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4025
4477
  */
4026
- const STORY_TEMPLATE_INDEX = 11;
4478
+
4027
4479
  /**
4028
- * Builds a short, memorable story sentence from the hash.
4480
+ * @@@
4481
+ *
4482
+ * @private utility of `linguisticHash`
4029
4483
  */
4030
- function createStorySentence(hash) {
4031
- const parts = createStoryParts(hash);
4032
- const template = pickFromHash(hash, STORY_TEMPLATE_INDEX, STORY_TEMPLATES);
4033
- return template(parts).trim();
4034
- }
4035
4484
  const ADJECTIVES = [
4036
4485
  'red',
4037
4486
  'blue',
@@ -4706,9 +5155,216 @@ const VERBS = [
4706
5155
  'spinning',
4707
5156
  ];
4708
5157
  /**
4709
- * TODO: Prompt: Extract number constants and word list to a separate file for reuse.
5158
+ * English word lists used by the linguistic hash.
5159
+ *
5160
+ * @private utility of `linguisticHash`
5161
+ */
5162
+ const LINGUISTIC_HASH_WORD_LISTS_EN = {
5163
+ adjective: ADJECTIVES,
5164
+ noun: NOUNS,
5165
+ verb: VERBS,
5166
+ };
5167
+ /**
5168
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4710
5169
  */
4711
5170
 
5171
+ /**
5172
+ * Default language used for linguistic hashes.
5173
+ *
5174
+ * @private utility of `linguisticHash`
5175
+ */
5176
+ const DEFAULT_LINGUISTIC_HASH_LANGUAGE = 'en';
5177
+ /**
5178
+ * @@@
5179
+ *
5180
+ * @private utility of `linguisticHash`
5181
+ */
5182
+ const LANGUAGE_CONFIGS = {
5183
+ en: {
5184
+ language: 'en',
5185
+ label: 'English',
5186
+ wordLists: LINGUISTIC_HASH_WORD_LISTS_EN,
5187
+ },
5188
+ cs: {
5189
+ language: 'cs',
5190
+ label: 'Czech',
5191
+ wordLists: LINGUISTIC_HASH_WORD_LISTS_CS,
5192
+ },
5193
+ };
5194
+ /**
5195
+ * Normalizes a requested language to a supported linguistic hash language.
5196
+ *
5197
+ * @private utility of `linguisticHash`
5198
+ */
5199
+ function normalizeLinguisticHashLanguage(language) {
5200
+ if (typeof language !== 'string') {
5201
+ return DEFAULT_LINGUISTIC_HASH_LANGUAGE;
5202
+ }
5203
+ const normalized = language.trim().toLowerCase();
5204
+ if (normalized === 'cs') {
5205
+ return 'cs';
5206
+ }
5207
+ if (normalized === 'en') {
5208
+ return 'en';
5209
+ }
5210
+ return DEFAULT_LINGUISTIC_HASH_LANGUAGE;
5211
+ }
5212
+ /**
5213
+ * Returns the language configuration for linguistic hash generation.
5214
+ *
5215
+ * @private utility of `linguisticHash`
5216
+ */
5217
+ function getLinguisticHashLanguageConfig(language) {
5218
+ const normalized = normalizeLinguisticHashLanguage(language);
5219
+ return LANGUAGE_CONFIGS[normalized];
5220
+ }
5221
+
5222
+ // <- TODO: !!!! Remove re-exports
5223
+ /**
5224
+ * Creates a human-readable hash as a short, story-like phrase.
5225
+ *
5226
+ * @param wordCount how many words to include (defaults to {@link DEFAULT_LINGUISTIC_HASH_WORD_COUNT}, clamped to
5227
+ * {@link MIN_LINGUISTIC_HASH_WORD_COUNT}..{@link MAX_LINGUISTIC_HASH_WORD_COUNT})
5228
+ * @param language optional language code (defaults to {@link DEFAULT_LINGUISTIC_HASH_LANGUAGE})
5229
+ *
5230
+ * @public exported from `@promptbook/utils`
5231
+ */
5232
+ async function linguisticHash(input, wordCount, language) {
5233
+ const hash = computeHash(input);
5234
+ const normalizedWordCount = normalizeLinguisticHashWordCount(wordCount);
5235
+ const languageConfig = getLinguisticHashLanguageConfig(language);
5236
+ const words = createLinguisticHashWords(hash, normalizedWordCount, languageConfig.wordLists);
5237
+ return capitalize(words.join(' '));
5238
+ }
5239
+ /**
5240
+ * @@@
5241
+ *
5242
+ * @private utility of `linguisticHash`
5243
+ */
5244
+ const HASH_SEGMENT_LENGTH = 8;
5245
+ /**
5246
+ * The minimum number of words for a linguistic hash.
5247
+ *
5248
+ * @private utility of `linguisticHash`
5249
+ */
5250
+ const MIN_LINGUISTIC_HASH_WORD_COUNT = 1;
5251
+ /**
5252
+ * The default number of words for a linguistic hash.
5253
+ *
5254
+ * @private utility of `linguisticHash`
5255
+ */
5256
+ const DEFAULT_LINGUISTIC_HASH_WORD_COUNT = 7;
5257
+ /**
5258
+ * Extracts a deterministic numeric seed from a SHA-256 hash.
5259
+ *
5260
+ * @private utility of `linguisticHash`
5261
+ */
5262
+ function getHashSeed(hash, segmentIndex) {
5263
+ const expandedHash = `${hash}${hash}`;
5264
+ const start = (segmentIndex * HASH_SEGMENT_LENGTH + segmentIndex) % hash.length;
5265
+ return parseInt(expandedHash.substring(start, start + HASH_SEGMENT_LENGTH), 16);
5266
+ }
5267
+ /**
5268
+ * Picks a deterministic item from a list based on the hash seed.
5269
+ *
5270
+ * @private utility of `linguisticHash`
5271
+ */
5272
+ function pickFromHash(hash, segmentIndex, list) {
5273
+ const seed = getHashSeed(hash, segmentIndex);
5274
+ return list[seed % list.length];
5275
+ }
5276
+ /**
5277
+ * Ordered word kinds used to build the linguistic hash output.
5278
+ *
5279
+ * @private utility of `linguisticHash`
5280
+ */
5281
+ const WORD_SEQUENCE = [
5282
+ 'adjective',
5283
+ 'noun',
5284
+ 'verb',
5285
+ 'adjective',
5286
+ 'noun',
5287
+ 'verb',
5288
+ 'adjective',
5289
+ 'noun',
5290
+ 'verb',
5291
+ 'adjective',
5292
+ 'noun',
5293
+ 'verb',
5294
+ 'adjective',
5295
+ 'noun',
5296
+ 'verb',
5297
+ 'adjective',
5298
+ 'noun',
5299
+ 'verb',
5300
+ 'adjective',
5301
+ 'noun',
5302
+ ];
5303
+ /**
5304
+ * The maximum number of words for a linguistic hash.
5305
+ *
5306
+ * @private utility of `linguisticHash`
5307
+ */
5308
+ const MAX_LINGUISTIC_HASH_WORD_COUNT = WORD_SEQUENCE.length;
5309
+ /**
5310
+ * Index of the noun used for single-word hashes.
5311
+ *
5312
+ * @private utility of `linguisticHash`
5313
+ */
5314
+ const SINGLE_WORD_INDEX = 1;
5315
+ /**
5316
+ * Normalizes the word count to a supported integer range.
5317
+ *
5318
+ * @private utility of `linguisticHash`
5319
+ */
5320
+ function normalizeLinguisticHashWordCount(wordCount) {
5321
+ if (typeof wordCount !== 'number' || !Number.isFinite(wordCount)) {
5322
+ return DEFAULT_LINGUISTIC_HASH_WORD_COUNT;
5323
+ }
5324
+ const rounded = Math.round(wordCount);
5325
+ return Math.min(MAX_LINGUISTIC_HASH_WORD_COUNT, Math.max(MIN_LINGUISTIC_HASH_WORD_COUNT, rounded));
5326
+ }
5327
+ /**
5328
+ * Picks a deterministic word from the hash by kind.
5329
+ *
5330
+ * @private utility of `linguisticHash`
5331
+ */
5332
+ function pickWordFromHash(hash, segmentIndex, wordKind, wordLists) {
5333
+ return pickFromHash(hash, segmentIndex, wordLists[wordKind]);
5334
+ }
5335
+ /**
5336
+ * Creates the deterministic word sequence used for the linguistic hash output.
5337
+ *
5338
+ * @private utility of `linguisticHash`
5339
+ */
5340
+ function createLinguisticHashWordSequence(hash, wordLists) {
5341
+ return WORD_SEQUENCE.map((wordKind, index) => pickWordFromHash(hash, index, wordKind, wordLists));
5342
+ }
5343
+ /**
5344
+ * Selects the requested number of words from the hash output.
5345
+ *
5346
+ * @private utility of `linguisticHash`
5347
+ */
5348
+ function createLinguisticHashWords(hash, wordCount, wordLists) {
5349
+ const words = createLinguisticHashWordSequence(hash, wordLists);
5350
+ if (wordCount === 1) {
5351
+ return [words[SINGLE_WORD_INDEX]];
5352
+ }
5353
+ return words.slice(0, wordCount);
5354
+ }
5355
+
5356
+ /**
5357
+ * Simple wrapper `new Date().toISOString()`
5358
+ *
5359
+ * Note: `$` is used to indicate that this function is not a pure function - it is not deterministic because it depends on the current time
5360
+ *
5361
+ * @returns string_date branded type
5362
+ * @public exported from `@promptbook/utils`
5363
+ */
5364
+ function $getCurrentDate() {
5365
+ return new Date().toISOString();
5366
+ }
5367
+
4712
5368
  /**
4713
5369
  * Normalizes a text string to SCREAMING_CASE (all uppercase with underscores).
4714
5370
  *
@@ -10712,6 +11368,21 @@ function book(strings, ...values) {
10712
11368
  * Note: [💞] Ignore a discrepancy between file name and entity name
10713
11369
  */
10714
11370
 
11371
+ /**
11372
+ * Tool call name emitted while preparing a GPT assistant for an agent.
11373
+ *
11374
+ * @public exported from `@promptbook/types`
11375
+ */
11376
+ const ASSISTANT_PREPARATION_TOOL_CALL_NAME = 'assistant_preparation';
11377
+ /**
11378
+ * Checks whether a tool call is the assistant preparation marker.
11379
+ *
11380
+ * @public exported from `@promptbook/types`
11381
+ */
11382
+ function isAssistantPreparationToolCall(toolCall) {
11383
+ return toolCall.name === ASSISTANT_PREPARATION_TOOL_CALL_NAME;
11384
+ }
11385
+
10715
11386
  /*! *****************************************************************************
10716
11387
  Copyright (c) Microsoft Corporation.
10717
11388
 
@@ -18065,6 +18736,33 @@ const DISCRIMINANT = 'OPEN_AI_ASSISTANT_V1';
18065
18736
  * TODO: [🧠][🌰] Allow to pass `title` for tracking purposes
18066
18737
  */
18067
18738
 
18739
+ /**
18740
+ * Emits a progress update to signal assistant preparation before long setup work.
18741
+ */
18742
+ function emitAssistantPreparationProgress(options) {
18743
+ const startedAt = $getCurrentDate();
18744
+ options.onProgress({
18745
+ content: '',
18746
+ modelName: options.modelName,
18747
+ timing: {
18748
+ start: startedAt,
18749
+ complete: startedAt,
18750
+ },
18751
+ usage: UNCERTAIN_USAGE,
18752
+ rawPromptContent: options.prompt.content,
18753
+ rawRequest: null,
18754
+ rawResponse: {
18755
+ status: 'assistant_preparation',
18756
+ },
18757
+ toolCalls: [
18758
+ {
18759
+ name: ASSISTANT_PREPARATION_TOOL_CALL_NAME,
18760
+ arguments: {},
18761
+ createdAt: startedAt,
18762
+ },
18763
+ ],
18764
+ });
18765
+ }
18068
18766
  /**
18069
18767
  * Execution Tools for calling LLM models with a predefined agent "soul"
18070
18768
  * This wraps underlying LLM execution tools and applies agent-specific system prompts and requirements
@@ -18288,6 +18986,11 @@ class AgentLlmExecutionTools {
18288
18986
  if (this.options.isVerbose) {
18289
18987
  console.log(`1️⃣ Updating OpenAI Assistant for agent ${this.title}...`);
18290
18988
  }
18989
+ emitAssistantPreparationProgress({
18990
+ onProgress,
18991
+ prompt,
18992
+ modelName: this.modelName,
18993
+ });
18291
18994
  assistant = await this.options.llmTools.updateAssistant({
18292
18995
  assistantId: cached.assistantId,
18293
18996
  name: this.title,
@@ -18306,6 +19009,11 @@ class AgentLlmExecutionTools {
18306
19009
  console.log(`1️⃣ Creating new OpenAI Assistant for agent ${this.title}...`);
18307
19010
  }
18308
19011
  // <- TODO: [🐱‍🚀] Check also `isCreatingNewAssistantsAllowed` and warn about it
19012
+ emitAssistantPreparationProgress({
19013
+ onProgress,
19014
+ prompt,
19015
+ modelName: this.modelName,
19016
+ });
18309
19017
  assistant = await this.options.llmTools.createNewAssistant({
18310
19018
  name: this.title,
18311
19019
  instructions: modelRequirements.systemMessage,
@@ -18836,6 +19544,8 @@ class RemoteAgent extends Agent {
18836
19544
  // <- TODO: [🐱‍🚀] Maybe use promptbookFetch
18837
19545
  let content = '';
18838
19546
  const toolCalls = [];
19547
+ const preparationToolCalls = [];
19548
+ let hasReceivedModelOutput = false;
18839
19549
  const normalizeToolCall = (toolCall) => {
18840
19550
  if (toolCall.createdAt) {
18841
19551
  return toolCall;
@@ -18882,6 +19592,17 @@ class RemoteAgent extends Agent {
18882
19592
  const upsertToolCalls = (incomingToolCalls) => {
18883
19593
  for (const toolCall of incomingToolCalls) {
18884
19594
  const normalized = normalizeToolCall(toolCall);
19595
+ if (isAssistantPreparationToolCall(normalized)) {
19596
+ if (hasReceivedModelOutput) {
19597
+ continue;
19598
+ }
19599
+ preparationToolCalls.length = 0;
19600
+ preparationToolCalls.push(normalized);
19601
+ continue;
19602
+ }
19603
+ if (preparationToolCalls.length > 0) {
19604
+ preparationToolCalls.length = 0;
19605
+ }
18885
19606
  const key = getToolCallKey(normalized);
18886
19607
  const existingIndex = toolCalls.findIndex((existing) => getToolCallKey(existing) === key);
18887
19608
  if (existingIndex === -1) {
@@ -18892,6 +19613,10 @@ class RemoteAgent extends Agent {
18892
19613
  }
18893
19614
  }
18894
19615
  };
19616
+ /**
19617
+ * Builds the tool call list including any preparation marker still active.
19618
+ */
19619
+ const getActiveToolCalls = () => preparationToolCalls.length > 0 ? [...preparationToolCalls, ...toolCalls] : toolCalls;
18895
19620
  if (!bookResponse.body) {
18896
19621
  content = await bookResponse.text();
18897
19622
  }
@@ -18928,7 +19653,7 @@ class RemoteAgent extends Agent {
18928
19653
  rawPromptContent: {},
18929
19654
  rawRequest: {},
18930
19655
  rawResponse: {},
18931
- toolCalls: normalizedToolCalls,
19656
+ toolCalls: getActiveToolCalls(),
18932
19657
  });
18933
19658
  sawToolCalls = true;
18934
19659
  isToolCallLine = true;
@@ -18956,6 +19681,10 @@ class RemoteAgent extends Agent {
18956
19681
  // console.debug('RemoteAgent chunk:', textChunk);
18957
19682
  content += textChunk;
18958
19683
  }
19684
+ if (!hasReceivedModelOutput && content.trim().length > 0) {
19685
+ hasReceivedModelOutput = true;
19686
+ preparationToolCalls.length = 0;
19687
+ }
18959
19688
  onProgress({
18960
19689
  content,
18961
19690
  modelName: this.modelName,
@@ -18964,7 +19693,7 @@ class RemoteAgent extends Agent {
18964
19693
  rawPromptContent: {},
18965
19694
  rawRequest: {},
18966
19695
  rawResponse: {},
18967
- toolCalls,
19696
+ toolCalls: getActiveToolCalls(),
18968
19697
  });
18969
19698
  }
18970
19699
  }
@@ -18972,6 +19701,10 @@ class RemoteAgent extends Agent {
18972
19701
  const lastChunk = decoder.decode();
18973
19702
  if (lastChunk) {
18974
19703
  content += lastChunk;
19704
+ if (!hasReceivedModelOutput && content.trim().length > 0) {
19705
+ hasReceivedModelOutput = true;
19706
+ preparationToolCalls.length = 0;
19707
+ }
18975
19708
  onProgress({
18976
19709
  content: lastChunk,
18977
19710
  modelName: this.modelName,
@@ -18980,7 +19713,7 @@ class RemoteAgent extends Agent {
18980
19713
  rawPromptContent: {},
18981
19714
  rawRequest: {},
18982
19715
  rawResponse: {},
18983
- toolCalls,
19716
+ toolCalls: getActiveToolCalls(),
18984
19717
  });
18985
19718
  }
18986
19719
  }