@onereach/step-voice 7.0.26-agentstepuiimprovements.0 → 7.0.26-agenttimeout.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/dst/Voice Agent.d.ts +31 -0
- package/dst/Voice Agent.js +153 -3
- package/package.json +1 -1
package/dst/Voice Agent.d.ts
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
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
|
+
}
|
|
2
27
|
interface Handler {
|
|
3
28
|
name: string;
|
|
4
29
|
description: string;
|
|
5
30
|
parameters: string;
|
|
31
|
+
feedback?: PerToolConfig;
|
|
6
32
|
}
|
|
7
33
|
interface AgentServiceConfig {
|
|
8
34
|
provider: string;
|
|
@@ -31,14 +57,19 @@ interface INPUT {
|
|
|
31
57
|
llm: Partial<AgentServiceConfig>;
|
|
32
58
|
tts: Partial<AgentServiceConfig>;
|
|
33
59
|
realtime: Partial<AgentServiceConfig>;
|
|
60
|
+
tool_feedback?: ToolCallFeedbackConfig;
|
|
61
|
+
soft_timeout?: SoftTimeoutConfig;
|
|
34
62
|
}
|
|
35
63
|
export default class VoiceAgent extends VoiceStep<Partial<INPUT>> {
|
|
36
64
|
runStep(): Promise<void>;
|
|
37
65
|
private normalizeIdlePrompts;
|
|
38
66
|
private findExitByLabel;
|
|
67
|
+
private validateToolFeedback;
|
|
39
68
|
private isStepFlagEnabled;
|
|
40
69
|
private isValidAgentUrl;
|
|
41
70
|
private buildAgentServiceConfig;
|
|
71
|
+
private validatePerToolFeedback;
|
|
72
|
+
private validateSoftTimeout;
|
|
42
73
|
private parseAgentServiceOptions;
|
|
43
74
|
exitToThread(): Promise<void>;
|
|
44
75
|
}
|
package/dst/Voice Agent.js
CHANGED
|
@@ -17,7 +17,15 @@ 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, {
|
|
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);
|
|
21
29
|
}
|
|
22
30
|
else {
|
|
23
31
|
this.log.warn('no exit for function_call', { name });
|
|
@@ -34,7 +42,7 @@ class VoiceAgent extends voice_1.default {
|
|
|
34
42
|
}
|
|
35
43
|
});
|
|
36
44
|
this.triggers.otherwise(async () => {
|
|
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 = '', custom_config_enabled = false, agent_url_overwritten = false, agent_url = '', mode = '', stt = {}, llm = {}, tts = {}, realtime = {} } = this.data;
|
|
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;
|
|
38
46
|
if (lodash_1.default.isEmpty(system_instruction)) {
|
|
39
47
|
this.throwError(new Error('Voice Agent: system instruction is required'));
|
|
40
48
|
}
|
|
@@ -48,7 +56,19 @@ class VoiceAgent extends voice_1.default {
|
|
|
48
56
|
parameters = {};
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
|
-
|
|
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;
|
|
52
72
|
});
|
|
53
73
|
const config = {
|
|
54
74
|
system_instruction,
|
|
@@ -91,6 +111,18 @@ class VoiceAgent extends voice_1.default {
|
|
|
91
111
|
this.throwError(new Error(`Voice Agent: unknown mode "${mode}"`));
|
|
92
112
|
}
|
|
93
113
|
}
|
|
114
|
+
if (this.isStepFlagEnabled(tool_feedback?.enabled)) {
|
|
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
|
+
}
|
|
94
126
|
const params = { config };
|
|
95
127
|
if (agentCustomUrl) {
|
|
96
128
|
params.url = agentCustomUrl;
|
|
@@ -108,6 +140,55 @@ class VoiceAgent extends voice_1.default {
|
|
|
108
140
|
const exit = lodash_1.default.find(this.step.exits, (e) => e.label === label);
|
|
109
141
|
return exit?.id;
|
|
110
142
|
}
|
|
143
|
+
validateToolFeedback(config) {
|
|
144
|
+
if (config == null || typeof config !== 'object')
|
|
145
|
+
return undefined;
|
|
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 undefined;
|
|
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 undefined;
|
|
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 undefined;
|
|
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 undefined;
|
|
167
|
+
}
|
|
168
|
+
// Validate delay_seconds
|
|
169
|
+
const delay = cfg.delay_seconds;
|
|
170
|
+
if (typeof delay !== 'number' || !Number.isFinite(delay) || delay <= 0 || delay > 30) {
|
|
171
|
+
this.log.warn('Voice Agent: invalid tool_feedback.delay_seconds — feedback config excluded');
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
// Validate pre_tool_speech_phrases
|
|
175
|
+
const phrases = cfg.pre_tool_speech_phrases;
|
|
176
|
+
if (!Array.isArray(phrases) ||
|
|
177
|
+
phrases.length < 1 ||
|
|
178
|
+
phrases.length > 20 ||
|
|
179
|
+
!phrases.every((p) => typeof p === 'string' && p.trim().length > 0)) {
|
|
180
|
+
this.log.warn('Voice Agent: invalid tool_feedback.pre_tool_speech_phrases — feedback config excluded');
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
enabled: true,
|
|
185
|
+
pre_tool_speech: cfg.pre_tool_speech,
|
|
186
|
+
pre_tool_speech_phrases: phrases,
|
|
187
|
+
tool_call_sound: cfg.tool_call_sound,
|
|
188
|
+
tool_call_sound_behavior: cfg.tool_call_sound_behavior,
|
|
189
|
+
delay_seconds: delay
|
|
190
|
+
};
|
|
191
|
+
}
|
|
111
192
|
isStepFlagEnabled(value) {
|
|
112
193
|
return value === true || value === 'true';
|
|
113
194
|
}
|
|
@@ -127,6 +208,75 @@ class VoiceAgent extends voice_1.default {
|
|
|
127
208
|
options: this.parseAgentServiceOptions(label, service.options)
|
|
128
209
|
};
|
|
129
210
|
}
|
|
211
|
+
validatePerToolFeedback(config, toolName) {
|
|
212
|
+
if (config == null || typeof config !== 'object' || Array.isArray(config)) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const raw = config;
|
|
216
|
+
const result = {};
|
|
217
|
+
if ('delay_seconds' in raw && raw.delay_seconds != null) {
|
|
218
|
+
const delay = Number(raw.delay_seconds);
|
|
219
|
+
if (!Number.isFinite(delay) || delay <= 0 || delay > 30) {
|
|
220
|
+
this.log.warn(`Voice Agent: invalid feedback.delay_seconds for tool "${toolName}" — per-tool feedback excluded`);
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
result.delay_seconds = delay;
|
|
224
|
+
}
|
|
225
|
+
if ('pre_tool_speech' in raw && raw.pre_tool_speech != null) {
|
|
226
|
+
const valid = ['auto', 'static', 'off'];
|
|
227
|
+
if (!valid.includes(raw.pre_tool_speech)) {
|
|
228
|
+
this.log.warn(`Voice Agent: invalid feedback.pre_tool_speech for tool "${toolName}" — per-tool feedback excluded`);
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
result.pre_tool_speech = raw.pre_tool_speech;
|
|
232
|
+
}
|
|
233
|
+
if ('tool_call_sound' in raw && raw.tool_call_sound != null) {
|
|
234
|
+
const valid = ['typing', 'none'];
|
|
235
|
+
if (!valid.includes(raw.tool_call_sound)) {
|
|
236
|
+
this.log.warn(`Voice Agent: invalid feedback.tool_call_sound for tool "${toolName}" — per-tool feedback excluded`);
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
result.tool_call_sound = raw.tool_call_sound;
|
|
240
|
+
}
|
|
241
|
+
if ('tool_call_sound_behavior' in raw && raw.tool_call_sound_behavior != null) {
|
|
242
|
+
const valid = ['always', 'with_pre_speech'];
|
|
243
|
+
if (!valid.includes(raw.tool_call_sound_behavior)) {
|
|
244
|
+
this.log.warn(`Voice Agent: invalid feedback.tool_call_sound_behavior for tool "${toolName}" — per-tool feedback excluded`);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
result.tool_call_sound_behavior = raw.tool_call_sound_behavior;
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
validateSoftTimeout(config) {
|
|
252
|
+
if (config == null || typeof config !== 'object' || Array.isArray(config))
|
|
253
|
+
return null;
|
|
254
|
+
const cfg = config;
|
|
255
|
+
const timeoutSeconds = cfg.timeout_seconds;
|
|
256
|
+
if (typeof timeoutSeconds !== 'number' || !Number.isFinite(timeoutSeconds) || timeoutSeconds <= 0 || timeoutSeconds > 30) {
|
|
257
|
+
this.log.warn('Voice Agent: invalid soft_timeout.timeout_seconds — soft timeout config excluded');
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const validModes = ['static', 'auto'];
|
|
261
|
+
if (!validModes.includes(cfg.mode)) {
|
|
262
|
+
this.log.warn('Voice Agent: invalid soft_timeout.mode — soft timeout config excluded');
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
// Validate phrases
|
|
266
|
+
const phrases = cfg.phrases;
|
|
267
|
+
if (!Array.isArray(phrases) ||
|
|
268
|
+
phrases.length < 1 ||
|
|
269
|
+
phrases.length > 20 ||
|
|
270
|
+
!phrases.every((p) => typeof p === 'string' && p.trim().length > 0)) {
|
|
271
|
+
this.log.warn('Voice Agent: invalid soft_timeout.phrases — soft timeout config excluded');
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
timeout_seconds: timeoutSeconds,
|
|
276
|
+
phrases: phrases,
|
|
277
|
+
mode: cfg.mode
|
|
278
|
+
};
|
|
279
|
+
}
|
|
130
280
|
parseAgentServiceOptions(label, options) {
|
|
131
281
|
if (options == null || options === '')
|
|
132
282
|
return undefined;
|