jsfe 1.10.5 → 1.10.7

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":"AA4LA;;;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;;;;;;;;AA/ZD,qCAKiD"}
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/helpers/answer.js"],"names":[],"mappings":"AA4MA;;;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,qCAKiD"}
@@ -18,6 +18,9 @@ export const ANSWER_WORDS = {
18
18
  'si', 'sí', 'claro', 'claro que sí', 'claro que si', 'seguro', 'por favor', 'correcto', 'está bien', 'esta bien', 'de acuerdo',
19
19
  'estoy de acuerdo', 'dale', 'por supuesto', 'bueno', 'confirmo', 'confirmado', 'apruebo', 'aprobado', 'adelante', 'hazlo',
20
20
  'procede', 'perfecto', 'exacto', 'eso es', 'así es', 'asi es',
21
+ // the offered thing, pointed at (prod 2026-10-25 17:46: "Ese está bien." to "¿Se lo envío a …?" was not a yes)
22
+ 'ese mismo', 'esa misma', 'eso mismo', 'el mismo', 'la misma', "that's the one", 'that is the one',
23
+ 'the same one',
21
24
  // agreeing to what the question offers: "Sí, quiero continuar" to "diga SÍ para continuar" (replay of prod, 2026-10-14).
22
25
  // A bare "I want" / "quiero" is never a confirmation (owner decision 2026-10-15): "Quiero pagar" at the express offer,
23
26
  // which charges on its YES, was a YES because 'pagar' is that choice's own word.
@@ -76,6 +79,10 @@ const THANKS = ['thanks', 'thank you', 'thank you so much', 'thanks a lot', 'gra
76
79
  const ACKNOWLEDGEMENTS = ['ok', 'okay', 'okey', 'está bien', 'esta bien', 'bueno', 'fine', "that's fine", 'alright', 'all right',
77
80
  'perfect', 'perfecto', 'sounds good', 'great', 'excelente', 'muy bien'].map(normalize).map((w) => w.split(' '));
78
81
  const CONFIRM_FILLER = CONFIRM_WORDS.map(normalize).map((w) => w.split(' '));
82
+ // At a soft question (a yes choice that does not charge or cancel), a word pointing at the offered thing may lead the YES:
83
+ // "ese está bien", "esa sí", "that one is fine". It is never a YES alone; a firm question stays strict.
84
+ const POINTERS = ['ese', 'esa', 'eso', 'esos', 'esas', 'ese es', 'esa es', 'that', 'this', 'that one', 'this one', 'that one is',
85
+ 'this one is', 'that is', 'this is'].map(normalize).map((w) => w.split(' '));
79
86
  // articles and possessives in front of an exact choice's own words ("Yes, the full balance", "Sí, el saldo completo")
80
87
  const ARTICLES = ['the', 'my', 'el', 'la', 'mi'].map((w) => [w]);
81
88
  const YES_SET = new Set(ANSWER_WORDS.yes.map(normalize));
@@ -87,7 +94,7 @@ const phraseAt = (tokens, i, phrase) => phrase.every((w, j) => tokens[i + j] ===
87
94
  * words from `words` — at least one of them. A YES that acts must be the whole answer (owner rule, 2026-10-14): "Yeah, sure,
88
95
  * thank you" and "Sí, claro, por favor" are YES; "yes, pay it" and "I made payments by 1" are not.
89
96
  */
90
- function onlyAffirmative(b, words, needOne = true, filler = []) {
97
+ function onlyAffirmative(b, words, needOne = true, filler = [], courtesyWords = COURTESY) {
91
98
  if (!words.length && needOne) {
92
99
  return false;
93
100
  }
@@ -101,7 +108,7 @@ function onlyAffirmative(b, words, needOne = true, filler = []) {
101
108
  let saw = false;
102
109
  while (i < tk.length) {
103
110
  const yes = own.filter((p) => at(i, p)).sort((x, y) => y.length - x.length)[0];
104
- const courtesy = yes ? null : [...COURTESY, ...filler].filter((p) => at(i, p)).sort((x, y) => y.length - x.length)[0];
111
+ const courtesy = yes ? null : [...courtesyWords, ...filler].filter((p) => at(i, p)).sort((x, y) => y.length - x.length)[0];
105
112
  if (yes) {
106
113
  i += yes.length;
107
114
  saw = true;
@@ -176,6 +183,15 @@ function textRequest(input, words, extra) {
176
183
  * when `yesOk`, a YES word ("yes 1", "sí, 1"). Owner decision 2026-10-15: "Yes 1" at "tell me the product number" was
177
184
  * missed. Anything else around the key ("no 1", "1 or 2", "I paid 1 already") is not that key.
178
185
  */
186
+ // The only words a firm YES's key may carry besides CONFIRM words (owner rule 2026-10-25): "1, por favor", "sí, 1".
187
+ const PLEASE_THANKS = ['please', 'por favor', ...THANKS].map(normalize).map((w) => w.split(' '));
188
+ /** A firm key: the key alone, or beside please/thanks and firm CONFIRM words only ("Sí, 1" — owner 2026-10-15 and
189
+ * 2026-10-25). Never a soft YES word, an acknowledgement, a key-naming word, a form of address or filler beside it. */
190
+ function firmKey(b, key) {
191
+ const tk = String(b).replace(/\./g, ' ').split(' ').filter(Boolean);
192
+ const at = tk.reduce((acc, t, i) => (t === key ? [...acc, i] : acc), []);
193
+ return at.length === 1 && onlyAffirmative(tk.filter((t, i) => i !== at[0]).join(' '), CONFIRM_WORDS, false, [], PLEASE_THANKS);
194
+ }
179
195
  // Words that name the key itself when said right before it: "el número 4", "opción 2", "number 4", "the 4" (prod
180
196
  // 2026-10-25 18:25: "Número 4" and "El número 4" at a numbered product list were not understood, twice).
181
197
  const KEY_NAMES = new Set(['number', 'numero', 'option', 'opcion', 'item', 'choice', 'the', 'el', 'la'].map(normalize));
@@ -410,12 +426,15 @@ export function pickChoice(answer, choices, acceptOther) {
410
426
  const strict = all.filter((w) => c.exact === true || /^[0-9*#]$/.test(String(w).trim()) || YES_SET.has(normalize(w)))
411
427
  .filter((w) => !(amount && /^\d+$/.test(String(w).trim())));
412
428
  const isKey = (w) => /^[0-9*#]$/.test(String(w).trim());
413
- const keyed = (w) => isKey(w) && (matchesChoice(raw, [w]) || keyWithOnlyCourtesy(b, String(w).trim(), !isNoType(c)) || (spoken !== b && keyWithOnlyCourtesy(spoken, String(w).trim(), !isNoType(c))));
429
+ const firm = c.key === 'yes' && c.exact === true;
430
+ const keyed = (w) => isKey(w) && (firm
431
+ ? firmKey(b, String(w).trim()) || (spoken !== b && firmKey(spoken, String(w).trim()))
432
+ : matchesChoice(raw, [w]) || keyWithOnlyCourtesy(b, String(w).trim(), !isNoType(c)) || (spoken !== b && keyWithOnlyCourtesy(spoken, String(w).trim(), !isNoType(c))));
414
433
  // A question is not a confirmation: "sure?" or "1?" never picks a choice that charges or cancels.
415
434
  if (c.exact === true && /[?¿]/.test(raw)) {
416
435
  // not this choice
417
436
  }
418
- else if (strict.some(keyed) || onlyAffirmative(b, [...strict.filter((w) => !isKey(w)), ...(c.key === 'yes' && c.exact !== true ? THANKS : [])], true, c.exact === true ? (c.key === 'yes' ? ACKNOWLEDGEMENTS : [...ACKNOWLEDGEMENTS, ...CONFIRM_FILLER, ...ARTICLES]) : [])) {
437
+ else if (strict.some(keyed) || onlyAffirmative(b, [...strict.filter((w) => !isKey(w)), ...(c.key === 'yes' && c.exact !== true ? THANKS : [])], true, c.exact === true ? (c.key === 'yes' ? ACKNOWLEDGEMENTS : [...ACKNOWLEDGEMENTS, ...CONFIRM_FILLER, ...ARTICLES]) : (c.key === 'yes' ? POINTERS : []))) {
419
438
  found = c.key;
420
439
  break;
421
440
  }
@@ -1 +1 @@
1
- export const JSFE_RUNTIME_FINGERPRINT = "sha256:5dcc5703f78eb0d76716ae4ec5d702abefd508aac9a44b3cb67b62efc93e244d";
1
+ export const JSFE_RUNTIME_FINGERPRINT = "sha256:7d7eed4421d54620c8003db7ad362a4ecfb2689e8fcaf050e43fd93912f6e914";
@@ -1,3 +1,17 @@
1
+ ## 1.10.7: a firm question's key in minimal context
2
+
3
+ At a firm question (a yes choice that charges or cancels), its key confirms only alone or beside please/thanks or a CONFIRM
4
+ word: "1", "uno", "1, por favor", "Sí, 1" (owner rule 2026-10-25). It no longer confirms beside a soft YES word or an
5
+ 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
6
+ filler ("um, 1"). Firm YES words are unchanged ("Sí, está bien" still confirms).
7
+
8
+ ## 1.10.6: pointing at the offered thing
9
+
10
+ At a soft question (a yes choice that does not charge or cancel), a word pointing at the offered thing may lead the YES:
11
+ "ese está bien", "esa sí", "that one is fine" (prod 2026-10-25 17:46: "Ese está bien." to "¿Se lo envío a …?" was not a
12
+ yes and the caller lost the flow). "ese mismo", "el mismo", "that's the one" are soft YES phrases. A pointing word alone is
13
+ never a YES, and a firm question stays strict.
14
+
1
15
  ## 1.10.5: a key named before it
2
16
 
3
17
  At a numbered choice, a word naming the key said right before it picks the key: "el número 4", "opción 2", "number 4", "the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsfe",
3
- "version": "1.10.5",
3
+ "version": "1.10.7",
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",