@onereach/step-voice 7.0.31 → 7.0.32-VOIC1701.2

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.
@@ -0,0 +1,41 @@
1
+ import VoiceStep from './voice';
2
+ type SystemInstructionMode = 'append' | 'replace' | 'off';
3
+ interface Tool {
4
+ name: string;
5
+ description: string;
6
+ parameters: string | Record<string, unknown>;
7
+ exitId?: string;
8
+ }
9
+ interface AgentServiceConfig {
10
+ provider: string;
11
+ model: string;
12
+ api_key?: string;
13
+ options?: Record<string, unknown>;
14
+ }
15
+ interface INPUT {
16
+ system_instruction_mode: SystemInstructionMode;
17
+ system_instruction: string;
18
+ developer_messages_mode: 'append' | 'replace';
19
+ developer_messages: Array<string | {
20
+ message?: string;
21
+ }>;
22
+ tools_mode: 'append' | 'replace';
23
+ tools: Tool[];
24
+ custom_config_enabled: boolean;
25
+ mode: string;
26
+ stt: Partial<AgentServiceConfig>;
27
+ llm: Partial<AgentServiceConfig>;
28
+ tts: Partial<AgentServiceConfig>;
29
+ realtime: Partial<AgentServiceConfig>;
30
+ }
31
+ export default class UpdateVoiceAgent extends VoiceStep<Partial<INPUT>> {
32
+ runStep(): Promise<void>;
33
+ exitToThread(): Promise<void>;
34
+ private findExitByLabel;
35
+ private normalizeMessages;
36
+ private buildTools;
37
+ private buildOptionalServiceOverride;
38
+ private parseAgentServiceOptions;
39
+ private isStepFlagEnabled;
40
+ }
41
+ export {};
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
5
+ const voice_1 = tslib_1.__importDefault(require("./voice"));
6
+ class UpdateVoiceAgent extends voice_1.default {
7
+ async runStep() {
8
+ const call = await this.fetchData();
9
+ this.triggers.local(`in/voice/${call.id}`, async (event) => {
10
+ switch (event.params.type) {
11
+ case 'ok': {
12
+ const hasTools = (this.data.tools || []).some(t => t && !lodash_1.default.isEmpty(lodash_1.default.trim(t.name)));
13
+ if (hasTools) {
14
+ return;
15
+ }
16
+ return this.exitStep('next');
17
+ }
18
+ case 'function_call': {
19
+ const cb = this.thread.takeCallback();
20
+ const name = event.params.name ?? 'function_call';
21
+ const params = event.params.arguments ?? {};
22
+ const functionId = event.params.functionId ?? '';
23
+ const exitId = this.findExitByLabel(name);
24
+ if (exitId) {
25
+ this.exitStep(exitId, {
26
+ [name]: params,
27
+ name,
28
+ functionId,
29
+ __voicecb: cb,
30
+ callId: call.id,
31
+ callType: call.type,
32
+ callCallback: call.callback,
33
+ }, true);
34
+ }
35
+ else {
36
+ this.log.warn('Update Voice Agent: no exit for function_call', { name });
37
+ }
38
+ return;
39
+ }
40
+ case 'hangup':
41
+ await this.handleHangup(call);
42
+ return await this.waitConvEnd();
43
+ case 'error':
44
+ return this.throwError(event.params.error);
45
+ case 'cancel':
46
+ return this.end();
47
+ }
48
+ });
49
+ this.triggers.otherwise(async () => {
50
+ const { system_instruction_mode = 'append', system_instruction = '', developer_messages_mode = 'append', developer_messages = [], tools_mode = 'append', tools: toolDefs = [], custom_config_enabled = false, mode = '', stt = {}, llm = {}, tts = {}, realtime = {}, } = this.data;
51
+ const params = {};
52
+ if (system_instruction_mode !== 'off'
53
+ && !lodash_1.default.isEmpty(lodash_1.default.trim(String(system_instruction)))) {
54
+ params.system_instruction = {
55
+ mode: system_instruction_mode === 'replace' ? 'replace' : 'append',
56
+ text: String(system_instruction),
57
+ };
58
+ }
59
+ const resolvedRulesMode = developer_messages_mode === 'replace' ? 'replace' : 'append';
60
+ const rules = this.normalizeMessages(developer_messages);
61
+ if (rules.length > 0 || resolvedRulesMode === 'replace') {
62
+ params.developer_messages = rules;
63
+ params.developer_messages_mode = resolvedRulesMode;
64
+ }
65
+ const resolvedToolsMode = tools_mode === 'replace' ? 'replace' : 'append';
66
+ const tools = this.buildTools(toolDefs);
67
+ if (tools.length > 0 || resolvedToolsMode === 'replace') {
68
+ params.tools = tools;
69
+ params.tools_mode = resolvedToolsMode;
70
+ }
71
+ if (this.isStepFlagEnabled(custom_config_enabled)) {
72
+ if (mode !== 'waterfall' && mode !== 'realtime') {
73
+ this.throwError(new Error(`Update Voice Agent: unknown mode "${mode}"`));
74
+ }
75
+ params.mode = mode;
76
+ if (mode === 'realtime') {
77
+ const realtimeOverride = this.buildOptionalServiceOverride('realtime', realtime);
78
+ if (!realtimeOverride) {
79
+ this.throwError(new Error('Update Voice Agent: set realtime model or options when pipeline override is enabled'));
80
+ }
81
+ params.realtime = realtimeOverride;
82
+ }
83
+ else {
84
+ const sttOverride = this.buildOptionalServiceOverride('stt', stt);
85
+ const llmOverride = this.buildOptionalServiceOverride('llm', llm);
86
+ const ttsOverride = this.buildOptionalServiceOverride('tts', tts);
87
+ if (!sttOverride && !llmOverride && !ttsOverride) {
88
+ this.throwError(new Error('Update Voice Agent: set at least one model or options when pipeline override is enabled'));
89
+ }
90
+ if (sttOverride)
91
+ params.stt = sttOverride;
92
+ if (llmOverride)
93
+ params.llm = llmOverride;
94
+ if (ttsOverride)
95
+ params.tts = ttsOverride;
96
+ }
97
+ }
98
+ if (!params.system_instruction
99
+ && params.developer_messages == null
100
+ && params.tools == null
101
+ && !params.mode) {
102
+ this.throwError(new Error('Update Voice Agent: provide a system instruction update, at least one rule, at least one tool, or a pipeline/models override'));
103
+ }
104
+ await this.sendCommands(call, [{ name: 'updateAgent', params }]);
105
+ return this.exitFlow();
106
+ });
107
+ }
108
+ async exitToThread() {
109
+ const result = this.state.result;
110
+ await this.thread.set(`__voiceAgentContext_${this.thread.id}`, result);
111
+ this.thread.exitStep(this.state.exitStep, result);
112
+ }
113
+ findExitByLabel(label) {
114
+ const exit = lodash_1.default.find(this.step.exits, (e) => e.label === label);
115
+ return exit?.id;
116
+ }
117
+ normalizeMessages(messages) {
118
+ return (messages || [])
119
+ .map(item => typeof item === 'string' ? item : item?.message ?? '')
120
+ .map(msg => lodash_1.default.trim(String(msg)))
121
+ .filter(msg => !lodash_1.default.isEmpty(msg));
122
+ }
123
+ buildTools(tools) {
124
+ return (tools || [])
125
+ .filter(t => t && !lodash_1.default.isEmpty(lodash_1.default.trim(t.name)))
126
+ .map(t => {
127
+ let parameters = {};
128
+ if (typeof t.parameters === 'string') {
129
+ try {
130
+ parameters = JSON.parse(t.parameters) || {};
131
+ }
132
+ catch {
133
+ parameters = {};
134
+ }
135
+ }
136
+ else if (t.parameters && typeof t.parameters === 'object') {
137
+ parameters = t.parameters;
138
+ }
139
+ return {
140
+ type: 'function',
141
+ name: lodash_1.default.trim(t.name),
142
+ description: t.description || '',
143
+ parameters,
144
+ };
145
+ });
146
+ }
147
+ buildOptionalServiceOverride(label, service) {
148
+ const options = this.parseAgentServiceOptions(label, service.options);
149
+ const hasModel = !lodash_1.default.isEmpty(lodash_1.default.trim(String(service.model ?? '')));
150
+ const hasOptions = options != null && Object.keys(options).length > 0;
151
+ if (!hasModel && !hasOptions) {
152
+ return undefined;
153
+ }
154
+ if (lodash_1.default.isEmpty(service.provider)) {
155
+ this.throwError(new Error(`Update Voice Agent: provider is required for ${label} (locked from Voice Agent pipeline)`));
156
+ }
157
+ return {
158
+ provider: service.provider ?? '',
159
+ model: hasModel ? lodash_1.default.trim(String(service.model)) : '',
160
+ options,
161
+ };
162
+ }
163
+ parseAgentServiceOptions(label, options) {
164
+ if (options == null || options === '')
165
+ return undefined;
166
+ if (typeof options === 'string') {
167
+ try {
168
+ options = JSON.parse(options);
169
+ }
170
+ catch {
171
+ this.throwError(new Error(`Update Voice Agent: invalid options JSON for ${label}`));
172
+ }
173
+ }
174
+ if (typeof options !== 'object' || Array.isArray(options)) {
175
+ this.throwError(new Error(`Update Voice Agent: options for ${label} must be a JSON object`));
176
+ }
177
+ return options;
178
+ }
179
+ isStepFlagEnabled(value) {
180
+ return value === true || value === 'true' || value === 1 || value === '1';
181
+ }
182
+ }
183
+ exports.default = UpdateVoiceAgent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onereach/step-voice",
3
- "version": "7.0.31",
3
+ "version": "7.0.32-VOIC1701.2",
4
4
  "author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
5
5
  "contributors": [
6
6
  "Roman Zolotarov",