jsfe 1.19.1 → 1.20.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,17 @@ 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
+ **The re-ask names the customer, opt-in (jsfe 1.20.0):** `sorryNotCaught(lang, cargo)` is the acknowledgement before a
402
+ question asked again ("Sorry, I didn't catch that. " / "Disculpe, no le entendí. "), used by `formInputPrompt`, `ask-choice`
403
+ and the provider menu. A flow set that sets `cargo.sorryByName = true` (for example once the caller is verified) gets it with
404
+ `cargo.displayName` ("Disculpe, Ana, no le entendí. "); without it the wording is unchanged.
405
+
406
+ **Acknowledging only data, opt-in (jsfe 1.20.0):** a form declaring `acknowledge: 'data'` (or the nearest enclosing form
407
+ that declares it) says "Got it, your …" / "Okay, I noted your …" only for a value the caller supplied, an input whose profile
408
+ kind is digits, email, phone, amount, identifier, account or text. A pick among offered words (`choice`, `pattern`), such as
409
+ NEW CARD, is not acknowledged: the next question already shows it was understood. Rejections are always said. Without the
410
+ attribute every input is acknowledged as before (`formAcknowledges(cargo, reading)`).
411
+
401
412
  **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
413
  one to three digits as a pause inside one number, because speech-to-text writes spoken groups that way ("926, 1 0." is
403
414
  the ZIP 92610, "7, 9, 984. 5." the code 799845). A comma after a longer number still separates two numbers ("92610,
@@ -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",
@@ -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
@@ -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 };
@@ -53,6 +54,7 @@ export namespace STANDARD_FUNCTIONS {
53
54
  export { anythingElse };
54
55
  export { goodbye };
55
56
  export { sayName };
57
+ export { sorryNotCaught };
56
58
  export { dateToWords };
57
59
  export { amountToSpeech };
58
60
  export { validateCardNumber };
@@ -141,6 +143,7 @@ import { formNoOwner } from './form-conversation.js';
141
143
  import { missFormInput } from './form-conversation.js';
142
144
  import { formMustComplete } from './form-conversation.js';
143
145
  import { formInputPrompt } from './form-conversation.js';
146
+ import { formAcknowledges } from './form-conversation.js';
144
147
  import { consumeFormFeedback } from './form-conversation.js';
145
148
  import { formConversationOutcome } from './form-conversation.js';
146
149
  import { readMoneyAmount } from './money.js';
@@ -174,6 +177,7 @@ import { normalizeAndFindCapture } from './capture.js';
174
177
  import { anythingElse } from './phrases.js';
175
178
  import { goodbye } from './phrases.js';
176
179
  import { sayName } from './phrases.js';
180
+ import { sorryNotCaught } from './phrases.js';
177
181
  import { dateToWords } from './date-words.js';
178
182
  import { amountToSpeech } from './amount-to-speech.js';
179
183
  import { validateCardNumber } from './card-checks.js';
@@ -243,5 +247,5 @@ import { validatePhone } from './validators.js';
243
247
  import { validateEmail } from './validators.js';
244
248
  import { urlToSpeech } from './url-speech.js';
245
249
  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 };
250
+ 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, 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
251
  //# 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;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;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
  /**
@@ -26,7 +26,7 @@ import { readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStateme
26
26
  import { ANSWER_WORDS, CONFIRM_WORDS, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice } 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, 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,
43
+ clearFormMisses, formNoOwner, missFormInput, formMustComplete, formInputPrompt, formAcknowledges, consumeFormFeedback, formConversationOutcome,
44
44
  readMoneyAmount, isMoneyAmount, moneyIntentAllows, isPastPaymentStatement, isPartialMoneyAnswer, validateMoneyOptions, takeChoiceOffer, matchesChoice, isAnswer, isAgentRequest, isExitRequest, isOtherRequest, isSpelledFragment, isAmountAnswer, amountInAnswer, pickChoice,
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:69084162d369591c450f501f25553af1ce23c48c59a83f94aed895c2cb521f89";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsfe",
3
- "version": "1.19.1",
3
+ "version": "1.20.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",