jsfe 1.10.6 → 1.10.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/helpers/answer.js"],"names":[],"mappings":"AAmMA;;;GAGG;AACH,wEAkBC;AAED,+HAA+H;AAC/H,oDAIC;AAcD,2GAA2G;AAC3G,uDAGC;AAOD;;;;;GAKG;AACH,+DAUC;AAKD;;;;GAIG;AACH,oDAEC;AAiBD;;;;;;GAMG;AACH,mDAAmF;AAEnF,kGAAkG;AAClG;;;EAmCC;AAUD;;;;;;;;;GASG;AACH,6EAyGC;;;;;;;;AAnaD,qCAKiD"}
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/helpers/answer.js"],"names":[],"mappings":"AA6MA;;;GAGG;AACH,wEAkBC;AAED,+HAA+H;AAC/H,oDAIC;AAcD,2GAA2G;AAC3G,uDAGC;AAOD;;;;;GAKG;AACH,+DAUC;AAKD;;;;GAIG;AACH,oDAEC;AAiBD;;;;;;GAMG;AACH,mDAAmF;AAEnF,kGAAkG;AAClG;;;EAmCC;AAUD;;;;;;;;;GASG;AACH,6EA4GC;;;;;;;;AA/aD,qCAKwE"}
@@ -39,14 +39,15 @@ export const ANSWER_WORDS = {
39
39
  // The ONLY words that confirm a choice that charges or cancels (`exact`), besides the choice's own words and keys; courtesy
40
40
  // around them is allowed (owner decision 2026-10-15: "clear charge confirmation exclusively"). Left out on purpose:
41
41
  // acknowledgements ("ok", "está bien", "fine", "sounds good", "perfecto": "I heard you", not "charge me"), "bueno" (the
42
- // Mexican phone "hello?"), courtesy alone ("please", "por favor"), words that are questions once ASR drops the "?"
43
- // ("right", "seguro", "exactly", "así es"), and agreeing to continue ("continue", "continuar").
42
+ // Mexican phone "hello?"), words that are questions once ASR drops the "?" ("right", "seguro", "exactly", "así es"), and
43
+ // agreeing to continue ("continue", "continuar"). "please" / "por favor" alone confirm (owner rule 2026-10-26: prod
44
+ // 21:47, "por favor" to "presione 1 o diga SÍ" at a payment offer was not taken and the payment was lost).
44
45
  export const CONFIRM_WORDS = ['yes', 'yeah', 'yep', 'yup', 'sure', 'of course', 'absolutely', 'definitely', 'confirm', 'i confirm',
45
46
  'confirmed', 'approve', 'i approve', 'approved', 'agree', 'i agree', 'agreed', 'proceed', 'go ahead', 'go ahead please', 'do it',
46
47
  'correct', "that's correct", 'that is correct', "that's right", 'that is right', 'yes i do',
47
48
  'si', 'sí', 'claro', 'claro que sí', 'claro que si', 'por supuesto', 'confirmo', 'confirmado', 'apruebo', 'aprobado', 'adelante',
48
49
  'dale', 'hazlo', 'procede', 'proceda', 'proceder', 'procedo', 'sí proceda', 'si proceda', 'correcto', 'de acuerdo',
49
- 'estoy de acuerdo', 'sí quiero', 'si quiero'];
50
+ 'estoy de acuerdo', 'sí quiero', 'si quiero', 'please', 'por favor'];
50
51
  // Acknowledgements: never a confirmation of an `exact` choice on their own, but said beside one ("Sí, está bien", "Yes,
51
52
  // okay") they change nothing, like courtesy. Beside an exact choice's own words, a CONFIRM word is the same ("Yes, the
52
53
  // full balance").
@@ -94,7 +95,7 @@ const phraseAt = (tokens, i, phrase) => phrase.every((w, j) => tokens[i + j] ===
94
95
  * words from `words` — at least one of them. A YES that acts must be the whole answer (owner rule, 2026-10-14): "Yeah, sure,
95
96
  * thank you" and "Sí, claro, por favor" are YES; "yes, pay it" and "I made payments by 1" are not.
96
97
  */
97
- function onlyAffirmative(b, words, needOne = true, filler = []) {
98
+ function onlyAffirmative(b, words, needOne = true, filler = [], courtesyWords = COURTESY) {
98
99
  if (!words.length && needOne) {
99
100
  return false;
100
101
  }
@@ -108,7 +109,7 @@ function onlyAffirmative(b, words, needOne = true, filler = []) {
108
109
  let saw = false;
109
110
  while (i < tk.length) {
110
111
  const yes = own.filter((p) => at(i, p)).sort((x, y) => y.length - x.length)[0];
111
- const courtesy = yes ? null : [...COURTESY, ...filler].filter((p) => at(i, p)).sort((x, y) => y.length - x.length)[0];
112
+ const courtesy = yes ? null : [...courtesyWords, ...filler].filter((p) => at(i, p)).sort((x, y) => y.length - x.length)[0];
112
113
  if (yes) {
113
114
  i += yes.length;
114
115
  saw = true;
@@ -183,6 +184,15 @@ function textRequest(input, words, extra) {
183
184
  * when `yesOk`, a YES word ("yes 1", "sí, 1"). Owner decision 2026-10-15: "Yes 1" at "tell me the product number" was
184
185
  * missed. Anything else around the key ("no 1", "1 or 2", "I paid 1 already") is not that key.
185
186
  */
187
+ // The only words a firm YES's key may carry besides CONFIRM words (owner rule 2026-10-25): "1, por favor", "sí, 1".
188
+ const PLEASE_THANKS = ['please', 'por favor', ...THANKS].map(normalize).map((w) => w.split(' '));
189
+ /** A firm key: the key alone, or beside please/thanks and firm CONFIRM words only ("Sí, 1" — owner 2026-10-15 and
190
+ * 2026-10-25). Never a soft YES word, an acknowledgement, a key-naming word, a form of address or filler beside it. */
191
+ function firmKey(b, key) {
192
+ const tk = String(b).replace(/\./g, ' ').split(' ').filter(Boolean);
193
+ const at = tk.reduce((acc, t, i) => (t === key ? [...acc, i] : acc), []);
194
+ return at.length === 1 && onlyAffirmative(tk.filter((t, i) => i !== at[0]).join(' '), CONFIRM_WORDS, false, [], PLEASE_THANKS);
195
+ }
186
196
  // Words that name the key itself when said right before it: "el número 4", "opción 2", "number 4", "the 4" (prod
187
197
  // 2026-10-25 18:25: "Número 4" and "El número 4" at a numbered product list were not understood, twice).
188
198
  const KEY_NAMES = new Set(['number', 'numero', 'option', 'opcion', 'item', 'choice', 'the', 'el', 'la'].map(normalize));
@@ -417,7 +427,10 @@ export function pickChoice(answer, choices, acceptOther) {
417
427
  const strict = all.filter((w) => c.exact === true || /^[0-9*#]$/.test(String(w).trim()) || YES_SET.has(normalize(w)))
418
428
  .filter((w) => !(amount && /^\d+$/.test(String(w).trim())));
419
429
  const isKey = (w) => /^[0-9*#]$/.test(String(w).trim());
420
- const keyed = (w) => isKey(w) && (matchesChoice(raw, [w]) || keyWithOnlyCourtesy(b, String(w).trim(), !isNoType(c)) || (spoken !== b && keyWithOnlyCourtesy(spoken, String(w).trim(), !isNoType(c))));
430
+ const firm = c.key === 'yes' && c.exact === true;
431
+ const keyed = (w) => isKey(w) && (firm
432
+ ? firmKey(b, String(w).trim()) || (spoken !== b && firmKey(spoken, String(w).trim()))
433
+ : matchesChoice(raw, [w]) || keyWithOnlyCourtesy(b, String(w).trim(), !isNoType(c)) || (spoken !== b && keyWithOnlyCourtesy(spoken, String(w).trim(), !isNoType(c))));
421
434
  // A question is not a confirmation: "sure?" or "1?" never picks a choice that charges or cancels.
422
435
  if (c.exact === true && /[?¿]/.test(raw)) {
423
436
  // not this choice
@@ -1 +1 @@
1
- export const JSFE_RUNTIME_FINGERPRINT = "sha256:ec8330acadcdcdf499278ebaacbd0f4ab3810a67be977d710ce77d40a8978a68";
1
+ export const JSFE_RUNTIME_FINGERPRINT = "sha256:2ee0e74e5da06d62d22520608be1621f099396640d5a2bc08b2f8855af499f8e";
@@ -1,3 +1,16 @@
1
+ ## 1.10.8: "por favor" confirms
2
+
3
+ "please" / "por favor" alone are a firm YES (`CONFIRM_WORDS`; owner rule 2026-10-26: prod 21:47, "por favor" to "presione 1 o
4
+ diga SÍ" at a payment offer was not taken and the payment was lost). "No, por favor", "espere por favor" and "un enlace
5
+ por favor" are still not a YES.
6
+
7
+ ## 1.10.7: a firm question's key in minimal context
8
+
9
+ At a firm question (a yes choice that charges or cancels), its key confirms only alone or beside please/thanks or a CONFIRM
10
+ word: "1", "uno", "1, por favor", "Sí, 1" (owner rule 2026-10-25). It no longer confirms beside a soft YES word or an
11
+ acknowledgement ("1 está bien", "ok 1"), a key-naming word ("opción 1", "el número 1", which 1.10.5 had admitted) or other
12
+ filler ("um, 1"). Firm YES words are unchanged ("Sí, está bien" still confirms).
13
+
1
14
  ## 1.10.6: pointing at the offered thing
2
15
 
3
16
  At a soft question (a yes choice that does not charge or cancel), a word pointing at the offered thing may lead the YES:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsfe",
3
- "version": "1.10.6",
3
+ "version": "1.10.8",
4
4
  "description": "TypeScript workflow engine for conversational/automation apps: multi-flow orchestration, interrupt/resume, stack-based control, robust errors, and flexible tool/REST integration.",
5
5
  "license": "MIT",
6
6
  "author": "Ron Pinkas",