jsfe 1.19.1 → 1.21.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/README.md CHANGED
@@ -398,6 +398,26 @@ reasonFor })` builds both executors' instructions. A reason question declares no
398
398
  unchanged: the generic withdrawal includes "I no longer want it", which at a reason question withdrew three prod
399
399
  cancellations.
400
400
 
401
+ **An option said back as offered (jsfe 1.21.0):** an answer that repeats an option exactly as the question offered it is
402
+ that option's word alone: "Sí para cancelar" to "diga SÍ para cancelar", "Yes to submit it" to "type YES to submit it".
403
+ `ask-choice` applies `withoutPromptEcho(answer, [question, question_es, retry, retry_es])` before it matches, so form inputs
404
+ and confirmations get it too. An offered option is a word or words in capitals followed by "to" or "para" and the clause
405
+ after it, up to punctuation or the next "or" / "o". Only the whole echo counts, courtesy and a repeated word aside: "Sí para
406
+ cancelar la cuenta", the echo of an option the question did not offer ("Sí para pagar" at a cancellation) and a question
407
+ ("¿Sí para cancelar?") are unchanged, so an `exact` choice is still confirmed only by its own words. Write offered options
408
+ in capitals for it to apply.
409
+
410
+ **The re-ask names the customer, opt-in (jsfe 1.20.0):** `sorryNotCaught(lang, cargo)` is the acknowledgement before a
411
+ question asked again ("Sorry, I didn't catch that. " / "Disculpe, no le entendí. "), used by `formInputPrompt`, `ask-choice`
412
+ and the provider menu. A flow set that sets `cargo.sorryByName = true` (for example once the caller is verified) gets it with
413
+ `cargo.displayName` ("Disculpe, Ana, no le entendí. "); without it the wording is unchanged.
414
+
415
+ **Acknowledging only data, opt-in (jsfe 1.20.0):** a form declaring `acknowledge: 'data'` (or the nearest enclosing form
416
+ that declares it) says "Got it, your …" / "Okay, I noted your …" only for a value the caller supplied, an input whose profile
417
+ kind is digits, email, phone, amount, identifier, account or text. A pick among offered words (`choice`, `pattern`), such as
418
+ NEW CARD, is not acknowledged: the next question already shows it was understood. Rejections are always said. Without the
419
+ attribute every input is acknowledged as before (`formAcknowledges(cargo, reading)`).
420
+
401
421
  **Digits said in groups (jsfe 1.19.1):** every `digits` input reads a comma, or a period and a space, after a group of
402
422
  one to three digits as a pause inside one number, because speech-to-text writes spoken groups that way ("926, 1 0." is
403
423
  the ZIP 92610, "7, 9, 984. 5." the code 799845). A comma after a longer number still separates two numbers ("92610,
@@ -1 +1 @@
1
- {"version":3,"file":"choice-flow.d.ts","sourceRoot":"","sources":["../../src/forms/choice-flow.js"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6rBE"}
1
+ {"version":3,"file":"choice-flow.d.ts","sourceRoot":"","sources":["../../src/forms/choice-flow.js"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAysBE"}
@@ -3,7 +3,7 @@ export const FLOWS = [
3
3
  {
4
4
  "id": "ask-choice",
5
5
  "name": "AskChoice",
6
- "version": "1.19.0",
6
+ "version": "1.21.0",
7
7
  "description": "Worker: ask one question and return cargo.choice plus the original cargo.choiceText. Declared choices, precheck keys and typed answer-validator keys keep priority across both read passes. Exact negative choices accept only their own declared words and keys. With amount, an unowned legacy payment question accepts a complete USD monetary answer or a simple payment instruction through readMoneyAmount; uncertain prose yields to DISPATCH without declaring an action failure. A lone digit keeps the question's keypad policy; amount:'marked' still requires marked money. An owning FORM supplies form_context and performs its own field, correction, provider-question and confirmation matching before deciding to retry or yield, retaining its draft and safety guards. Optional answer_precheck runs before choices; answer_validator runs only when no choice matched. AGENT/0 requests a person; EXIT/* leaves the request; a consumed switch offer routes its declared flow. Params include question(_es), choices [{key,phrases,exact?,negative?,neutral?}], retry(_es), accept_other, expect, amount, digits, exit_context(_es), pii and form_context.",
8
8
  "parameters": [
9
9
  { "name": "form_context", "type": "object", "description": "Optional declared FORM reader context {form,current,names,questions}; valid field readings take precedence over stale verification-code echoes." },
@@ -216,13 +216,13 @@ export const FLOWS = [
216
216
  "id": "ac_retry_en",
217
217
  "type": "SET",
218
218
  "variable": "ac_retry",
219
- "value": "typeof retry !== 'undefined' && retry ? retry : \"Sorry, I didn't catch that. \" + question"
219
+ "value": "typeof retry !== 'undefined' && retry ? retry : sorryNotCaught('en', cargo) + question"
220
220
  },
221
221
  {
222
222
  "id": "ac_retry_spanish",
223
223
  "type": "SET",
224
224
  "variable": "ac_retry_es",
225
- "value": "typeof retry_es !== 'undefined' && retry_es ? retry_es : 'Disculpe, no le entendí. ' + ac_q_es"
225
+ "value": "typeof retry_es !== 'undefined' && retry_es ? retry_es : sorryNotCaught('es', cargo) + ac_q_es"
226
226
  },
227
227
  {
228
228
  "id": "ac_exit_context",
@@ -391,6 +391,12 @@ export const FLOWS = [
391
391
  "variable": "ac_prechecked",
392
392
  "value": "typeof answer_key !== 'undefined' && answer_key ? String(answer_key) : ''"
393
393
  },
394
+ {
395
+ "id": "ac_prompt_echo",
396
+ "type": "SET",
397
+ "variable": "ac_answer",
398
+ "value": "withoutPromptEcho(ac_answer, [ac_q, ac_q_es, ac_retry, ac_retry_es])"
399
+ },
394
400
  {
395
401
  "id": "ac_match",
396
402
  "type": "SET",
@@ -562,6 +568,12 @@ export const FLOWS = [
562
568
  "variable": "ac_prechecked",
563
569
  "value": "typeof answer_key !== 'undefined' && answer_key ? String(answer_key) : ''"
564
570
  },
571
+ {
572
+ "id": "ac_prompt_echo_again",
573
+ "type": "SET",
574
+ "variable": "ac_answer",
575
+ "value": "withoutPromptEcho(ac_answer, [ac_q, ac_q_es, ac_retry, ac_retry_es])"
576
+ },
565
577
  {
566
578
  "id": "ac_match_again",
567
579
  "type": "SET",
@@ -4,7 +4,7 @@ import { linkFormSchemas, validateFlowContracts } from './contracts.js';
4
4
  import { compileFormPrompts } from './prompt-compiler.js';
5
5
  import { withSafetyRevision } from './continuation-safety.js';
6
6
  import { capturedAuthorSpec, copyAuthorSpec, authoredExpressions } from './declaration-capture.js';
7
- const formKeys = new Set(['inputs', 'before', 'after', 'confirm', 'before_confirm', 'declined', 'stop', 'close_on_stop', 'resume_on_parent_change', 'done', 'validator', 'confirmation_condition', 'prompt', 'prompt_es', 'incomplete_outcome', 'on_exhausted', 'on_no', 'must_complete']);
7
+ const formKeys = new Set(['inputs', 'before', 'after', 'confirm', 'before_confirm', 'declined', 'stop', 'close_on_stop', 'resume_on_parent_change', 'done', 'validator', 'confirmation_condition', 'prompt', 'prompt_es', 'incomplete_outcome', 'on_exhausted', 'on_no', 'must_complete', 'acknowledge']);
8
8
  const sharedKeys = ['id', 'name', 'description', 'version', 'scope', 'primary', 'parameters', 'contract', 'parameterInstructions'];
9
9
  const safe = /^[A-Za-z_$][\w$]*$/;
10
10
  const fail = message => { throw new Error('Flow declaration: ' + message); };
@@ -1,4 +1,4 @@
1
- export function formFlow({ id, name, version, description, inputs, after, extraVars, parameters, confirm, before_confirm, declined, stop, close_on_stop, on_no, resume_on_parent_change, before, done, primary, scope, validator, confirmation_condition, prompt, prompt_es, incomplete_outcome, on_exhausted, must_complete }: {
1
+ export function formFlow({ id, name, version, description, inputs, after, extraVars, parameters, confirm, before_confirm, declined, stop, close_on_stop, on_no, resume_on_parent_change, before, done, primary, scope, validator, confirmation_condition, prompt, prompt_es, incomplete_outcome, on_exhausted, must_complete, acknowledge }: {
2
2
  id: any;
3
3
  name: any;
4
4
  version: any;
@@ -25,6 +25,7 @@ export function formFlow({ id, name, version, description, inputs, after, extraV
25
25
  incomplete_outcome?: null | undefined;
26
26
  on_exhausted?: null | undefined;
27
27
  must_complete?: boolean | undefined;
28
+ acknowledge?: string | undefined;
28
29
  }): {
29
30
  variables: {
30
31
  [k: string]: {
@@ -1 +1 @@
1
- {"version":3,"file":"flows.d.ts","sourceRoot":"","sources":["../../src/forms/flows.js"],"names":[],"mappings":"AAqIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6DC;AACD;;;GAGG;AACH;;;;;;EAGC;AAwfD,wHAAwH;AACxH,wEAaC;AACD,4FAA4F;AAC5F;;;EAYC;AACD,sGAAsG;AACtG;;;EAOC;AA7rBM,6CAAuG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAs3B9G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAOG"}
1
+ {"version":3,"file":"flows.d.ts","sourceRoot":"","sources":["../../src/forms/flows.js"],"names":[],"mappings":"AAqIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8DC;AACD;;;GAGG;AACH;;;;;;EAGC;AAwfD,wHAAwH;AACxH,wEAaC;AACD,4FAA4F;AAC5F;;;EAYC;AACD,sGAAsG;AACtG;;;EAOC;AA9rBM,6CAAuG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAu3B9G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAOG"}
@@ -127,8 +127,10 @@ function validateAcceptanceDeclarations(id, inputs) {
127
127
  else { /* no invites, or a list of names */ }
128
128
  }
129
129
  }
130
- export function formFlow({ id, name, version, description, inputs, after = [], extraVars = {}, parameters = [], confirm = null, before_confirm = [], declined = [], stop = '', close_on_stop = false, on_no = '', resume_on_parent_change = false, before = [], done = true, primary = false, scope = 'isolated', validator = '', confirmation_condition = 'true', prompt = undefined, prompt_es = undefined, incomplete_outcome = null, on_exhausted = null, must_complete = false }) {
130
+ export function formFlow({ id, name, version, description, inputs, after = [], extraVars = {}, parameters = [], confirm = null, before_confirm = [], declined = [], stop = '', close_on_stop = false, on_no = '', resume_on_parent_change = false, before = [], done = true, primary = false, scope = 'isolated', validator = '', confirmation_condition = 'true', prompt = undefined, prompt_es = undefined, incomplete_outcome = null, on_exhausted = null, must_complete = false, acknowledge = 'all' }) {
131
131
  validateFormExhaustion(on_exhausted);
132
+ if (acknowledge !== 'all' && acknowledge !== 'data')
133
+ throw new Error(`FORM ${id}: acknowledge must be 'all' or 'data'`);
132
134
  if (on_no !== '' && (typeof on_no !== 'string' || !/^[\w-]+$/.test(on_no)))
133
135
  throw new Error(`FORM ${id}: on_no must be a flow id`);
134
136
  if (typeof must_complete !== 'boolean')
@@ -162,7 +164,7 @@ export function formFlow({ id, name, version, description, inputs, after = [], e
162
164
  ...(hasFormResponse(inputs) ? [{ ...SET(`${id}_response_reader_required`, 'noop', "typeof validateFormResponse === 'function'"), requireTrue: true }] : []),
163
165
  ...proposalRuntimeSteps(id, [], hasInputProposals(inputs) ? [INPUT_PROPOSALS_REQUIREMENT] : []),
164
166
  SET(`${id}_resume_kind`, 'form_internal_resume', '!!form_instance'),
165
- SET(`${id}_open`, 'form_instance', `openFormInstance(cargo, ${JSON.stringify(id)}, inputs, { parent: parent_form || null, input: result_input || '', context:!!parent_form && !result_input, resume_on_parent_change: ${resume_on_parent_change === true}, resume: form_instance || (!parent_form ? (cargo.formTasks || {})[${JSON.stringify(id)}] || '' : ''), providers: provides, questions: questions, incomplete_outcome: ${incompleteExpression}, on_exhausted: form_on_exhausted, on_no: form_on_no, must_complete: form_must_complete })`),
167
+ SET(`${id}_open`, 'form_instance', `openFormInstance(cargo, ${JSON.stringify(id)}, inputs, { parent: parent_form || null, input: result_input || '', context:!!parent_form && !result_input, resume_on_parent_change: ${resume_on_parent_change === true}, resume: form_instance || (!parent_form ? (cargo.formTasks || {})[${JSON.stringify(id)}] || '' : ''), providers: provides, questions: questions, incomplete_outcome: ${incompleteExpression}, on_exhausted: form_on_exhausted, on_no: form_on_no, must_complete: form_must_complete${acknowledge === 'data' ? ", acknowledge: 'data'" : ''} })`),
166
168
  SIDE(`${id}_task`, `(!parent_form ? (cargo.formTasks = cargo.formTasks || {}, cargo.formTasks[${JSON.stringify(id)}] = form_instance) : true, true)`),
167
169
  SIDE(`${id}_provider_reset`, '(delete cargo.forms[form_instance].providerRequests, delete cargo.forms[form_instance].activeGates, delete cargo.forms[form_instance].providerGateActive, true)'),
168
170
  SIDE(`${id}_pass_reset`, '(cargo.forms[form_instance].replays = 0, form_internal_resume ? true : (cargo.forms[form_instance].attempts = {},cargo.forms[form_instance].misses={},cargo.forms[form_instance].feedback={}), true)'),
@@ -521,8 +523,8 @@ const acceptedEffects = {
521
523
  WHEN('ie_none', '!ca_h', END('ie_end')),
522
524
  SET('ie_rest', 'ca_rest', 'readings.slice(1)'),
523
525
  WHEN('ie_reject', "ca_h.outcome === 'rejected'", SIDE('ie_attempt', "(cargo.forms[ca_h.form].attempts[ca_h.asked || ca_h.name] = Number(cargo.forms[ca_h.form].attempts[ca_h.asked || ca_h.name] || 0) + 1, cargo.forms[ca_h.form].feedback=cargo.forms[ca_h.form].feedback || {}, cargo.forms[ca_h.form].feedback[ca_h.asked || ca_h.name]='invalid', true)")),
524
- SET('ie_say_en', 'ca_ack', "ca_h.outcome === 'rejected' && ca_h.quiet ? '' : ca_h.outcome === 'rejected' ? (ca_h.message || ('That ' + (ca_h.label || ca_h.name) + \" doesn't look right.\")) : ca_h.silent === true || ca_h.fromPending ? '' : ca_h.outcome === 'known' && !ca_h.current ? ('Thank you, I already have your ' + ca_h.label + '.') : ca_h.outcome === 'changed' && ca_h.origin !== 'activation' ? ('Okay, I noted your ' + ca_h.label + '.') : (ca_h.outcome === 'taken' || ca_h.outcome === 'pending') && ca_h.origin !== 'activation' ? ('Got it, your ' + ca_h.label + '.') : ''"),
525
- SET('ie_say_es', 'ca_ack_es', "ca_h.outcome === 'rejected' && ca_h.quiet ? '' : ca_h.outcome === 'rejected' ? (ca_h.message_es || ca_h.message || ('Ese ' + (ca_h.label_es || ca_h.label || ca_h.name) + ' no parece correcto.')) : ca_h.silent === true || ca_h.fromPending ? '' : ca_h.outcome === 'known' && !ca_h.current ? ('Gracias, ya tengo su ' + ca_h.label_es + '.') : ca_h.outcome === 'changed' && ca_h.origin !== 'activation' ? ('Listo, anoté su ' + ca_h.label_es + '.') : (ca_h.outcome === 'taken' || ca_h.outcome === 'pending') && ca_h.origin !== 'activation' ? ('Entendido, su ' + ca_h.label_es + '.') : ''"),
526
+ SET('ie_say_en', 'ca_ack', "ca_h.outcome === 'rejected' && ca_h.quiet ? '' : ca_h.outcome === 'rejected' ? (ca_h.message || ('That ' + (ca_h.label || ca_h.name) + \" doesn't look right.\")) : ca_h.silent === true || ca_h.fromPending || !formAcknowledges(cargo, ca_h) ? '' : ca_h.outcome === 'known' && !ca_h.current ? ('Thank you, I already have your ' + ca_h.label + '.') : ca_h.outcome === 'changed' && ca_h.origin !== 'activation' ? ('Okay, I noted your ' + ca_h.label + '.') : (ca_h.outcome === 'taken' || ca_h.outcome === 'pending') && ca_h.origin !== 'activation' ? ('Got it, your ' + ca_h.label + '.') : ''"),
527
+ SET('ie_say_es', 'ca_ack_es', "ca_h.outcome === 'rejected' && ca_h.quiet ? '' : ca_h.outcome === 'rejected' ? (ca_h.message_es || ca_h.message || ('Ese ' + (ca_h.label_es || ca_h.label || ca_h.name) + ' no parece correcto.')) : ca_h.silent === true || ca_h.fromPending || !formAcknowledges(cargo, ca_h) ? '' : ca_h.outcome === 'known' && !ca_h.current ? ('Gracias, ya tengo su ' + ca_h.label_es + '.') : ca_h.outcome === 'changed' && ca_h.origin !== 'activation' ? ('Listo, anoté su ' + ca_h.label_es + '.') : (ca_h.outcome === 'taken' || ca_h.outcome === 'pending') && ca_h.origin !== 'activation' ? ('Entendido, su ' + ca_h.label_es + '.') : ''"),
526
528
  WHEN('ie_say', 'ca_ack', SAY('ie_ack', '{{ca_ack}}', '{{ca_ack_es}}')),
527
529
  WHEN('ie_callback', "ca_h.after && ca_h.outcome !== 'known' && ca_h.outcome !== 'rejected' && ca_h.outcome !== 'pending'", FLOW('ie_after', '{{ca_h.after}}', 'call', { form: '{{ca_h.form}}', input: '{{ca_h.name}}', value: '{{ca_h.value}}' })),
528
530
  WHEN('ie_more', 'ca_rest.length > 0', FLOW('ie_next', 'input-accepted-effects', 'replace', { readings: '{{ca_rest}}' })),
@@ -809,8 +811,8 @@ const providerMenu = {
809
811
  variables: vars({ retry: '', pm_q: '', pm_q_es: '', pm_choices: [], pm_key: '', pm_keys: [], pm_close: false, pm_flow: '', pm_bye: '', pm_bye_es: '', pm_who: '', pm_sorry: '', pm_sorry_es: '' }),
810
812
  steps: [
811
813
  SET('pm_name', 'pm_who', NAME_JS),
812
- SET('pm_question', 'pm_q', `(function () { ${RENDER_JS} var m = provides.menu; var t = cargo.voice && m.question_voice ? m.question_voice : m.question; return (retry === '1' ? "Sorry, I didn't catch that. " : '') + fill(t, {}, null, 'en', { name: pm_who, verb: cargo.verb || (cargo.voice ? 'say' : 'type') }); })()`),
813
- SET('pm_question_es', 'pm_q_es', `(function () { ${RENDER_JS} var m = provides.menu; var t = cargo.voice && (m.question_voice_es || m.question_voice) ? (m.question_voice_es || m.question_voice) : (m.question_es || m.question); return (retry === '1' ? 'Disculpe, no le entendí. ' : '') + fill(t, {}, null, 'es', { name: pm_who, verb: cargo.verb_es || (cargo.voice ? 'diga' : 'escriba') }); })()`),
814
+ SET('pm_question', 'pm_q', `(function () { ${RENDER_JS} var m = provides.menu; var t = cargo.voice && m.question_voice ? m.question_voice : m.question; return (retry === '1' ? sorryNotCaught('en', cargo) : '') + fill(t, {}, null, 'en', { name: pm_who, verb: cargo.verb || (cargo.voice ? 'say' : 'type') }); })()`),
815
+ SET('pm_question_es', 'pm_q_es', `(function () { ${RENDER_JS} var m = provides.menu; var t = cargo.voice && (m.question_voice_es || m.question_voice) ? (m.question_voice_es || m.question_voice) : (m.question_es || m.question); return (retry === '1' ? sorryNotCaught('es', cargo) : '') + fill(t, {}, null, 'es', { name: pm_who, verb: cargo.verb_es || (cargo.voice ? 'diga' : 'escriba') }); })()`),
814
816
  SET('pm_build', 'pm_choices', "provides.facts.concat(provides.sets || []).filter(function (f) { return Array.isArray(f.phrases ?? f.words) && (f.phrases ?? f.words).length; }).map(function (f) { return { key: 'fact:' + f.key, phrases: f.phrases ?? f.words }; }).concat((provides.menu.choices || []).map(function (c) { return { key: 'act:' + c.key, phrases: c.phrases ?? c.words, exact: c.exact === true }; })).concat(provides.menu.done ? [{ key: 'done', phrases: provides.menu.done.phrases ?? provides.menu.done.words, exact: true }] : [])"),
815
817
  FLOW('pm_ask', 'ask-choice', 'call', { question: '{{pm_q}}', question_es: '{{pm_q_es}}', choices: '{{pm_choices}}', accept_other: true, digits: { min: 1, max: 1 }, exit_context: '{{provides.subject}}', exit_context_es: '{{provides.subject_es}}' }),
816
818
  // A declared terminal phrase (for example "no thanks") may also fit a shorter action
@@ -41,6 +41,7 @@ export function numericAmountReading(input: any): {
41
41
  value: number;
42
42
  candidates: number;
43
43
  };
44
+ export function withoutPromptEcho(answer: any, questions: any): any;
44
45
  /**
45
46
  * ask-choice's matcher: the key of the choice the answer picks, '__agent', '__exit', or '' (no choice).
46
47
  * choices: [{ key, phrases, negative?, neutral?, exact? }]. A key (digit, * or #) and a YES word pick a choice only as the whole
@@ -1 +1 @@
1
- {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/helpers/answer.js"],"names":[],"mappings":"AAsNA;;;GAGG;AACH,wEAkBC;AAED,qHAAqH;AACrH,+CAGC;AAED;;;;GAIG;AACH,mDAIC;AAED,+HAA+H;AAC/H,oDAIC;AAcD,2GAA2G;AAC3G,uDAGC;AAOD;;;;;GAKG;AACH,+DAUC;AAKD;;;;GAIG;AACH,oDAEC;AAqBD;;;;;;GAMG;AACH,mDAAmF;AAEnF,kGAAkG;AAClG;;;EAoCC;AAUD;;;;;;;;;GASG;AACH,6EA4GC;;;;;;;;AA9cD,qCAKwE"}
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/helpers/answer.js"],"names":[],"mappings":"AAsNA;;;GAGG;AACH,wEAkBC;AAED,qHAAqH;AACrH,+CAGC;AAED;;;;GAIG;AACH,mDAIC;AAED,+HAA+H;AAC/H,oDAIC;AAcD,2GAA2G;AAC3G,uDAGC;AAOD;;;;;GAKG;AACH,+DAUC;AAKD;;;;GAIG;AACH,oDAEC;AAqBD;;;;;;GAMG;AACH,mDAAmF;AAEnF,kGAAkG;AAClG;;;EAoCC;AAqBD,oEAqBC;AAED;;;;;;;;;GASG;AACH,6EA4GC;;;;;;;;AAhfD,qCAKwE"}
@@ -398,6 +398,41 @@ const KEY_WORDS = { cero: '0', zero: '0', uno: '1', una: '1', one: '1', dos: '2'
398
398
  function spokenKeys(b) {
399
399
  return String(b).replace(/\./g, ' ').split(' ').filter(Boolean).map((t) => KEY_WORDS[t] ?? t).join(' ');
400
400
  }
401
+ /**
402
+ * An answer that repeats an option exactly as the question offered it ("Sí para cancelar" to "diga SÍ para cancelar", "Yes to
403
+ * submit it" to "say YES to submit it") is that option's word alone (owner 2026-10-31; prod 10-31 11:15: "Sí para cancelar"
404
+ * at a cancellation confirmation was not understood). An offered option is a word or words in capitals followed by "to" or
405
+ * "para" and the clause after it, up to punctuation or the next "or" / "o". Only the whole answer counts, courtesy and a
406
+ * repeated word aside: "Sí para cancelar la cuenta", the echo of an option the question did not offer, or a question
407
+ * ("¿Sí para cancelar?") is unchanged.
408
+ * questions: the texts the caller may have heard (the question, its other language, its re-ask).
409
+ */
410
+ const OFFERED_OPTION = /(?<![\p{L}\p{N}])(\p{Lu}{2,}(?:\s+\p{Lu}{2,})*)\s+(to|para)\s+(.+?)(?=\s*(?:[.,;:!?¿¡]|\s(?:or|o)\s|$))/gu;
411
+ const ECHO_COURTESY = /^(?:(?:please|por favor|thanks|thank you|gracias|okay|ok|um|uh|este|pues)\s+)*|(?:\s+(?:please|por favor|thanks|thank you|gracias|now|ahora))*$/g;
412
+ export function withoutPromptEcho(answer, questions) {
413
+ const raw = String(answer ?? '');
414
+ const said = normalize(raw.replace(/[,;!?¿¡]/g, ' ')).replace(/\.$/, '').replace(ECHO_COURTESY, '').trim();
415
+ if (!said || !/\s(?:to|para)\s/.test(said) || /[?¿]/.test(raw)) {
416
+ // not an echo; a question is never collapsed (it never confirms a choice that charges or cancels)
417
+ return raw;
418
+ }
419
+ else {
420
+ // may be an echo
421
+ }
422
+ for (const text of (Array.isArray(questions) ? questions : [questions]).filter((q) => typeof q === 'string' && q)) {
423
+ for (const [, word, link, clause] of text.matchAll(OFFERED_OPTION)) {
424
+ const w = normalize(word);
425
+ const echo = normalize(`${word} ${link} ${clause}`);
426
+ if (said === echo || said === `${w} ${echo}`) {
427
+ return word.toLowerCase();
428
+ }
429
+ else {
430
+ // not this option
431
+ }
432
+ }
433
+ }
434
+ return raw;
435
+ }
401
436
  /**
402
437
  * ask-choice's matcher: the key of the choice the answer picks, '__agent', '__exit', or '' (no choice).
403
438
  * choices: [{ key, phrases, negative?, neutral?, exact? }]. A key (digit, * or #) and a YES word pick a choice only as the whole
@@ -9,6 +9,7 @@ export function formMustComplete(cargo: any, id: any, input: any): boolean;
9
9
  * question_text / retry_text (and _es): the written-channel wording, used only when the conversation is not a call.
10
10
  */
11
11
  export function formInputPrompt(cargo: any, id: any, input: any, spec: any, data?: {}, language?: string): any;
12
+ export function formAcknowledges(cargo: any, reading: any): boolean;
12
13
  export function consumeFormFeedback(cargo: any, id: any, input: any): boolean;
13
14
  /** Recovery refers to the actual owning root, and never permits a fresh attempt at an unknown action. */
14
15
  export function formConversationOutcome(cargo: any, id: any, reason: any, failure?: boolean, recoveryMode?: string): {
@@ -1 +1 @@
1
- {"version":3,"file":"form-conversation.d.ts","sourceRoot":"","sources":["../../src/helpers/form-conversation.js"],"names":[],"mappings":"AAKA,0EAGC;AACD,oEAGC;AACD;;qGAEqG;AACrG,2EAWC;AACD;;;GAGG;AACH,+GAQC;AACD,8EAAwI;AAExI,yGAAyG;AACzG;;;;;;;;;;;;;;;;;;;;EAUC;AAED,sGAAsG;AACtG;;;;;;;;;;;;;;;;;;;;EAeC;AAED;2HAC2H;AAC3H,8EAOC"}
1
+ {"version":3,"file":"form-conversation.d.ts","sourceRoot":"","sources":["../../src/helpers/form-conversation.js"],"names":[],"mappings":"AAMA,0EAGC;AACD,oEAGC;AACD;;qGAEqG;AACrG,2EAWC;AACD;;;GAGG;AACH,+GAQC;AAKD,oEAOC;AACD,8EAAwI;AAExI,yGAAyG;AACzG;;;;;;;;;;;;;;;;;;;;EAUC;AAED,sGAAsG;AACtG;;;;;;;;;;;;;;;;;;;;EAeC;AAED;2HAC2H;AAC3H,8EAOC"}
@@ -2,6 +2,7 @@
2
2
  import { formIncompleteOutcome, closeFormInstance } from './form-state.js';
3
3
  import { isWholeNo } from './answer.js';
4
4
  import { readInputProfile } from './match-inputs.js';
5
+ import { sorryNotCaught } from './phrases.js';
5
6
  export function clearFormMisses(cargo, id, input) {
6
7
  const state = cargo.forms?.[id];
7
8
  if (!state)
@@ -56,7 +57,29 @@ export function formInputPrompt(cargo, id, input, spec, data = {}, language = 'e
56
57
  return es ? 'Continúe.' : 'Go on.';
57
58
  if (feedback && retry)
58
59
  return retry;
59
- return (feedback === 'miss' ? (es ? 'Disculpe, no le entendí. ' : "Sorry, I didn't catch that. ") : '') + question;
60
+ return (feedback === 'miss' ? sorryNotCaught(es ? 'es' : 'en', cargo) : '') + question;
61
+ }
62
+ /** Whether an accepted input is acknowledged ("Got it, your amount."). A form declaring acknowledge: 'data' (jsfe 1.20.0,
63
+ * owner 2026-10-31), or the nearest enclosing form that declares it, acknowledges only a value the caller supplied (digits,
64
+ * email, phone, amount, identifier, account, text), never a pick among offered words (choice, pattern). Default: every input. */
65
+ const DATA_KINDS = new Set(['digits', 'email', 'phone', 'amount', 'identifier', 'account', 'text']);
66
+ export function formAcknowledges(cargo, reading) {
67
+ const seen = new Set();
68
+ let id = reading && reading.form, mode = 'all';
69
+ while (id && cargo.forms?.[id] && !seen.has(id)) {
70
+ seen.add(id);
71
+ const state = cargo.forms[id];
72
+ if (state.acknowledge) {
73
+ mode = state.acknowledge;
74
+ break;
75
+ }
76
+ id = state.parent;
77
+ }
78
+ if (mode !== 'data')
79
+ return true;
80
+ const state = cargo.forms[reading.form] || {}, group = (state.specs || []).find(s => s.name === reading.name || s.any_of?.some(i => i.name === reading.name));
81
+ const spec = group?.any_of?.find(i => i.name === reading.name) || group, kind = spec?.profile?.kind;
82
+ return DATA_KINDS.has(kind);
60
83
  }
61
84
  export function consumeFormFeedback(cargo, id, input) { if (cargo.forms?.[id]?.feedback)
62
85
  delete cargo.forms[id].feedback[input]; return true; }
@@ -18,7 +18,7 @@ export function settleFormActivations(batch?: {}, cargo?: null): {
18
18
  pending: any[];
19
19
  };
20
20
  /** Explicit ownership: unrelated tasks and sibling inputs never share an instance by definition id. */
21
- export function openFormInstance(cargo: any, definition: any, specs: any, { parent, input, resume, task, providers, questions, context, resume_on_parent_change, incomplete_outcome, on_exhausted, on_no, must_complete }?: {
21
+ export function openFormInstance(cargo: any, definition: any, specs: any, { parent, input, resume, task, providers, questions, context, resume_on_parent_change, incomplete_outcome, on_exhausted, on_no, acknowledge, must_complete }?: {
22
22
  parent?: null | undefined;
23
23
  input?: string | undefined;
24
24
  resume?: string | undefined;
@@ -30,6 +30,7 @@ export function openFormInstance(cargo: any, definition: any, specs: any, { pare
30
30
  incomplete_outcome?: undefined;
31
31
  on_exhausted?: undefined;
32
32
  on_no?: undefined;
33
+ acknowledge?: undefined;
33
34
  must_complete?: undefined;
34
35
  }): any;
35
36
  /** An incomplete optional follow-up may preserve an explicitly completed task outcome. */
@@ -1 +1 @@
1
- {"version":3,"file":"form-state.d.ts","sourceRoot":"","sources":["../../src/helpers/form-state.js"],"names":[],"mappings":"AAQA,qDAKC;AAED,oDAEC;AAED,qFAAqF;AACrF,oEA8BC;AA0CD,2FAEC;AACD,8FAcC;AACD,2DAOC;AACD,uEA6CC;AAED,kGAAkG;AAClG,2GAOC;AACD,0HAA0H;AAC1H,uEAwBC;AACD,8HAA8H;AAC9H;;;;;EAWC;AACD,uGAAuG;AACvG;;;;;;;;;;;;;QAoCC;AAED,0FAA0F;AAC1F;;;SAIC;AACD,gGAAgG;AAChG;;;;;;;;;;;EAQC;AAED,sGAAsG;AACtG,2DAIC;AACD;;;GAGG;AACH;;;;;;;SAkBC;AAED,2FAA2F;AAC3F,oGAIC;AACD,gFA4BC;AAED,2GAA2G;AAC3G;;;EASC;AACD,mEAoBC;AACD,mEAGC;AACD,sEAUC;AACD,+EAEC;AAoCD,qFAYC;AACD,oGAqCC;AACD;;;SAKC;AACD,qEAGC;AACD,gEAgBC;AACD;;uGAEuG;AACvG,sEAGC;AACD,2DAQC;AACD,oGAUC;AAED,uEAAuE;AACvE,wHA+BC;AAED,uHAAuH;AACvH,6EAaC;AACD,mHAAmH;AACnH,iGAsDC;AACD;;;GAGG;AACH;;;SAcC;AACD,+EASC;AACD,8EAeC;AArpBM,8CAAmE"}
1
+ {"version":3,"file":"form-state.d.ts","sourceRoot":"","sources":["../../src/helpers/form-state.js"],"names":[],"mappings":"AAQA,qDAKC;AAED,oDAEC;AAED,qFAAqF;AACrF,oEA8BC;AA0CD,2FAEC;AACD,8FAcC;AACD,2DAOC;AACD,uEA6CC;AAED,kGAAkG;AAClG,2GAOC;AACD,0HAA0H;AAC1H,uEAwBC;AACD,8HAA8H;AAC9H;;;;;EAWC;AACD,uGAAuG;AACvG;;;;;;;;;;;;;;QAuCC;AAED,0FAA0F;AAC1F;;;SAIC;AACD,gGAAgG;AAChG;;;;;;;;;;;EAQC;AAED,sGAAsG;AACtG,2DAIC;AACD;;;GAGG;AACH;;;;;;;SAkBC;AAED,2FAA2F;AAC3F,oGAIC;AACD,gFA4BC;AAED,2GAA2G;AAC3G;;;EASC;AACD,mEAoBC;AACD,mEAGC;AACD,sEAUC;AACD,+EAEC;AAoCD,qFAYC;AACD,oGAqCC;AACD;;;SAKC;AACD,qEAGC;AACD,gEAgBC;AACD;;uGAEuG;AACvG,sEAGC;AACD,2DAQC;AACD,oGAUC;AAED,uEAAuE;AACvE,wHA+BC;AAED,uHAAuH;AACvH,6EAaC;AACD,mHAAmH;AACnH,iGAsDC;AACD;;;GAGG;AACH;;;SAcC;AACD,+EASC;AACD,8EAeC;AAxpBM,8CAAmE"}
@@ -293,9 +293,11 @@ export function settleFormActivations(batch = {}, cargo = null) {
293
293
  rejected: rejected.map(h => h.activation_inferred ? { ...h, ...h.activation_entry, activation_inferred: false } : h), pending: pending.concat(accepted.filter(h => held.has(h.activation_group))).filter(h => !discarded.has(h.activation_group)).map(h => held.has(h.activation_group) ? { ...h, ok: undefined, outcome: 'pending', silent: true } : h) };
294
294
  }
295
295
  /** Explicit ownership: unrelated tasks and sibling inputs never share an instance by definition id. */
296
- export function openFormInstance(cargo, definition, specs, { parent = null, input = '', resume = '', task = '', providers = null, questions = null, context = false, resume_on_parent_change = undefined, incomplete_outcome = undefined, on_exhausted = undefined, on_no = undefined, must_complete = undefined } = {}) {
296
+ export function openFormInstance(cargo, definition, specs, { parent = null, input = '', resume = '', task = '', providers = null, questions = null, context = false, resume_on_parent_change = undefined, incomplete_outcome = undefined, on_exhausted = undefined, on_no = undefined, acknowledge = undefined, must_complete = undefined } = {}) {
297
297
  const incomplete = validateFormIncompleteOutcome(incomplete_outcome);
298
298
  validateFormExhaustion(on_exhausted);
299
+ if (acknowledge !== undefined && acknowledge !== 'all' && acknowledge !== 'data')
300
+ throw new Error("FORM acknowledge must be 'all' or 'data'");
299
301
  cargo.forms ||= {};
300
302
  const existing = resume && cargo.forms[resume];
301
303
  if (resume && !existing)
@@ -313,6 +315,8 @@ export function openFormInstance(cargo, definition, specs, { parent = null, inpu
313
315
  existing.on_no = on_no || '';
314
316
  if (must_complete !== undefined)
315
317
  existing.must_complete = must_complete === true;
318
+ if (acknowledge !== undefined)
319
+ existing.acknowledge = acknowledge;
316
320
  return resume;
317
321
  }
318
322
  if (parent && !cargo.forms[parent])
@@ -333,13 +337,15 @@ export function openFormInstance(cargo, definition, specs, { parent = null, inpu
333
337
  cargo.forms[child].on_no = on_no || '';
334
338
  if (must_complete !== undefined)
335
339
  cargo.forms[child].must_complete = must_complete === true;
340
+ if (acknowledge !== undefined)
341
+ cargo.forms[child].acknowledge = acknowledge;
336
342
  return child;
337
343
  }
338
344
  }
339
345
  cargo.formSequence = Number(cargo.formSequence || 0) + 1;
340
346
  const id = `${definition}:${cargo.formSequence}`;
341
347
  cargo.forms[id] = { id, definition, task: owner?.task || task || id, parent, result_input: input,
342
- on_exhausted: on_exhausted || '', on_no: on_no || '', must_complete: must_complete === true, incomplete_outcome: incomplete, context_only: !!context, resume_on_parent_change: resume_on_parent_change === true, parent_revision: owner?.revision ?? null, specs, values: {}, accepted: {}, errors: {}, pending: {}, seeds: {}, attempts: {}, misses: {}, feedback: {}, prepared: {}, data: {}, arguments: {}, contexts: {}, children: {}, childResults: {}, revision: 0,
348
+ on_exhausted: on_exhausted || '', on_no: on_no || '', must_complete: must_complete === true, ...(acknowledge !== undefined ? { acknowledge } : {}), incomplete_outcome: incomplete, context_only: !!context, resume_on_parent_change: resume_on_parent_change === true, parent_revision: owner?.revision ?? null, specs, values: {}, accepted: {}, errors: {}, pending: {}, seeds: {}, attempts: {}, misses: {}, feedback: {}, prepared: {}, data: {}, arguments: {}, contexts: {}, children: {}, childResults: {}, revision: 0,
343
349
  providers: providers || owner?.providers || null, questions: questions?.length ? questions : owner?.questions || [], status: 'collecting' };
344
350
  if (owner) {
345
351
  if (context) {
@@ -22,6 +22,7 @@ export namespace STANDARD_FUNCTIONS {
22
22
  export { missFormInput };
23
23
  export { formMustComplete };
24
24
  export { formInputPrompt };
25
+ export { formAcknowledges };
25
26
  export { consumeFormFeedback };
26
27
  export { formConversationOutcome };
27
28
  export { readMoneyAmount };
@@ -40,6 +41,7 @@ export namespace STANDARD_FUNCTIONS {
40
41
  export { isAmountAnswer };
41
42
  export { amountInAnswer };
42
43
  export { pickChoice };
44
+ export { withoutPromptEcho };
43
45
  export { readEmail };
44
46
  export { readPhone };
45
47
  export { readInternationalPhone };
@@ -53,6 +55,7 @@ export namespace STANDARD_FUNCTIONS {
53
55
  export { anythingElse };
54
56
  export { goodbye };
55
57
  export { sayName };
58
+ export { sorryNotCaught };
56
59
  export { dateToWords };
57
60
  export { amountToSpeech };
58
61
  export { validateCardNumber };
@@ -141,6 +144,7 @@ import { formNoOwner } from './form-conversation.js';
141
144
  import { missFormInput } from './form-conversation.js';
142
145
  import { formMustComplete } from './form-conversation.js';
143
146
  import { formInputPrompt } from './form-conversation.js';
147
+ import { formAcknowledges } from './form-conversation.js';
144
148
  import { consumeFormFeedback } from './form-conversation.js';
145
149
  import { formConversationOutcome } from './form-conversation.js';
146
150
  import { readMoneyAmount } from './money.js';
@@ -161,6 +165,7 @@ import { isSpelledFragment } from './answer.js';
161
165
  import { isAmountAnswer } from './answer.js';
162
166
  import { amountInAnswer } from './answer.js';
163
167
  import { pickChoice } from './answer.js';
168
+ import { withoutPromptEcho } from './answer.js';
164
169
  import { readEmail } from './contact.js';
165
170
  import { readPhone } from './contact.js';
166
171
  import { readInternationalPhone } from './contact.js';
@@ -174,6 +179,7 @@ import { normalizeAndFindCapture } from './capture.js';
174
179
  import { anythingElse } from './phrases.js';
175
180
  import { goodbye } from './phrases.js';
176
181
  import { sayName } from './phrases.js';
182
+ import { sorryNotCaught } from './phrases.js';
177
183
  import { dateToWords } from './date-words.js';
178
184
  import { amountToSpeech } from './amount-to-speech.js';
179
185
  import { validateCardNumber } from './card-checks.js';
@@ -243,5 +249,5 @@ import { validatePhone } from './validators.js';
243
249
  import { validateEmail } from './validators.js';
244
250
  import { urlToSpeech } from './url-speech.js';
245
251
  import { textWithUrlToSpeech } from './url-speech.js';
246
- export { continuationSafetyProtocol, cancelFormTask, contextualResponseProtocol, validateFormResponse, hasFormResponse, formProposalPolicy, stageFormProposal, nextFormProposal, formProposalReadings, bindFormProposal, decideFormProposal, commitFormProposals, settleFormProposalValidation, formProposalProtocol, validateFormProposalPolicy, validateFormProposalDescriptor, formProposalDescriptor, clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, consumeFormFeedback, formConversationOutcome, readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions, takeChoiceOffer, matchesChoice, ANSWER_WORDS, CONFIRM_WORDS, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice, readEmail, readPhone, readInternationalPhone, readIdentifier, last4, maskEmail, callerTextNumber, textDestination, callerIsInternational, normalizeAndFindCapture, anythingElse, goodbye, sayName, dateToWords, amountToSpeech, validateCardNumber, validateExpiration, consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFormAction, confirmFormRevision, prepareFormAction, actionConfirmationValid, beginFormAction, finishFormAction, actionGateVerified, sourceNeedsLoad, beginSourceRefresh, completeSourceRefresh, pickProviderQuestion, matchInputs, readFormAnswer, readInputProfile, formAcceptanceTrace, resolveFormInputs, formInputApplies, formInputFilled, nextFormInput, formInputChain, openFormInstance, validateFormIncompleteOutcome, formIncompleteOutcome, validateFormExhaustion, exhaustFormInput, formInitialReadings, orderFormReadings, proposedFormValues, applyFormValidation, formReadingDependencies, exclusiveFormReadings, enrichFormMatches, expandFormActivations, settleFormActivations, rememberFormArguments, resetFormInputs, hasFormValue, formPath, formValuesEqual, formReadingReady, formReadingRelevant, formPreparation, queueFormReadings, pendingFormReadings, formWorkLimit, answerResetsFormReplays, rejectFormReadings, invalidateFormInputs, acceptFormReadings, formInstanceApplies, formParentResume, closeFormInstance, checkOtp, clearOtp, maskDestination, validateOTP, OTP_EXPIRY_MS, validateDigits, validatePhone, validateEmail, urlToSpeech, textWithUrlToSpeech };
252
+ export { continuationSafetyProtocol, cancelFormTask, contextualResponseProtocol, validateFormResponse, hasFormResponse, formProposalPolicy, stageFormProposal, nextFormProposal, formProposalReadings, bindFormProposal, decideFormProposal, commitFormProposals, settleFormProposalValidation, formProposalProtocol, validateFormProposalPolicy, validateFormProposalDescriptor, formProposalDescriptor, clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, formAcknowledges, consumeFormFeedback, formConversationOutcome, readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions, takeChoiceOffer, matchesChoice, ANSWER_WORDS, CONFIRM_WORDS, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice, withoutPromptEcho, readEmail, readPhone, readInternationalPhone, readIdentifier, last4, maskEmail, callerTextNumber, textDestination, callerIsInternational, normalizeAndFindCapture, anythingElse, goodbye, sayName, sorryNotCaught, dateToWords, amountToSpeech, validateCardNumber, validateExpiration, consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFormAction, confirmFormRevision, prepareFormAction, actionConfirmationValid, beginFormAction, finishFormAction, actionGateVerified, sourceNeedsLoad, beginSourceRefresh, completeSourceRefresh, pickProviderQuestion, matchInputs, readFormAnswer, readInputProfile, formAcceptanceTrace, resolveFormInputs, formInputApplies, formInputFilled, nextFormInput, formInputChain, openFormInstance, validateFormIncompleteOutcome, formIncompleteOutcome, validateFormExhaustion, exhaustFormInput, formInitialReadings, orderFormReadings, proposedFormValues, applyFormValidation, formReadingDependencies, exclusiveFormReadings, enrichFormMatches, expandFormActivations, settleFormActivations, rememberFormArguments, resetFormInputs, hasFormValue, formPath, formValuesEqual, formReadingReady, formReadingRelevant, formPreparation, queueFormReadings, pendingFormReadings, formWorkLimit, answerResetsFormReplays, rejectFormReadings, invalidateFormInputs, acceptFormReadings, formInstanceApplies, formParentResume, closeFormInstance, checkOtp, clearOtp, maskDestination, validateOTP, OTP_EXPIRY_MS, validateDigits, validatePhone, validateEmail, urlToSpeech, textWithUrlToSpeech };
247
253
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CACyC,iCAAiC;+BAI0E,wBAAwB;2CAH9F,0BAA0B;qCAA1B,0BAA0B;gCAA1B,0BAA0B;mCACsE,qBAAqB;kCAArB,qBAAqB;iCAArB,qBAAqB;qCAArB,qBAAqB;iCAArB,qBAAqB;mCAArB,qBAAqB;oCAArB,qBAAqB;6CAArB,qBAAqB;qCAC/E,wBAAwB;2CAAxB,wBAAwB;+CAAxB,wBAAwB;uCAAxB,wBAAwB;gCACQ,wBAAwB;4BAAxB,wBAAwB;8BAAxB,wBAAwB;iCAAxB,wBAAwB;gCAAxB,wBAAwB;oCAAxB,wBAAwB;wCAAxB,wBAAwB;gCAmB7C,YAAY;8BAAZ,YAAY;kCAAZ,YAAY;uCAAZ,YAAY;qCAAZ,YAAY;qCAAZ,YAAY;gCAlB3G,mBAAmB;8BAiBrB,qBAAqB;6BAEiH,aAAa;8BAAb,aAAa;yBAAb,aAAa;+BAAb,aAAa;8BAAb,aAAa;+BAAb,aAAa;kCAAb,aAAa;+BAAb,aAAa;+BAAb,aAAa;2BAAb,aAAa;0BACxB,cAAc;0BAAd,cAAc;uCAAd,cAAc;+BAAd,cAAc;sBAAd,cAAc;0BAAd,cAAc;iCAAd,cAAc;gCAAd,cAAc;sCAAd,cAAc;wCAC/H,cAAc;6BACP,cAAc;wBAAd,cAAc;wBAAd,cAAc;4BACjC,iBAAiB;+BACd,uBAAuB;mCACC,kBAAkB;mCAAlB,kBAAkB;qCAxB+I,mBAAmB;yCAAnB,mBAAmB;8BAAnB,mBAAmB;iCAAnB,mBAAmB;oCAAnB,mBAAmB;kCAAnB,mBAAmB;wCAAnB,mBAAmB;gCAAnB,mBAAmB;iCAAnB,mBAAmB;mCAAnB,mBAAmB;gCAe1I,mBAAmB;mCAAnB,mBAAmB;sCAAnB,mBAAmB;qCAAnB,mBAAmB;4BAUjC,mBAAmB;+BAAnB,mBAAmB;iCAAnB,mBAAmB;oCAAnB,mBAAmB;kCACkoB,iBAAiB;iCAAjB,iBAAiB;gCAAjB,iBAAiB;8BAAjB,iBAAiB;+BAAjB,iBAAiB;iCAAjB,iBAAiB;8CAAjB,iBAAiB;sCAAjB,iBAAiB;uCAAjB,iBAAiB;iCAAjB,iBAAiB;oCAAjB,iBAAiB;kCAAjB,iBAAiB;mCAAjB,iBAAiB;oCAAjB,iBAAiB;wCAAjB,iBAAiB;sCAAjB,iBAAiB;kCAAjB,iBAAiB;sCAAjB,iBAAiB;sCAAjB,iBAAiB;sCAAjB,iBAAiB;gCAAjB,iBAAiB;6BAAjB,iBAAiB;yBAAjB,iBAAiB;gCAAjB,iBAAiB;iCAAjB,iBAAiB;oCAAjB,iBAAiB;gCAAjB,iBAAiB;kCAAjB,iBAAiB;oCAAjB,iBAAiB;8BAAjB,iBAAiB;wCAAjB,iBAAiB;mCAAjB,iBAAiB;qCAAjB,iBAAiB;mCAAjB,iBAAiB;oCAAjB,iBAAiB;iCAAjB,iBAAiB;kCAAjB,iBAAiB;yBACzqB,gBAAgB;yBAAhB,gBAAgB;gCAAhB,gBAAgB;4BAAhB,gBAAgB;8BAAhB,gBAAgB;+BACnC,iBAAiB;8BAAjB,iBAAiB;8BAAjB,iBAAiB;4BAC7B,iBAAiB;oCAAjB,iBAAiB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CACyC,iCAAiC;+BAI2F,wBAAwB;2CAH/G,0BAA0B;qCAA1B,0BAA0B;gCAA1B,0BAA0B;mCACsE,qBAAqB;kCAArB,qBAAqB;iCAArB,qBAAqB;qCAArB,qBAAqB;iCAArB,qBAAqB;mCAArB,qBAAqB;oCAArB,qBAAqB;6CAArB,qBAAqB;qCAC/E,wBAAwB;2CAAxB,wBAAwB;+CAAxB,wBAAwB;uCAAxB,wBAAwB;gCACyB,wBAAwB;4BAAxB,wBAAwB;8BAAxB,wBAAwB;iCAAxB,wBAAwB;gCAAxB,wBAAwB;iCAAxB,wBAAwB;oCAAxB,wBAAwB;wCAAxB,wBAAwB;gCAmB9D,YAAY;8BAAZ,YAAY;kCAAZ,YAAY;uCAAZ,YAAY;qCAAZ,YAAY;qCAAZ,YAAY;gCAlB3G,mBAAmB;8BAiBrB,qBAAqB;6BAEoI,aAAa;8BAAb,aAAa;yBAAb,aAAa;+BAAb,aAAa;8BAAb,aAAa;+BAAb,aAAa;kCAAb,aAAa;+BAAb,aAAa;+BAAb,aAAa;2BAAb,aAAa;kCAAb,aAAa;0BAC3C,cAAc;0BAAd,cAAc;uCAAd,cAAc;+BAAd,cAAc;sBAAd,cAAc;0BAAd,cAAc;iCAAd,cAAc;gCAAd,cAAc;sCAAd,cAAc;wCAC/H,cAAc;6BACS,cAAc;wBAAd,cAAc;wBAAd,cAAc;+BAAd,cAAc;4BACjD,iBAAiB;+BACd,uBAAuB;mCACC,kBAAkB;mCAAlB,kBAAkB;qCAxB+I,mBAAmB;yCAAnB,mBAAmB;8BAAnB,mBAAmB;iCAAnB,mBAAmB;oCAAnB,mBAAmB;kCAAnB,mBAAmB;wCAAnB,mBAAmB;gCAAnB,mBAAmB;iCAAnB,mBAAmB;mCAAnB,mBAAmB;gCAe1I,mBAAmB;mCAAnB,mBAAmB;sCAAnB,mBAAmB;qCAAnB,mBAAmB;4BAUjC,mBAAmB;+BAAnB,mBAAmB;iCAAnB,mBAAmB;oCAAnB,mBAAmB;kCACkoB,iBAAiB;iCAAjB,iBAAiB;gCAAjB,iBAAiB;8BAAjB,iBAAiB;+BAAjB,iBAAiB;iCAAjB,iBAAiB;8CAAjB,iBAAiB;sCAAjB,iBAAiB;uCAAjB,iBAAiB;iCAAjB,iBAAiB;oCAAjB,iBAAiB;kCAAjB,iBAAiB;mCAAjB,iBAAiB;oCAAjB,iBAAiB;wCAAjB,iBAAiB;sCAAjB,iBAAiB;kCAAjB,iBAAiB;sCAAjB,iBAAiB;sCAAjB,iBAAiB;sCAAjB,iBAAiB;gCAAjB,iBAAiB;6BAAjB,iBAAiB;yBAAjB,iBAAiB;gCAAjB,iBAAiB;iCAAjB,iBAAiB;oCAAjB,iBAAiB;gCAAjB,iBAAiB;kCAAjB,iBAAiB;oCAAjB,iBAAiB;8BAAjB,iBAAiB;wCAAjB,iBAAiB;mCAAjB,iBAAiB;qCAAjB,iBAAiB;mCAAjB,iBAAiB;oCAAjB,iBAAiB;iCAAjB,iBAAiB;kCAAjB,iBAAiB;yBACzqB,gBAAgB;yBAAhB,gBAAgB;gCAAhB,gBAAgB;4BAAhB,gBAAgB;8BAAhB,gBAAgB;+BACnC,iBAAiB;8BAAjB,iBAAiB;8BAAjB,iBAAiB;4BAC7B,iBAAiB;oCAAjB,iBAAiB"}
@@ -3,7 +3,7 @@ import { continuationSafetyProtocol } from '../forms/continuation-safety.js';
3
3
  import { contextualResponseProtocol, validateFormResponse, hasFormResponse } from './contextual-response.js';
4
4
  import { formProposalPolicy, stageFormProposal, nextFormProposal, formProposalReadings, bindFormProposal, decideFormProposal, commitFormProposals, settleFormProposalValidation } from './form-proposals.js';
5
5
  import { formProposalProtocol, validateFormProposalPolicy, validateFormProposalDescriptor, formProposalDescriptor } from './proposal-contract.js';
6
- import { cancelFormTask, clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, consumeFormFeedback, formConversationOutcome } from './form-conversation.js';
6
+ import { cancelFormTask, clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, formAcknowledges, consumeFormFeedback, formConversationOutcome } from './form-conversation.js';
7
7
  import { takeChoiceOffer } from './choice-offer.js';
8
8
  import { consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFormAction, confirmFormRevision, prepareFormAction, actionConfirmationValid, beginFormAction, finishFormAction, actionGateVerified } from './form-actions.js';
9
9
  /**
@@ -23,10 +23,10 @@ import { consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFo
23
23
  import { sourceNeedsLoad, beginSourceRefresh, completeSourceRefresh, pickProviderQuestion } from './form-sources.js';
24
24
  import { matchesChoice } from './matches-choice.js';
25
25
  import { readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions } from './money.js';
26
- import { ANSWER_WORDS, CONFIRM_WORDS, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice } from './answer.js';
26
+ import { ANSWER_WORDS, CONFIRM_WORDS, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice, withoutPromptEcho } from './answer.js';
27
27
  import { readEmail, readPhone, readInternationalPhone, readIdentifier, last4, maskEmail, callerTextNumber, textDestination, callerIsInternational } from './contact.js';
28
28
  import { normalizeAndFindCapture } from './capture.js';
29
- import { anythingElse, goodbye, sayName } from './phrases.js';
29
+ import { anythingElse, goodbye, sayName, sorryNotCaught } from './phrases.js';
30
30
  import { dateToWords } from './date-words.js';
31
31
  import { amountToSpeech } from './amount-to-speech.js';
32
32
  import { validateCardNumber, validateExpiration } from './card-checks.js';
@@ -35,14 +35,14 @@ import { resolveFormInputs, formInputApplies, formInputFilled, nextFormInput, fo
35
35
  import { checkOtp, clearOtp, maskDestination, validateOTP, OTP_EXPIRY_MS } from './otp-check.js';
36
36
  import { validateDigits, validatePhone, validateEmail } from './validators.js';
37
37
  import { urlToSpeech, textWithUrlToSpeech } from './url-speech.js';
38
- export { continuationSafetyProtocol, cancelFormTask, contextualResponseProtocol, validateFormResponse, hasFormResponse, formProposalPolicy, stageFormProposal, nextFormProposal, formProposalReadings, bindFormProposal, decideFormProposal, commitFormProposals, settleFormProposalValidation, formProposalProtocol, validateFormProposalPolicy, validateFormProposalDescriptor, formProposalDescriptor, clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, consumeFormFeedback, formConversationOutcome, readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions, takeChoiceOffer, matchesChoice, ANSWER_WORDS, CONFIRM_WORDS, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice, readEmail, readPhone, readInternationalPhone, readIdentifier, last4, maskEmail, callerTextNumber, textDestination, callerIsInternational, normalizeAndFindCapture, anythingElse, goodbye, sayName, dateToWords, amountToSpeech, validateCardNumber, validateExpiration, consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFormAction, confirmFormRevision, prepareFormAction, actionConfirmationValid, beginFormAction, finishFormAction, actionGateVerified, sourceNeedsLoad, beginSourceRefresh, completeSourceRefresh, pickProviderQuestion, matchInputs, readFormAnswer, readInputProfile, formAcceptanceTrace, resolveFormInputs, formInputApplies, formInputFilled, nextFormInput, formInputChain, openFormInstance, validateFormIncompleteOutcome, formIncompleteOutcome, validateFormExhaustion, exhaustFormInput, formInitialReadings, orderFormReadings, proposedFormValues, applyFormValidation, formReadingDependencies, exclusiveFormReadings, enrichFormMatches, expandFormActivations, settleFormActivations, rememberFormArguments, resetFormInputs, hasFormValue, formPath, formValuesEqual, formReadingReady, formReadingRelevant, formPreparation, queueFormReadings, pendingFormReadings, formWorkLimit, answerResetsFormReplays, rejectFormReadings, invalidateFormInputs, acceptFormReadings, formInstanceApplies, formParentResume, closeFormInstance, checkOtp, clearOtp, maskDestination, validateOTP, OTP_EXPIRY_MS, validateDigits, validatePhone, validateEmail, urlToSpeech, textWithUrlToSpeech, };
38
+ export { continuationSafetyProtocol, cancelFormTask, contextualResponseProtocol, validateFormResponse, hasFormResponse, formProposalPolicy, stageFormProposal, nextFormProposal, formProposalReadings, bindFormProposal, decideFormProposal, commitFormProposals, settleFormProposalValidation, formProposalProtocol, validateFormProposalPolicy, validateFormProposalDescriptor, formProposalDescriptor, clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, formAcknowledges, consumeFormFeedback, formConversationOutcome, readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions, takeChoiceOffer, matchesChoice, ANSWER_WORDS, CONFIRM_WORDS, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice, withoutPromptEcho, readEmail, readPhone, readInternationalPhone, readIdentifier, last4, maskEmail, callerTextNumber, textDestination, callerIsInternational, normalizeAndFindCapture, anythingElse, goodbye, sayName, sorryNotCaught, dateToWords, amountToSpeech, validateCardNumber, validateExpiration, consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFormAction, confirmFormRevision, prepareFormAction, actionConfirmationValid, beginFormAction, finishFormAction, actionGateVerified, sourceNeedsLoad, beginSourceRefresh, completeSourceRefresh, pickProviderQuestion, matchInputs, readFormAnswer, readInputProfile, formAcceptanceTrace, resolveFormInputs, formInputApplies, formInputFilled, nextFormInput, formInputChain, openFormInstance, validateFormIncompleteOutcome, formIncompleteOutcome, validateFormExhaustion, exhaustFormInput, formInitialReadings, orderFormReadings, proposedFormValues, applyFormValidation, formReadingDependencies, exclusiveFormReadings, enrichFormMatches, expandFormActivations, settleFormActivations, rememberFormArguments, resetFormInputs, hasFormValue, formPath, formValuesEqual, formReadingReady, formReadingRelevant, formPreparation, queueFormReadings, pendingFormReadings, formWorkLimit, answerResetsFormReplays, rejectFormReadings, invalidateFormInputs, acceptFormReadings, formInstanceApplies, formParentResume, closeFormInstance, checkOtp, clearOtp, maskDestination, validateOTP, OTP_EXPIRY_MS, validateDigits, validatePhone, validateEmail, urlToSpeech, textWithUrlToSpeech, };
39
39
  /** The functions flows call by name, ready to spread into a host's approved functions. */
40
40
  export const STANDARD_FUNCTIONS = {
41
41
  continuationSafetyProtocol, cancelFormTask, contextualResponseProtocol, validateFormResponse, hasFormResponse,
42
42
  formProposalPolicy, stageFormProposal, nextFormProposal, formProposalReadings, bindFormProposal, decideFormProposal, commitFormProposals, settleFormProposalValidation, formProposalProtocol, validateFormProposalPolicy, validateFormProposalDescriptor, formProposalDescriptor,
43
- clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, consumeFormFeedback, formConversationOutcome,
44
- readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions, takeChoiceOffer, matchesChoice, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice,
43
+ clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, formAcknowledges, consumeFormFeedback, formConversationOutcome,
44
+ readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions, takeChoiceOffer, matchesChoice, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice, withoutPromptEcho,
45
45
  readEmail, readPhone, readInternationalPhone, readIdentifier, last4, maskEmail, callerTextNumber, textDestination, callerIsInternational,
46
- normalizeAndFindCapture, anythingElse, goodbye, sayName, dateToWords, amountToSpeech, validateCardNumber, validateExpiration, consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFormAction, confirmFormRevision, prepareFormAction, actionConfirmationValid, beginFormAction, finishFormAction, actionGateVerified, sourceNeedsLoad, beginSourceRefresh, completeSourceRefresh, pickProviderQuestion, matchInputs, readFormAnswer, readInputProfile, formAcceptanceTrace, resolveFormInputs, formInputApplies, formInputFilled, nextFormInput, formInputChain, openFormInstance, validateFormIncompleteOutcome, formIncompleteOutcome, validateFormExhaustion, exhaustFormInput, formInitialReadings, orderFormReadings, proposedFormValues, applyFormValidation, formReadingDependencies, exclusiveFormReadings, enrichFormMatches, expandFormActivations, settleFormActivations, rememberFormArguments, resetFormInputs, hasFormValue, formPath, formValuesEqual, formReadingReady, formReadingRelevant, formPreparation, queueFormReadings, pendingFormReadings, formWorkLimit, answerResetsFormReplays, rejectFormReadings, invalidateFormInputs, acceptFormReadings, formInstanceApplies, formParentResume, closeFormInstance,
46
+ normalizeAndFindCapture, anythingElse, goodbye, sayName, sorryNotCaught, dateToWords, amountToSpeech, validateCardNumber, validateExpiration, consumeActionReceipt, authorizeFormActionRetry, formSignature, selectFormAction, confirmFormRevision, prepareFormAction, actionConfirmationValid, beginFormAction, finishFormAction, actionGateVerified, sourceNeedsLoad, beginSourceRefresh, completeSourceRefresh, pickProviderQuestion, matchInputs, readFormAnswer, readInputProfile, formAcceptanceTrace, resolveFormInputs, formInputApplies, formInputFilled, nextFormInput, formInputChain, openFormInstance, validateFormIncompleteOutcome, formIncompleteOutcome, validateFormExhaustion, exhaustFormInput, formInitialReadings, orderFormReadings, proposedFormValues, applyFormValidation, formReadingDependencies, exclusiveFormReadings, enrichFormMatches, expandFormActivations, settleFormActivations, rememberFormArguments, resetFormInputs, hasFormValue, formPath, formValuesEqual, formReadingReady, formReadingRelevant, formPreparation, queueFormReadings, pendingFormReadings, formWorkLimit, answerResetsFormReplays, rejectFormReadings, invalidateFormInputs, acceptFormReadings, formInstanceApplies, formParentResume, closeFormInstance,
47
47
  validateOTP, validateDigits, validatePhone, validateEmail, urlToSpeech, textWithUrlToSpeech,
48
48
  };
@@ -5,6 +5,12 @@
5
5
  */
6
6
  /** A name as said to the customer: trimmed; an all-capitals name (as account systems store it) in title case. */
7
7
  export function sayName(name: any): string;
8
+ /**
9
+ * The acknowledgement before a question asked again ("Sorry, I didn't catch that. "), with a trailing space. It names the
10
+ * customer only when the flows opt in with cargo.sorryByName (jsfe 1.20.0; owner 2026-10-31) and cargo.displayName is
11
+ * known; otherwise it is the wording every earlier version said.
12
+ */
13
+ export function sorryNotCaught(lang: any, cargo: any): string;
8
14
  /** The closing question after a task is done, in the turn's language ('en' when there is none), with the name if known. */
9
15
  export function anythingElse(lang: any, name: any): any;
10
16
  /** The parting wish when a conversation ends, in the turn's language, with the name if known. */
@@ -1 +1 @@
1
- {"version":3,"file":"phrases.d.ts","sourceRoot":"","sources":["../../src/helpers/phrases.js"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iHAAiH;AACjH,2CAOC;AAWD,2HAA2H;AAC3H,wDAEC;AAED,iGAAiG;AACjG,mDAEC"}
1
+ {"version":3,"file":"phrases.d.ts","sourceRoot":"","sources":["../../src/helpers/phrases.js"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iHAAiH;AACjH,2CAOC;AAED;;;;GAIG;AACH,8DAOC;AAWD,2HAA2H;AAC3H,wDAEC;AAED,iGAAiG;AACjG,mDAEC"}
@@ -13,6 +13,20 @@ export function sayName(name) {
13
13
  return n;
14
14
  }
15
15
  }
16
+ /**
17
+ * The acknowledgement before a question asked again ("Sorry, I didn't catch that. "), with a trailing space. It names the
18
+ * customer only when the flows opt in with cargo.sorryByName (jsfe 1.20.0; owner 2026-10-31) and cargo.displayName is
19
+ * known; otherwise it is the wording every earlier version said.
20
+ */
21
+ export function sorryNotCaught(lang, cargo) {
22
+ const n = cargo && cargo.sorryByName === true ? sayName(cargo.displayName) : '';
23
+ if (lang === 'es') {
24
+ return n ? `Disculpe, ${n}, no le entendí. ` : 'Disculpe, no le entendí. ';
25
+ }
26
+ else {
27
+ return n ? `Sorry, ${n}, I didn't catch that. ` : "Sorry, I didn't catch that. ";
28
+ }
29
+ }
16
30
  const ANYTHING_ELSE = {
17
31
  en: (n) => (n ? `Is there anything else I can help you with, ${n}?` : 'Is there anything else I can help you with?'),
18
32
  es: (n) => (n ? `¿Hay algo más en lo que pueda ayudarle, ${n}?` : '¿Hay algo más en lo que pueda ayudarle?'),
@@ -1 +1 @@
1
- export const JSFE_RUNTIME_FINGERPRINT = "sha256:f99ae1f2c338d0ef94a77bb5c074d8d015d853556943e2c26a3ecb6af5cc65df";
1
+ export const JSFE_RUNTIME_FINGERPRINT = "sha256:95579ac2171e7f268caf73ed69d304c734a772103b502bdd524bd65315d408c3";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsfe",
3
- "version": "1.19.1",
3
+ "version": "1.21.0",
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",