@kognitivedev/backend-cloud 0.2.29
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/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-test.log +14 -0
- package/CHANGELOG.md +11 -0
- package/README.md +88 -0
- package/dist/cloud-voice-parameters.d.ts +11 -0
- package/dist/cloud-voice-parameters.js +219 -0
- package/dist/cloud-voice-prompt-service.d.ts +24 -0
- package/dist/cloud-voice-prompt-service.js +382 -0
- package/dist/cloud-voice-runtime-service.d.ts +73 -0
- package/dist/cloud-voice-runtime-service.js +443 -0
- package/dist/cloud-voice.d.ts +36 -0
- package/dist/cloud-voice.js +683 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +26 -0
- package/dist/phone-control.d.ts +50 -0
- package/dist/phone-control.js +97 -0
- package/dist/phone-runtime/audio-playout-tracker.d.ts +51 -0
- package/dist/phone-runtime/audio-playout-tracker.js +93 -0
- package/dist/phone-runtime/openai-twilio-realtime.d.ts +95 -0
- package/dist/phone-runtime/openai-twilio-realtime.js +1074 -0
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +216 -0
- package/dist/types.d.ts +468 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +14 -0
- package/package.json +47 -0
- package/src/__tests__/audio-playout-tracker.test.ts +46 -0
- package/src/__tests__/cloud-voice.test.ts +1006 -0
- package/src/__tests__/openai-twilio-realtime.test.ts +1193 -0
- package/src/__tests__/phone-control.test.ts +105 -0
- package/src/cloud-voice-parameters.ts +236 -0
- package/src/cloud-voice-prompt-service.ts +493 -0
- package/src/cloud-voice-runtime-service.ts +465 -0
- package/src/cloud-voice.ts +831 -0
- package/src/index.ts +10 -0
- package/src/phone-control.ts +156 -0
- package/src/phone-runtime/audio-playout-tracker.ts +132 -0
- package/src/phone-runtime/openai-twilio-realtime.ts +1250 -0
- package/src/tools.ts +227 -0
- package/src/types.ts +529 -0
- package/src/utils.ts +11 -0
- package/tsconfig.json +13 -0
package/src/tools.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CloudVoiceTelephonyDestination,
|
|
3
|
+
ExecuteCloudVoiceToolBindingInput,
|
|
4
|
+
ExecuteCloudVoiceToolBindingResult,
|
|
5
|
+
} from "./types";
|
|
6
|
+
import { renderCloudVoiceParameterTemplate } from "./cloud-voice-parameters";
|
|
7
|
+
import { getNumber, getRecord, getString } from "./utils";
|
|
8
|
+
|
|
9
|
+
function requiredHandler<T>(handler: T | undefined, toolType: string): T {
|
|
10
|
+
if (!handler) throw new Error(`Cloud Voice tool type "${toolType}" is not configured`);
|
|
11
|
+
return handler;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function applyParameterBindings(input: ExecuteCloudVoiceToolBindingInput) {
|
|
15
|
+
const args = { ...getRecord(input.args) };
|
|
16
|
+
const bindings = getRecord(input.tool.parameterBindings);
|
|
17
|
+
const parameters = getRecord(input.parameters);
|
|
18
|
+
for (const [field, rawBinding] of Object.entries(bindings)) {
|
|
19
|
+
const binding = getRecord(rawBinding);
|
|
20
|
+
const parameterKey = getString(binding.parameter, "");
|
|
21
|
+
if (!field || !parameterKey || !Object.prototype.hasOwnProperty.call(parameters, parameterKey)) continue;
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(args, field) && args[field] !== undefined && args[field] !== null && args[field] !== "") continue;
|
|
23
|
+
args[field] = parameters[parameterKey];
|
|
24
|
+
}
|
|
25
|
+
return args;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function omitReservedToolArgs(args: Record<string, unknown>) {
|
|
29
|
+
const next = { ...args };
|
|
30
|
+
delete next.to;
|
|
31
|
+
delete next.fromNumberId;
|
|
32
|
+
delete next.timeoutMs;
|
|
33
|
+
delete next.intervalMs;
|
|
34
|
+
return next;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function readMappedValue(value: unknown, context: Record<string, unknown>) {
|
|
38
|
+
if (typeof value === "string") return renderCloudVoiceParameterTemplate(value, context);
|
|
39
|
+
const record = getRecord(value);
|
|
40
|
+
const mode = getString(record.mode, "");
|
|
41
|
+
if (mode === "literal") return record.value;
|
|
42
|
+
if (mode === "tool_input") return context[getString(record.value ?? record.key, "")];
|
|
43
|
+
if (mode === "parent_parameter") return context[getString(record.value ?? record.parameter, "")];
|
|
44
|
+
if (Object.keys(record).length > 0 && "value" in record) return record.value;
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function resolveCloudVoiceAgentParameters(input: ExecuteCloudVoiceToolBindingInput, args: Record<string, unknown>) {
|
|
49
|
+
const config = getRecord(input.tool.config);
|
|
50
|
+
const context = { ...(input.parameters ?? {}), ...args };
|
|
51
|
+
const parameters = omitReservedToolArgs(args);
|
|
52
|
+
const mappings = getRecord(config.parameterMappings);
|
|
53
|
+
for (const [key, mapping] of Object.entries(mappings)) {
|
|
54
|
+
const mapped = readMappedValue(mapping, context);
|
|
55
|
+
if (mapped !== undefined && mapped !== null && mapped !== "") {
|
|
56
|
+
parameters[key] = mapped;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return parameters;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveTransferDestination(value: unknown): CloudVoiceTelephonyDestination {
|
|
63
|
+
const record = getRecord(value);
|
|
64
|
+
if (record.type === "phone_number" && typeof record.phoneNumber === "string" && record.phoneNumber.trim()) {
|
|
65
|
+
return {
|
|
66
|
+
type: "phone_number",
|
|
67
|
+
phoneNumber: record.phoneNumber.trim(),
|
|
68
|
+
connectionId: getString(record.connectionId, "") || undefined,
|
|
69
|
+
callerId: getString(record.callerId, "") || undefined,
|
|
70
|
+
metadata: getRecord(record.metadata),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (record.type === "sip_uri" && typeof record.uri === "string" && record.uri.trim()) {
|
|
74
|
+
return {
|
|
75
|
+
type: "sip_uri",
|
|
76
|
+
uri: record.uri.trim(),
|
|
77
|
+
connectionId: getString(record.connectionId, "") || undefined,
|
|
78
|
+
transport: record.transport === "udp" || record.transport === "tcp" || record.transport === "tls" ? record.transport : undefined,
|
|
79
|
+
metadata: getRecord(record.metadata),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (record.type === "extension" && typeof record.extension === "string" && record.extension.trim()) {
|
|
83
|
+
const connectionId = getString(record.connectionId, "");
|
|
84
|
+
if (!connectionId) throw new Error("SIP extension transfer destination is missing connectionId");
|
|
85
|
+
return {
|
|
86
|
+
type: "extension",
|
|
87
|
+
extension: record.extension.trim(),
|
|
88
|
+
connectionId,
|
|
89
|
+
metadata: getRecord(record.metadata),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (record.type === "queue" && typeof record.queueId === "string" && record.queueId.trim()) {
|
|
93
|
+
return {
|
|
94
|
+
type: "queue",
|
|
95
|
+
queueId: record.queueId.trim(),
|
|
96
|
+
metadata: getRecord(record.metadata),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
throw new Error("SIP transfer destination is invalid");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function executeCloudVoiceToolBinding(input: ExecuteCloudVoiceToolBindingInput): Promise<ExecuteCloudVoiceToolBindingResult> {
|
|
103
|
+
const { tool } = input;
|
|
104
|
+
const args = applyParameterBindings(input);
|
|
105
|
+
|
|
106
|
+
if (tool.type === "web_search") {
|
|
107
|
+
const query = getString(args.query, getString(tool.config.query, ""));
|
|
108
|
+
const result = await requiredHandler(input.executeWebSearch, tool.type)({
|
|
109
|
+
query,
|
|
110
|
+
parameters: getRecord(tool.config.parameters),
|
|
111
|
+
});
|
|
112
|
+
return { result, metadata: {} };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (tool.type === "cloud_flow") {
|
|
116
|
+
const flowSlug = getString(tool.config.flowSlug, "");
|
|
117
|
+
const result = await requiredHandler(input.executeCloudFlow, tool.type)({
|
|
118
|
+
flowSlug,
|
|
119
|
+
args,
|
|
120
|
+
resourceId: input.resourceId,
|
|
121
|
+
});
|
|
122
|
+
return { result, metadata: {} };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (tool.type === "knowledge_base") {
|
|
126
|
+
const result = await requiredHandler(input.executeKnowledgeBase, tool.type)({
|
|
127
|
+
pipelineId: getString(tool.config.pipelineId, ""),
|
|
128
|
+
query: getString(args.query, ""),
|
|
129
|
+
topK: getNumber(tool.config.topK, 5),
|
|
130
|
+
});
|
|
131
|
+
return { result, metadata: {} };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (tool.type === "platform_action") {
|
|
135
|
+
const result = await requiredHandler(input.executePlatformAction, tool.type)({
|
|
136
|
+
actionSlug: getString(tool.config.actionSlug, ""),
|
|
137
|
+
connectionId: getString(tool.config.connectionId, ""),
|
|
138
|
+
args,
|
|
139
|
+
});
|
|
140
|
+
return { result, metadata: {} };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (tool.type === "calendar_action") {
|
|
144
|
+
const result = await requiredHandler(input.executeCalendarAction, tool.type)({
|
|
145
|
+
action: getString(tool.config.action, getString(tool.config.actionSlug, tool.id)),
|
|
146
|
+
args,
|
|
147
|
+
config: getRecord(tool.config),
|
|
148
|
+
});
|
|
149
|
+
return { result, metadata: {} };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (tool.type === "appointment_action") {
|
|
153
|
+
const result = await requiredHandler(input.executeAppointmentAction, tool.type)({
|
|
154
|
+
action: getString(tool.config.action, getString(tool.config.actionSlug, tool.id)),
|
|
155
|
+
args,
|
|
156
|
+
config: getRecord(tool.config),
|
|
157
|
+
});
|
|
158
|
+
return { result, metadata: {} };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (tool.type === "cloud_voice_agent") {
|
|
162
|
+
const config = getRecord(tool.config);
|
|
163
|
+
const context = { ...(input.parameters ?? {}), ...args };
|
|
164
|
+
const toTemplate = getString(config.toTemplate, getString(config.to, ""));
|
|
165
|
+
const to = getString(args.to, toTemplate ? renderCloudVoiceParameterTemplate(toTemplate, context) : "");
|
|
166
|
+
const fromNumberId = getString(args.fromNumberId, getString(config.fromNumberId, ""));
|
|
167
|
+
const timeoutMs = getNumber(args.timeoutMs, getNumber(config.timeoutMs, 600_000));
|
|
168
|
+
const intervalMs = getNumber(args.intervalMs, getNumber(config.intervalMs, 2_000));
|
|
169
|
+
const result = await requiredHandler(input.executeCloudVoiceAgent, tool.type)({
|
|
170
|
+
agentSlug: getString(config.agentSlug, ""),
|
|
171
|
+
fromNumberId,
|
|
172
|
+
to,
|
|
173
|
+
parameters: resolveCloudVoiceAgentParameters(input, args),
|
|
174
|
+
timeoutMs,
|
|
175
|
+
intervalMs,
|
|
176
|
+
metadata: getRecord(config.metadata),
|
|
177
|
+
tool,
|
|
178
|
+
args,
|
|
179
|
+
});
|
|
180
|
+
return { result, metadata: {} };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (tool.type === "external_webhook") {
|
|
184
|
+
const result = await requiredHandler(input.executeExternalWebhook, tool.type)({
|
|
185
|
+
tool,
|
|
186
|
+
args,
|
|
187
|
+
});
|
|
188
|
+
return { result, metadata: {} };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (tool.type === "sip_transfer") {
|
|
192
|
+
const config = getRecord(tool.config);
|
|
193
|
+
const providerCallId = getString(args.providerCallId, getString(config.providerCallId, ""));
|
|
194
|
+
if (!providerCallId) throw new Error(`SIP transfer tool "${tool.id}" is missing providerCallId`);
|
|
195
|
+
const mode = args.mode === "attended" || args.mode === "warm" || args.mode === "blind"
|
|
196
|
+
? args.mode
|
|
197
|
+
: config.mode === "attended" || config.mode === "warm" || config.mode === "blind"
|
|
198
|
+
? config.mode
|
|
199
|
+
: undefined;
|
|
200
|
+
const result = await requiredHandler(input.executeSipTransfer, tool.type)({
|
|
201
|
+
providerCallId,
|
|
202
|
+
destination: resolveTransferDestination(args.destination ?? config.destination),
|
|
203
|
+
mode,
|
|
204
|
+
reason: getString(args.reason, getString(config.reason, "agent_requested_transfer")),
|
|
205
|
+
policy: getRecord(args.policy ?? config.policy),
|
|
206
|
+
metadata: {
|
|
207
|
+
projectId: input.projectId,
|
|
208
|
+
sessionId: input.sessionId,
|
|
209
|
+
toolId: tool.id,
|
|
210
|
+
...(input.resourceId ?? {}),
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
return {
|
|
214
|
+
result,
|
|
215
|
+
metadata: {
|
|
216
|
+
transfer: {
|
|
217
|
+
providerCallId: result.providerCallId,
|
|
218
|
+
transferId: result.transferId,
|
|
219
|
+
mode: result.mode,
|
|
220
|
+
status: result.status,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
throw new Error(`Unsupported Cloud Voice tool type "${String(tool.type)}"`);
|
|
227
|
+
}
|