@onereach/step-voice 7.0.26-agenttimeout.6 → 7.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,34 +1,8 @@
1
1
  import VoiceStep from './voice';
2
- type PreToolSpeechMode = 'auto' | 'static' | 'off';
3
- type ToolCallSound = 'typing' | 'none';
4
- type ToolCallSoundBehavior = 'always' | 'with_pre_speech';
5
- type SoftTimeoutMode = 'static' | 'auto';
6
- interface ToolCallFeedbackConfig {
7
- enabled: boolean;
8
- pre_tool_speech: PreToolSpeechMode;
9
- pre_tool_speech_phrases: string[];
10
- tool_call_sound: ToolCallSound;
11
- tool_call_sound_behavior: ToolCallSoundBehavior;
12
- delay_seconds: number;
13
- }
14
- interface PerToolConfig {
15
- enabled?: boolean | null;
16
- pre_tool_speech?: PreToolSpeechMode | null;
17
- pre_tool_speech_phrases?: string[] | null;
18
- tool_call_sound?: ToolCallSound | null;
19
- tool_call_sound_behavior?: ToolCallSoundBehavior | null;
20
- delay_seconds?: number | null;
21
- }
22
- interface SoftTimeoutConfig {
23
- timeout_seconds: number;
24
- phrases: string[];
25
- mode: SoftTimeoutMode;
26
- }
27
2
  interface Handler {
28
3
  name: string;
29
4
  description: string;
30
5
  parameters: string;
31
- feedback?: PerToolConfig;
32
6
  }
33
7
  interface AgentServiceConfig {
34
8
  provider: string;
@@ -49,6 +23,10 @@ interface INPUT {
49
23
  prompt?: string;
50
24
  }>;
51
25
  idle_goodbye_message: string;
26
+ dtmf_enabled: boolean;
27
+ dtmf_timeout: number | string;
28
+ dtmf_termination_digit: string;
29
+ dtmf_prefix: string;
52
30
  custom_config_enabled: boolean;
53
31
  agent_url_overwritten: boolean;
54
32
  agent_url: string;
@@ -57,19 +35,14 @@ interface INPUT {
57
35
  llm: Partial<AgentServiceConfig>;
58
36
  tts: Partial<AgentServiceConfig>;
59
37
  realtime: Partial<AgentServiceConfig>;
60
- tool_feedback?: ToolCallFeedbackConfig;
61
- soft_timeout?: SoftTimeoutConfig;
62
38
  }
63
39
  export default class VoiceAgent extends VoiceStep<Partial<INPUT>> {
64
40
  runStep(): Promise<void>;
65
41
  private normalizeIdlePrompts;
66
42
  private findExitByLabel;
67
- private validateToolFeedback;
68
43
  private isStepFlagEnabled;
69
44
  private isValidAgentUrl;
70
45
  private buildAgentServiceConfig;
71
- private validatePerToolFeedback;
72
- private validateSoftTimeout;
73
46
  private parseAgentServiceOptions;
74
47
  exitToThread(): Promise<void>;
75
48
  }
@@ -17,15 +17,7 @@ class VoiceAgent extends voice_1.default {
17
17
  const functionId = event.params.functionId ?? '';
18
18
  const exitId = this.findExitByLabel(name) ?? this.getExitStepId('function_call');
19
19
  if (exitId) {
20
- this.exitStep(exitId, {
21
- [name]: params,
22
- name,
23
- functionId,
24
- __voicecb: cb,
25
- callId: call.id,
26
- callType: call.type,
27
- callCallback: call.callback
28
- }, true);
20
+ this.exitStep(exitId, { [name]: params, name, functionId, __voicecb: cb, callId: call.id, callType: call.type, callCallback: call.callback }, true);
29
21
  }
30
22
  else {
31
23
  this.log.warn('no exit for function_call', { name });
@@ -42,7 +34,7 @@ class VoiceAgent extends voice_1.default {
42
34
  }
43
35
  });
44
36
  this.triggers.otherwise(async () => {
45
- const { handlers = [], system_instruction = '', developer_messages = [], greeting_message = '', prevent_greeting_interruption = false, idle_detection_enabled = false, idle_timeout_secs = 8, idle_max_retries = 3, idle_prompts = [], idle_goodbye_message = '', custom_config_enabled = false, agent_url_overwritten = false, tool_feedback, soft_timeout, agent_url = '', mode = '', stt = {}, llm = {}, tts = {}, realtime = {} } = this.data;
37
+ const { handlers = [], system_instruction = '', developer_messages = [], greeting_message = '', prevent_greeting_interruption = false, idle_detection_enabled = false, idle_timeout_secs = 8, idle_max_retries = 3, idle_prompts = [], idle_goodbye_message = '', dtmf_enabled = false, dtmf_timeout = 2, dtmf_termination_digit = '#', dtmf_prefix = 'DTMF: ', custom_config_enabled = false, agent_url_overwritten = false, agent_url = '', mode = '', stt = {}, llm = {}, tts = {}, realtime = {} } = this.data;
46
38
  if (lodash_1.default.isEmpty(system_instruction)) {
47
39
  this.throwError(new Error('Voice Agent: system instruction is required'));
48
40
  }
@@ -56,19 +48,7 @@ class VoiceAgent extends voice_1.default {
56
48
  parameters = {};
57
49
  }
58
50
  }
59
- const tool = {
60
- type: 'function',
61
- name: h.name,
62
- description: h.description,
63
- parameters: parameters || {}
64
- };
65
- if (h.feedback != null) {
66
- const validatedFeedback = this.validatePerToolFeedback(h.feedback, h.name);
67
- if (validatedFeedback) {
68
- tool.feedback = validatedFeedback;
69
- }
70
- }
71
- return tool;
51
+ return { type: 'function', name: h.name, description: h.description, parameters: parameters || {} };
72
52
  });
73
53
  const config = {
74
54
  system_instruction,
@@ -89,6 +69,17 @@ class VoiceAgent extends voice_1.default {
89
69
  goodbye_message: lodash_1.default.isEmpty(lodash_1.default.trim(idle_goodbye_message)) ? undefined : idle_goodbye_message
90
70
  };
91
71
  }
72
+ if (this.isStepFlagEnabled(dtmf_enabled)) {
73
+ const timeout = Number(dtmf_timeout);
74
+ const terminationDigit = String(dtmf_termination_digit || '#');
75
+ const prefix = dtmf_prefix == null || dtmf_prefix === '' ? 'DTMF: ' : String(dtmf_prefix);
76
+ config.dtmf = {
77
+ enabled: true,
78
+ timeout: Number.isFinite(timeout) ? timeout : 2,
79
+ termination_digit: terminationDigit,
80
+ prefix
81
+ };
82
+ }
92
83
  let agentCustomUrl = '';
93
84
  if (this.isStepFlagEnabled(agent_url_overwritten)) {
94
85
  if (!this.isValidAgentUrl(agent_url)) {
@@ -111,18 +102,6 @@ class VoiceAgent extends voice_1.default {
111
102
  this.throwError(new Error(`Voice Agent: unknown mode "${mode}"`));
112
103
  }
113
104
  }
114
- if (this.isStepFlagEnabled(tool_feedback?.enabled) && tools.length > 0) {
115
- const validatedFeedback = this.validateToolFeedback(tool_feedback);
116
- if (validatedFeedback) {
117
- config.tool_feedback = validatedFeedback;
118
- }
119
- }
120
- if (soft_timeout != null) {
121
- const validatedSoftTimeout = this.validateSoftTimeout(soft_timeout);
122
- if (validatedSoftTimeout) {
123
- config.soft_timeout = validatedSoftTimeout;
124
- }
125
- }
126
105
  const params = { config };
127
106
  if (agentCustomUrl) {
128
107
  params.url = agentCustomUrl;
@@ -140,57 +119,6 @@ class VoiceAgent extends voice_1.default {
140
119
  const exit = lodash_1.default.find(this.step.exits, (e) => e.label === label);
141
120
  return exit?.id;
142
121
  }
143
- validateToolFeedback(config) {
144
- if (config == null || typeof config !== 'object')
145
- return null;
146
- const cfg = config;
147
- // If enabled is not boolean true, silently return undefined (disabled case)
148
- if (typeof cfg.enabled !== 'boolean' || cfg.enabled !== true)
149
- return null;
150
- // Validate pre_tool_speech
151
- const validPreToolSpeech = ['auto', 'static', 'off'];
152
- if (!validPreToolSpeech.includes(cfg.pre_tool_speech)) {
153
- this.log.warn('Voice Agent: invalid tool_feedback.pre_tool_speech — feedback config excluded');
154
- return null;
155
- }
156
- // Validate tool_call_sound
157
- const validToolCallSound = ['typing', 'none'];
158
- if (!validToolCallSound.includes(cfg.tool_call_sound)) {
159
- this.log.warn('Voice Agent: invalid tool_feedback.tool_call_sound — feedback config excluded');
160
- return null;
161
- }
162
- // Validate tool_call_sound_behavior
163
- const validToolCallSoundBehavior = ['always', 'with_pre_speech'];
164
- if (!validToolCallSoundBehavior.includes(cfg.tool_call_sound_behavior)) {
165
- this.log.warn('Voice Agent: invalid tool_feedback.tool_call_sound_behavior — feedback config excluded');
166
- return null;
167
- }
168
- // Validate delay_seconds
169
- const delay = Number(cfg.delay_seconds);
170
- if (delay <= 0 || delay > 30) {
171
- this.log.warn('Voice Agent: invalid tool_feedback.delay_seconds — feedback config excluded');
172
- return null;
173
- }
174
- // Validate pre_tool_speech_phrases (only required when mode is 'static')
175
- const phrases = cfg.pre_tool_speech_phrases;
176
- if (cfg.pre_tool_speech === 'static') {
177
- if (!Array.isArray(phrases) ||
178
- phrases.length < 1 ||
179
- phrases.length > 20 ||
180
- !phrases.every((p) => typeof p === 'string' && p.trim().length > 0)) {
181
- this.log.warn('Voice Agent: invalid tool_feedback.pre_tool_speech_phrases — feedback config excluded');
182
- return null;
183
- }
184
- }
185
- return {
186
- enabled: true,
187
- pre_tool_speech: cfg.pre_tool_speech,
188
- pre_tool_speech_phrases: (Array.isArray(phrases) ? phrases : []),
189
- tool_call_sound: cfg.tool_call_sound,
190
- tool_call_sound_behavior: cfg.tool_call_sound_behavior,
191
- delay_seconds: delay
192
- };
193
- }
194
122
  isStepFlagEnabled(value) {
195
123
  return value === true || value === 'true';
196
124
  }
@@ -210,75 +138,6 @@ class VoiceAgent extends voice_1.default {
210
138
  options: this.parseAgentServiceOptions(label, service.options)
211
139
  };
212
140
  }
213
- validatePerToolFeedback(config, toolName) {
214
- if (config == null || typeof config !== 'object' || Array.isArray(config)) {
215
- return null;
216
- }
217
- const raw = config;
218
- const result = {};
219
- if ('delay_seconds' in raw && raw.delay_seconds != null) {
220
- const delay = Number(raw.delay_seconds);
221
- if (delay <= 0 || delay > 30) {
222
- this.log.warn(`Voice Agent: invalid feedback.delay_seconds for tool "${toolName}" — per-tool feedback excluded`);
223
- return null;
224
- }
225
- result.delay_seconds = delay;
226
- }
227
- if ('pre_tool_speech' in raw && raw.pre_tool_speech != null) {
228
- const valid = ['auto', 'static', 'off'];
229
- if (!valid.includes(raw.pre_tool_speech)) {
230
- this.log.warn(`Voice Agent: invalid feedback.pre_tool_speech for tool "${toolName}" — per-tool feedback excluded`);
231
- return null;
232
- }
233
- result.pre_tool_speech = raw.pre_tool_speech;
234
- }
235
- if ('tool_call_sound' in raw && raw.tool_call_sound != null) {
236
- const valid = ['typing', 'none'];
237
- if (!valid.includes(raw.tool_call_sound)) {
238
- this.log.warn(`Voice Agent: invalid feedback.tool_call_sound for tool "${toolName}" — per-tool feedback excluded`);
239
- return null;
240
- }
241
- result.tool_call_sound = raw.tool_call_sound;
242
- }
243
- if ('tool_call_sound_behavior' in raw && raw.tool_call_sound_behavior != null) {
244
- const valid = ['always', 'with_pre_speech'];
245
- if (!valid.includes(raw.tool_call_sound_behavior)) {
246
- this.log.warn(`Voice Agent: invalid feedback.tool_call_sound_behavior for tool "${toolName}" — per-tool feedback excluded`);
247
- return null;
248
- }
249
- result.tool_call_sound_behavior = raw.tool_call_sound_behavior;
250
- }
251
- return result;
252
- }
253
- validateSoftTimeout(config) {
254
- if (config == null || typeof config !== 'object' || Array.isArray(config))
255
- return null;
256
- const cfg = config;
257
- const timeoutSeconds = Number(cfg.timeout_seconds);
258
- if (timeoutSeconds <= 0 || timeoutSeconds > 30) {
259
- this.log.warn('Voice Agent: invalid soft_timeout.timeout_seconds — soft timeout config excluded');
260
- return null;
261
- }
262
- const validModes = ['static', 'auto'];
263
- if (!validModes.includes(cfg.mode)) {
264
- this.log.warn('Voice Agent: invalid soft_timeout.mode — soft timeout config excluded');
265
- return null;
266
- }
267
- // Validate phrases
268
- const phrases = cfg.phrases;
269
- if (!Array.isArray(phrases) ||
270
- phrases.length < 1 ||
271
- phrases.length > 20 ||
272
- !phrases.every((p) => typeof p === 'string' && p.trim().length > 0)) {
273
- this.log.warn('Voice Agent: invalid soft_timeout.phrases — soft timeout config excluded');
274
- return null;
275
- }
276
- return {
277
- timeout_seconds: timeoutSeconds,
278
- phrases: phrases,
279
- mode: cfg.mode
280
- };
281
- }
282
141
  parseAgentServiceOptions(label, options) {
283
142
  if (options == null || options === '')
284
143
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onereach/step-voice",
3
- "version": "7.0.26-agenttimeout.6",
3
+ "version": "7.0.26",
4
4
  "author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
5
5
  "contributors": [
6
6
  "Roman Zolotarov",