@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.
Files changed (43) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-test.log +14 -0
  3. package/CHANGELOG.md +11 -0
  4. package/README.md +88 -0
  5. package/dist/cloud-voice-parameters.d.ts +11 -0
  6. package/dist/cloud-voice-parameters.js +219 -0
  7. package/dist/cloud-voice-prompt-service.d.ts +24 -0
  8. package/dist/cloud-voice-prompt-service.js +382 -0
  9. package/dist/cloud-voice-runtime-service.d.ts +73 -0
  10. package/dist/cloud-voice-runtime-service.js +443 -0
  11. package/dist/cloud-voice.d.ts +36 -0
  12. package/dist/cloud-voice.js +683 -0
  13. package/dist/index.d.ts +10 -0
  14. package/dist/index.js +26 -0
  15. package/dist/phone-control.d.ts +50 -0
  16. package/dist/phone-control.js +97 -0
  17. package/dist/phone-runtime/audio-playout-tracker.d.ts +51 -0
  18. package/dist/phone-runtime/audio-playout-tracker.js +93 -0
  19. package/dist/phone-runtime/openai-twilio-realtime.d.ts +95 -0
  20. package/dist/phone-runtime/openai-twilio-realtime.js +1074 -0
  21. package/dist/tools.d.ts +2 -0
  22. package/dist/tools.js +216 -0
  23. package/dist/types.d.ts +468 -0
  24. package/dist/types.js +2 -0
  25. package/dist/utils.d.ts +3 -0
  26. package/dist/utils.js +14 -0
  27. package/package.json +47 -0
  28. package/src/__tests__/audio-playout-tracker.test.ts +46 -0
  29. package/src/__tests__/cloud-voice.test.ts +1006 -0
  30. package/src/__tests__/openai-twilio-realtime.test.ts +1193 -0
  31. package/src/__tests__/phone-control.test.ts +105 -0
  32. package/src/cloud-voice-parameters.ts +236 -0
  33. package/src/cloud-voice-prompt-service.ts +493 -0
  34. package/src/cloud-voice-runtime-service.ts +465 -0
  35. package/src/cloud-voice.ts +831 -0
  36. package/src/index.ts +10 -0
  37. package/src/phone-control.ts +156 -0
  38. package/src/phone-runtime/audio-playout-tracker.ts +132 -0
  39. package/src/phone-runtime/openai-twilio-realtime.ts +1250 -0
  40. package/src/tools.ts +227 -0
  41. package/src/types.ts +529 -0
  42. package/src/utils.ts +11 -0
  43. package/tsconfig.json +13 -0
@@ -0,0 +1,683 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CLOUD_VOICE_FLOW_INSTRUCTION_COMPILER_VERSION = exports.CLOUD_VOICE_SIP_TRANSFER_TOOL = exports.CLOUD_VOICE_PHONE_HANGUP_TOOL = exports.CLOUD_VOICE_CHANNELS = exports.resolveCloudVoiceProviderSystemPrompt = exports.compileCloudVoiceInstructions = exports.buildPhoneOpeningPrompt = exports.buildPhoneControlRule = exports.toPreparedTranscription = exports.toOpenAITurnDetection = exports.resolveCloudVoiceSpeechLanguageCode = exports.normalizeCloudVoiceTurnDetection = exports.normalizeCloudVoicePipelineConfig = exports.normalizeCloudVoiceHumanizationConfig = exports.normalizeCloudVoiceConversationProfile = exports.getCloudVoiceProviderCapabilities = exports.compileCartesiaTtsOptions = exports.DEFAULT_CLOUD_VOICE_HUMANIZATION = exports.CLOUD_VOICE_PROVIDER_CAPABILITIES = exports.CLOUD_VOICE_PROMPT_COMPILER_VERSION = exports.CLOUD_VOICE_CONFIG_VERSION = void 0;
4
+ exports.resolveCloudVoiceChannel = resolveCloudVoiceChannel;
5
+ exports.shouldInjectPhoneControlTools = shouldInjectPhoneControlTools;
6
+ exports.shouldInjectSipControlTools = shouldInjectSipControlTools;
7
+ exports.shouldPersistPhonePrepareSnapshot = shouldPersistPhonePrepareSnapshot;
8
+ exports.resolveToolInputSchema = resolveToolInputSchema;
9
+ exports.compileVoiceGraphToInstructions = compileVoiceGraphToInstructions;
10
+ exports.compileCloudVoiceGraphConfig = compileCloudVoiceGraphConfig;
11
+ exports.normalizeClientToolManifests = normalizeClientToolManifests;
12
+ exports.prepareCloudVoiceSessionConfig = prepareCloudVoiceSessionConfig;
13
+ exports.createPhonePrepareSnapshot = createPhonePrepareSnapshot;
14
+ const utils_1 = require("./utils");
15
+ const cloud_voice_runtime_service_1 = require("./cloud-voice-runtime-service");
16
+ const cloud_voice_prompt_service_1 = require("./cloud-voice-prompt-service");
17
+ const cloud_voice_parameters_1 = require("./cloud-voice-parameters");
18
+ var cloud_voice_runtime_service_2 = require("./cloud-voice-runtime-service");
19
+ Object.defineProperty(exports, "CLOUD_VOICE_CONFIG_VERSION", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.CLOUD_VOICE_CONFIG_VERSION; } });
20
+ Object.defineProperty(exports, "CLOUD_VOICE_PROMPT_COMPILER_VERSION", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.CLOUD_VOICE_PROMPT_COMPILER_VERSION; } });
21
+ Object.defineProperty(exports, "CLOUD_VOICE_PROVIDER_CAPABILITIES", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.CLOUD_VOICE_PROVIDER_CAPABILITIES; } });
22
+ Object.defineProperty(exports, "DEFAULT_CLOUD_VOICE_HUMANIZATION", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.DEFAULT_CLOUD_VOICE_HUMANIZATION; } });
23
+ Object.defineProperty(exports, "compileCartesiaTtsOptions", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.compileCartesiaTtsOptions; } });
24
+ Object.defineProperty(exports, "getCloudVoiceProviderCapabilities", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.getCloudVoiceProviderCapabilities; } });
25
+ Object.defineProperty(exports, "normalizeCloudVoiceConversationProfile", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.normalizeCloudVoiceConversationProfile; } });
26
+ Object.defineProperty(exports, "normalizeCloudVoiceHumanizationConfig", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.normalizeCloudVoiceHumanizationConfig; } });
27
+ Object.defineProperty(exports, "normalizeCloudVoicePipelineConfig", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.normalizeCloudVoicePipelineConfig; } });
28
+ Object.defineProperty(exports, "normalizeCloudVoiceTurnDetection", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.normalizeCloudVoiceTurnDetection; } });
29
+ Object.defineProperty(exports, "resolveCloudVoiceSpeechLanguageCode", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.resolveCloudVoiceSpeechLanguageCode; } });
30
+ Object.defineProperty(exports, "toOpenAITurnDetection", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.toOpenAITurnDetection; } });
31
+ Object.defineProperty(exports, "toPreparedTranscription", { enumerable: true, get: function () { return cloud_voice_runtime_service_2.toPreparedTranscription; } });
32
+ var cloud_voice_prompt_service_2 = require("./cloud-voice-prompt-service");
33
+ Object.defineProperty(exports, "buildPhoneControlRule", { enumerable: true, get: function () { return cloud_voice_prompt_service_2.buildPhoneControlRule; } });
34
+ Object.defineProperty(exports, "buildPhoneOpeningPrompt", { enumerable: true, get: function () { return cloud_voice_prompt_service_2.buildPhoneOpeningPrompt; } });
35
+ Object.defineProperty(exports, "compileCloudVoiceInstructions", { enumerable: true, get: function () { return cloud_voice_prompt_service_2.compileCloudVoiceInstructions; } });
36
+ Object.defineProperty(exports, "resolveCloudVoiceProviderSystemPrompt", { enumerable: true, get: function () { return cloud_voice_prompt_service_2.resolveCloudVoiceProviderSystemPrompt; } });
37
+ exports.CLOUD_VOICE_CHANNELS = new Set(["web", "iframe", "script", "phone", "sip", "outbound"]);
38
+ exports.CLOUD_VOICE_PHONE_HANGUP_TOOL = {
39
+ type: "function",
40
+ name: "hang_up_call",
41
+ description: "End the active phone call only after the caller clearly asks to end the call, says goodbye, or answers that they do not need anything else after you ask. Before using this tool, make sure the conversation has a natural closing: ask if there is anything else unless the caller already clearly ended, then say a brief goodbye such as \"bye\", \"see you later\", or \"take care\". Never use this when the caller asks what tools, abilities, or actions you have access to.",
42
+ parameters: {
43
+ type: "object",
44
+ properties: {
45
+ reason: {
46
+ type: "string",
47
+ description: "Short reason for ending the call.",
48
+ },
49
+ },
50
+ required: ["reason"],
51
+ additionalProperties: false,
52
+ },
53
+ };
54
+ exports.CLOUD_VOICE_SIP_TRANSFER_TOOL = {
55
+ type: "function",
56
+ name: "sip_transfer_call",
57
+ description: "Transfer the active SIP or phone call to a configured destination only when the current voice flow or agent policy allows transfer. Use this for live SIP/queue/extension/phone-number handoff, not for summarizing information.",
58
+ parameters: {
59
+ type: "object",
60
+ properties: {
61
+ providerCallId: {
62
+ type: "string",
63
+ description: "Provider call id for the active call leg. Omit when the runtime supplies it out of band.",
64
+ },
65
+ destinationId: {
66
+ type: "string",
67
+ description: "Configured transfer destination id.",
68
+ },
69
+ mode: {
70
+ type: "string",
71
+ enum: ["blind", "attended", "warm"],
72
+ description: "Transfer mode requested by the flow policy.",
73
+ },
74
+ reason: {
75
+ type: "string",
76
+ description: "Brief reason for the transfer.",
77
+ },
78
+ },
79
+ required: ["destinationId", "reason"],
80
+ additionalProperties: false,
81
+ },
82
+ };
83
+ function resolveCloudVoiceChannel(value) {
84
+ if (value === undefined || value === null || value === "")
85
+ return "web";
86
+ if (typeof value === "string" && exports.CLOUD_VOICE_CHANNELS.has(value)) {
87
+ return value;
88
+ }
89
+ throw new Error(`Unsupported cloud voice channel "${String(value)}"`);
90
+ }
91
+ function shouldInjectPhoneControlTools(channel) {
92
+ return channel === "phone" || channel === "sip" || channel === "outbound";
93
+ }
94
+ function getTransferDestinations(config) {
95
+ const destinations = (0, utils_1.getRecord)(config.metadata).transferDestinations;
96
+ return Array.isArray(destinations)
97
+ ? destinations.filter((destination) => {
98
+ const record = (0, utils_1.getRecord)(destination);
99
+ return typeof record.id === "string" && record.id.trim() !== "" && typeof record.destination === "object";
100
+ })
101
+ : [];
102
+ }
103
+ function entryModeForChannel(channel) {
104
+ return channel === "outbound" ? "outgoing" : channel === "phone" ? "incoming" : "both";
105
+ }
106
+ function normalizeEntryMode(value) {
107
+ if (value === "incoming" || value === "inbound")
108
+ return "incoming";
109
+ if (value === "outgoing" || value === "outbound")
110
+ return "outgoing";
111
+ return "both";
112
+ }
113
+ function shouldInjectSipControlTools(config, channel) {
114
+ if (channel !== "sip" && channel !== "phone" && channel !== "outbound")
115
+ return false;
116
+ return getTransferDestinations(config).some((destination) => destination.destination.type !== "browser_queue");
117
+ }
118
+ function shouldPersistPhonePrepareSnapshot(channel) {
119
+ return shouldInjectPhoneControlTools(channel);
120
+ }
121
+ function resolveToolInputSchema(tool) {
122
+ var _a;
123
+ const schema = (_a = tool.inputSchema) !== null && _a !== void 0 ? _a : (0, utils_1.getRecord)(tool.config).inputSchema;
124
+ return schema && typeof schema === "object" && !Array.isArray(schema)
125
+ ? schema
126
+ : { type: "object", additionalProperties: true };
127
+ }
128
+ const MAX_FLOW_NODES = 64;
129
+ const MAX_FLOW_EDGES = 128;
130
+ const MAX_FLOW_TEXT_LENGTH = 900;
131
+ exports.CLOUD_VOICE_FLOW_INSTRUCTION_COMPILER_VERSION = "voice-flow-paths-v1";
132
+ function getFlowArray(value) {
133
+ return Array.isArray(value) ? value : [];
134
+ }
135
+ function cleanFlowText(value, maxLength = MAX_FLOW_TEXT_LENGTH) {
136
+ const text = (0, utils_1.getString)(value, "").replace(/\s+/g, " ").trim();
137
+ return text.length > maxLength ? `${text.slice(0, maxLength - 3)}...` : text;
138
+ }
139
+ function normalizeFlowOutput(value) {
140
+ const record = (0, utils_1.getRecord)(value);
141
+ const id = cleanFlowText(record.id, 96);
142
+ const label = cleanFlowText(record.label, 140);
143
+ if (!id || !label)
144
+ return null;
145
+ return {
146
+ id,
147
+ label,
148
+ description: cleanFlowText(record.description, 360) || undefined,
149
+ desc: cleanFlowText(record.desc, 360) || undefined,
150
+ condition: cleanFlowText(record.condition, 360) || undefined,
151
+ icon: cleanFlowText(record.icon, 96) || undefined,
152
+ metadata: (0, utils_1.getRecord)(record.metadata),
153
+ };
154
+ }
155
+ function normalizeFlowNode(value) {
156
+ const record = (0, utils_1.getRecord)(value);
157
+ const id = cleanFlowText(record.id, 96);
158
+ const type = cleanFlowText(record.type, 64) || "case";
159
+ if (!id)
160
+ return null;
161
+ const toolIds = getFlowArray(record.toolIds)
162
+ .map((toolId) => cleanFlowText(toolId, 96))
163
+ .filter(Boolean);
164
+ const phoneNumberIds = getFlowArray(record.phoneNumberIds)
165
+ .map((phoneNumberId) => cleanFlowText(phoneNumberId, 96))
166
+ .filter(Boolean);
167
+ const maxDuration = typeof record.maxDuration === "number" && Number.isFinite(record.maxDuration)
168
+ ? Math.round(record.maxDuration)
169
+ : cleanFlowText(record.maxDuration, 32) || undefined;
170
+ const transferMode = record.transferMode === "attended" || record.transferMode === "warm" || record.transferMode === "blind"
171
+ ? record.transferMode
172
+ : undefined;
173
+ const metadata = (0, utils_1.getRecord)(record.metadata);
174
+ const subAgentMetadata = type === "sub_agent"
175
+ ? Object.assign(Object.assign(Object.assign({}, (0, utils_1.getRecord)(metadata.subAgent)), ((0, utils_1.getString)(record.subAgentToolId, "") ? { toolId: (0, utils_1.getString)(record.subAgentToolId, "") } : {})), ((0, utils_1.getString)(record.subAgentSlug, "") ? { agentSlug: (0, utils_1.getString)(record.subAgentSlug, "") } : {})) : null;
176
+ return {
177
+ id,
178
+ type,
179
+ entryMode: normalizeEntryMode(record.entryMode),
180
+ title: cleanFlowText(record.title, 160) || undefined,
181
+ prompt: cleanFlowText(record.prompt) || undefined,
182
+ firstMessage: cleanFlowText(record.firstMessage, 360) || undefined,
183
+ language: cleanFlowText(record.language, 32) || undefined,
184
+ maxDuration,
185
+ outputs: getFlowArray(record.outputs).map(normalizeFlowOutput).filter((output) => Boolean(output)),
186
+ toolId: cleanFlowText(record.toolId, 96) || undefined,
187
+ toolIds,
188
+ phoneNumberIds,
189
+ transferTarget: cleanFlowText(record.transferTarget, 160) || undefined,
190
+ transferDestinationId: cleanFlowText(record.transferDestinationId, 96) || undefined,
191
+ transferMode,
192
+ metadata: subAgentMetadata ? Object.assign(Object.assign({}, metadata), { subAgent: subAgentMetadata }) : metadata,
193
+ };
194
+ }
195
+ function normalizeFlowEdge(value) {
196
+ const record = (0, utils_1.getRecord)(value);
197
+ const from = cleanFlowText(record.from, 96);
198
+ const to = cleanFlowText(record.to, 96);
199
+ if (!from || !to)
200
+ return null;
201
+ const fromPort = record.fromPort === null ? null : cleanFlowText(record.fromPort, 96) || null;
202
+ return {
203
+ id: cleanFlowText(record.id, 96) || undefined,
204
+ from,
205
+ fromPort,
206
+ to,
207
+ };
208
+ }
209
+ function normalizeFlowGraph(value) {
210
+ const record = (0, utils_1.getRecord)(value);
211
+ const nodes = getFlowArray(record.nodes)
212
+ .slice(0, MAX_FLOW_NODES)
213
+ .map(normalizeFlowNode)
214
+ .filter((node) => Boolean(node));
215
+ const knownNodeIds = new Set(nodes.map((node) => node.id));
216
+ const edges = getFlowArray(record.edges)
217
+ .slice(0, MAX_FLOW_EDGES)
218
+ .map(normalizeFlowEdge)
219
+ .filter((edge) => Boolean(edge && knownNodeIds.has(edge.from) && knownNodeIds.has(edge.to)));
220
+ if (nodes.length === 0)
221
+ return null;
222
+ const startNodeId = cleanFlowText(record.startNodeId, 96);
223
+ return {
224
+ version: record.version === 1 ? 1 : undefined,
225
+ startNodeId: startNodeId && knownNodeIds.has(startNodeId) ? startNodeId : undefined,
226
+ nodes,
227
+ edges,
228
+ metadata: (0, utils_1.getRecord)(record.metadata),
229
+ };
230
+ }
231
+ function resolveFlowStartNode(graph, options = {}) {
232
+ var _a, _b, _c, _d, _e;
233
+ const entryMode = (_a = options.entryMode) !== null && _a !== void 0 ? _a : "both";
234
+ const initialNodes = graph.nodes.filter((node) => node.type === "initial");
235
+ const matchingStart = entryMode !== "both"
236
+ ? initialNodes.find((node) => normalizeEntryMode(node.entryMode) === entryMode)
237
+ : null;
238
+ const bothStart = initialNodes.find((node) => normalizeEntryMode(node.entryMode) === "both");
239
+ const legacyStart = (_d = (_c = (_b = graph.nodes.find((node) => node.id === graph.startNodeId)) !== null && _b !== void 0 ? _b : initialNodes[0]) !== null && _c !== void 0 ? _c : graph.nodes[0]) !== null && _d !== void 0 ? _d : null;
240
+ return (_e = matchingStart !== null && matchingStart !== void 0 ? matchingStart : bothStart) !== null && _e !== void 0 ? _e : legacyStart;
241
+ }
242
+ function outputDescription(output) {
243
+ var _a, _b, _c;
244
+ return (_c = (_b = (_a = output.condition) !== null && _a !== void 0 ? _a : output.description) !== null && _b !== void 0 ? _b : output.desc) !== null && _c !== void 0 ? _c : "";
245
+ }
246
+ function edgeTargetTitle(edge, nodesById) {
247
+ var _a;
248
+ const target = nodesById.get(edge.to);
249
+ return target ? `${(_a = target.title) !== null && _a !== void 0 ? _a : target.id} (${target.type})` : edge.to;
250
+ }
251
+ function collectNodeToolIds(node) {
252
+ var _a;
253
+ const metadata = (0, utils_1.getRecord)(node.metadata);
254
+ const subAgent = (0, utils_1.getRecord)(metadata.subAgent);
255
+ return [
256
+ node.toolId,
257
+ ...((_a = node.toolIds) !== null && _a !== void 0 ? _a : []),
258
+ (0, utils_1.getString)(node.subAgentToolId, ""),
259
+ (0, utils_1.getString)(subAgent.toolId, ""),
260
+ (0, utils_1.getString)(subAgent.subAgentToolId, ""),
261
+ (0, utils_1.getString)(metadata.toolId, ""),
262
+ (0, utils_1.getString)(metadata.toolName, ""),
263
+ ].map((value) => cleanFlowText(value, 96)).filter(Boolean);
264
+ }
265
+ function toolToManifest(tool) {
266
+ var _a;
267
+ return {
268
+ type: "function",
269
+ name: tool.id,
270
+ description: (_a = tool.description) !== null && _a !== void 0 ? _a : tool.name,
271
+ parameters: resolveToolInputSchema(tool),
272
+ };
273
+ }
274
+ function stableJson(value) {
275
+ if (Array.isArray(value))
276
+ return `[${value.map(stableJson).join(",")}]`;
277
+ if (value && typeof value === "object") {
278
+ const record = value;
279
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
280
+ }
281
+ return JSON.stringify(value);
282
+ }
283
+ function hashText(value) {
284
+ let hash = 2166136261;
285
+ for (let index = 0; index < value.length; index += 1) {
286
+ hash ^= value.charCodeAt(index);
287
+ hash = Math.imul(hash, 16777619);
288
+ }
289
+ return (hash >>> 0).toString(36);
290
+ }
291
+ function graphSignature(graph) {
292
+ return hashText(stableJson(graph));
293
+ }
294
+ function toolLabel(toolId, toolsById) {
295
+ var _a;
296
+ const tool = toolsById.get(toolId);
297
+ return tool ? `${(_a = tool.name) !== null && _a !== void 0 ? _a : tool.id} (\`${tool.id}\`)` : `\`${toolId}\``;
298
+ }
299
+ function toolRequiredInputs(tool) {
300
+ if (!tool)
301
+ return "";
302
+ const schema = (0, utils_1.getRecord)(resolveToolInputSchema(tool));
303
+ const required = Array.isArray(schema.required)
304
+ ? schema.required.filter((item) => typeof item === "string" && item.trim().length > 0)
305
+ : [];
306
+ return required.length > 0 ? required.join(", ") : "";
307
+ }
308
+ function outgoingEdges(nodeId, edgesBySource) {
309
+ var _a;
310
+ return (_a = edgesBySource.get(nodeId)) !== null && _a !== void 0 ? _a : [];
311
+ }
312
+ function outputForEdge(node, edge) {
313
+ var _a, _b;
314
+ return (_b = (_a = node === null || node === void 0 ? void 0 : node.outputs) === null || _a === void 0 ? void 0 : _a.find((output) => output.id === edge.fromPort)) !== null && _b !== void 0 ? _b : null;
315
+ }
316
+ function walkFlowPath(input) {
317
+ var _a, _b, _c, _d, _e, _f;
318
+ const steps = [];
319
+ const toolIds = [];
320
+ const visited = new Set((_a = input.visited) !== null && _a !== void 0 ? _a : []);
321
+ let current = (_b = input.nodesById.get(input.fromNodeId)) !== null && _b !== void 0 ? _b : null;
322
+ while (current && !visited.has(current.id)) {
323
+ visited.add(current.id);
324
+ const title = (_c = current.title) !== null && _c !== void 0 ? _c : current.id;
325
+ if (current.type !== "initial") {
326
+ if (current.prompt) {
327
+ steps.push(`At "${title}", ${current.prompt}`);
328
+ }
329
+ else if (current.type === "case") {
330
+ steps.push(`Handle "${title}" as the active case.`);
331
+ }
332
+ }
333
+ const currentToolIds = collectNodeToolIds(current);
334
+ if (current.type === "tool" && currentToolIds.length === 0 && current.title) {
335
+ const inferred = [...input.toolsById.keys()].find((toolId) => { var _a; return toolId === (current === null || current === void 0 ? void 0 : current.title) || toolId.replace(/[_-]/g, " ").toLowerCase() === ((_a = current === null || current === void 0 ? void 0 : current.title) === null || _a === void 0 ? void 0 : _a.toLowerCase()); });
336
+ if (inferred)
337
+ currentToolIds.push(inferred);
338
+ }
339
+ for (const toolId of currentToolIds) {
340
+ input.referencedToolIds.add(toolId);
341
+ toolIds.push(toolId);
342
+ const tool = input.toolsById.get(toolId);
343
+ const requiredInputs = toolRequiredInputs(tool);
344
+ if (current.type === "sub_agent") {
345
+ steps.push(`Call sub-agent tool ${toolLabel(toolId, input.toolsById)}${requiredInputs ? ` after collecting: ${requiredInputs}` : ""}. Wait for its final result, read the returned \`outcome\`, and continue through the matching outcome branch.`);
346
+ if (current.outputs && current.outputs.length > 0) {
347
+ steps.push(`Sub-agent outcome branches: ${current.outputs.map((output) => `${output.label}${outputDescription(output) ? ` (${outputDescription(output)})` : ""}`).join("; ")}.`);
348
+ }
349
+ }
350
+ else {
351
+ steps.push(`Use ${toolLabel(toolId, input.toolsById)}${requiredInputs ? ` after collecting: ${requiredInputs}` : ""}.`);
352
+ }
353
+ }
354
+ if (current.type === "end" || current.type === "transfer") {
355
+ return { steps, toolIds, terminal: current };
356
+ }
357
+ const edges = outgoingEdges(current.id, input.edgesBySource);
358
+ const defaultEdge = (_e = (_d = edges.find((edge) => !edge.fromPort)) !== null && _d !== void 0 ? _d : edges[0]) !== null && _e !== void 0 ? _e : null;
359
+ if (!defaultEdge)
360
+ return { steps, toolIds, terminal: current };
361
+ const output = outputForEdge(current, defaultEdge);
362
+ if (output) {
363
+ const condition = outputDescription(output);
364
+ steps.push(`If "${output.label}"${condition ? ` (${condition})` : ""} matches inside this step, continue.`);
365
+ }
366
+ current = (_f = input.nodesById.get(defaultEdge.to)) !== null && _f !== void 0 ? _f : null;
367
+ }
368
+ return { steps: [...steps, "Stop following this route if it loops back to a node already visited."], toolIds, terminal: current };
369
+ }
370
+ function terminalInstruction(node) {
371
+ var _a;
372
+ if (!node)
373
+ return "";
374
+ const title = (_a = node.title) !== null && _a !== void 0 ? _a : node.id;
375
+ if (node.type === "end") {
376
+ return node.prompt ? `Then end with: ${node.prompt}` : `Then end at "${title}" with a brief polite closing.`;
377
+ }
378
+ if (node.type === "transfer") {
379
+ const target = node.transferTarget || node.transferDestinationId || title;
380
+ return node.prompt ? `Then transfer/escalate to ${target}: ${node.prompt}` : `Then transfer/escalate to ${target} with a concise handoff summary.`;
381
+ }
382
+ return "";
383
+ }
384
+ function compileVoiceGraphToInstructions(graphInput, options = {}) {
385
+ var _a, _b, _c, _d;
386
+ const graph = normalizeFlowGraph(graphInput);
387
+ if (!graph)
388
+ return null;
389
+ const entryMode = (_a = options.entryMode) !== null && _a !== void 0 ? _a : entryModeForChannel(options.channel);
390
+ const start = resolveFlowStartNode(graph, { entryMode });
391
+ const nodesById = new Map(graph.nodes.map((node) => [node.id, node]));
392
+ const edgesBySource = new Map();
393
+ for (const edge of graph.edges) {
394
+ const list = (_b = edgesBySource.get(edge.from)) !== null && _b !== void 0 ? _b : [];
395
+ list.push(edge);
396
+ edgesBySource.set(edge.from, list);
397
+ }
398
+ const toolsById = new Map(((_c = options.tools) !== null && _c !== void 0 ? _c : []).map((tool) => [tool.id, tool]));
399
+ const referencedToolIds = new Set();
400
+ const warnings = [];
401
+ const signature = graphSignature(graph);
402
+ const lines = [
403
+ (start === null || start === void 0 ? void 0 : start.prompt) || "You are a realtime voice agent. Help the caller clearly and concisely.",
404
+ "",
405
+ "Use this conversation flow as the source of truth for routing and tool usage.",
406
+ "Do not reveal internal node IDs, graph structure, or implementation details to the caller.",
407
+ "Choose the first route that clearly matches the caller's intent. If no route clearly matches, ask one concise clarifying question.",
408
+ ];
409
+ if (start === null || start === void 0 ? void 0 : start.firstMessage) {
410
+ lines.push(`Opening rule: if you speak first, say exactly this as your first sentence before any other greeting or introduction: ${start.firstMessage}`, "Do not prepend, replace, or append an internal agent name, agent number, slug, node name, or workflow name to that first sentence.");
411
+ }
412
+ if (start === null || start === void 0 ? void 0 : start.language)
413
+ lines.push(`Use this language guidance when possible: ${start.language}.`);
414
+ if ((start === null || start === void 0 ? void 0 : start.maxDuration) !== undefined)
415
+ lines.push(`Keep the call within ${String(start.maxDuration)} minutes unless the caller needs a short final clarification.`);
416
+ const startEdges = start ? outgoingEdges(start.id, edgesBySource) : [];
417
+ const routeEdges = start && start.outputs && start.outputs.length > 0
418
+ ? start.outputs.flatMap((output) => startEdges.filter((edge) => edge.fromPort === output.id).map((edge) => ({ output, edge })))
419
+ : startEdges.map((edge) => ({ output: outputForEdge(start !== null && start !== void 0 ? start : undefined, edge), edge }));
420
+ if (routeEdges.length > 0) {
421
+ lines.push("", "Routes:");
422
+ }
423
+ routeEdges.forEach(({ output, edge }, index) => {
424
+ var _a;
425
+ const condition = output ? outputDescription(output) : "";
426
+ const routeName = (_a = output === null || output === void 0 ? void 0 : output.label) !== null && _a !== void 0 ? _a : edgeTargetTitle(edge, nodesById);
427
+ const path = walkFlowPath({
428
+ fromNodeId: edge.to,
429
+ nodesById,
430
+ edgesBySource,
431
+ toolsById,
432
+ referencedToolIds,
433
+ visited: start ? new Set([start.id]) : undefined,
434
+ });
435
+ lines.push("", `${index + 1}. When ${condition || routeName}:`);
436
+ if ((output === null || output === void 0 ? void 0 : output.label) && condition)
437
+ lines.push(` Treat this as the "${output.label}" route.`);
438
+ if (path.steps.length === 0) {
439
+ lines.push(` Continue to "${routeName}" and handle it according to its instruction.`);
440
+ }
441
+ else {
442
+ path.steps.forEach((step, stepIndex) => lines.push(` ${stepIndex + 1}. ${step}`));
443
+ }
444
+ const uniqueToolIds = [...new Set(path.toolIds)];
445
+ if (uniqueToolIds.length > 0) {
446
+ lines.push(` Use tools in this route: ${uniqueToolIds.map((toolId) => toolLabel(toolId, toolsById)).join(", ")}.`);
447
+ lines.push(" Never invent tool results. If a required tool is unavailable or returns no result, explain that limitation and ask for the next best detail.");
448
+ }
449
+ const terminal = terminalInstruction(path.terminal);
450
+ if (terminal)
451
+ lines.push(` ${terminal}`);
452
+ });
453
+ if (routeEdges.length === 0 && start) {
454
+ lines.push("", "No explicit routes are connected. Follow the start node instructions, answer concisely, and ask one clarifying question when intent is unclear.");
455
+ }
456
+ lines.push("", "General tool and closing rules:", "- Use tools only when the matching route requires them or the caller provides enough context for that route.", "- Collect required tool inputs before calling a tool.", "- Summarize tool results in natural spoken language; do not read raw JSON or internal IDs unless they are useful to the caller.", "- Before ending, ask whether the caller needs anything else unless the caller already clearly ended the conversation.");
457
+ const missingToolIds = [...referencedToolIds].filter((toolId) => !toolsById.has(toolId));
458
+ if (missingToolIds.length > 0) {
459
+ warnings.push(`Flow graph references tools that are not configured on this agent: ${missingToolIds.join(", ")}`);
460
+ lines.push("", `Unavailable graph tools: ${missingToolIds.join(", ")}. If these are needed, explain that the action is unavailable instead of inventing results.`);
461
+ }
462
+ const toolManifest = [...referencedToolIds]
463
+ .flatMap((toolId) => {
464
+ const tool = toolsById.get(toolId);
465
+ return tool ? [toolToManifest(tool)] : [];
466
+ });
467
+ return {
468
+ instructions: lines.join("\n"),
469
+ compilerVersion: exports.CLOUD_VOICE_FLOW_INSTRUCTION_COMPILER_VERSION,
470
+ graphSignature: signature,
471
+ startNodeId: (_d = start === null || start === void 0 ? void 0 : start.id) !== null && _d !== void 0 ? _d : null,
472
+ entryMode,
473
+ nodeCount: graph.nodes.length,
474
+ edgeCount: graph.edges.length,
475
+ referencedToolIds: [...referencedToolIds],
476
+ missingToolIds,
477
+ toolManifest,
478
+ warnings,
479
+ };
480
+ }
481
+ function compileCloudVoiceGraphConfig(config) {
482
+ const compiledFlow = compileVoiceGraphToInstructions((0, utils_1.getRecord)(config.metadata).flowGraph, { tools: config.tools });
483
+ if (!compiledFlow)
484
+ return config;
485
+ const runtimeConfig = applyFlowStartRuntimeConfig(config);
486
+ return Object.assign(Object.assign({}, runtimeConfig), { instructions: compiledFlow.instructions, metadata: Object.assign(Object.assign({}, (0, utils_1.getRecord)(runtimeConfig.metadata)), { flowGraphInstructionCompiler: {
487
+ version: compiledFlow.compilerVersion,
488
+ graphSignature: compiledFlow.graphSignature,
489
+ entryMode: compiledFlow.entryMode,
490
+ compiledAt: new Date().toISOString(),
491
+ } }) });
492
+ }
493
+ function getFlowStartNode(config, options = {}) {
494
+ var _a, _b, _c, _d;
495
+ const flowGraph = (0, utils_1.getRecord)(config.metadata).flowGraph;
496
+ const graph = (0, utils_1.getRecord)(flowGraph);
497
+ const nodes = Array.isArray(graph.nodes) ? graph.nodes.map(utils_1.getRecord) : [];
498
+ if (nodes.length === 0)
499
+ return null;
500
+ const entryMode = (_a = options.entryMode) !== null && _a !== void 0 ? _a : "both";
501
+ const initialNodes = nodes.filter((node) => (0, utils_1.getString)(node.type) === "initial");
502
+ const matchingStart = entryMode !== "both"
503
+ ? initialNodes.find((node) => normalizeEntryMode(node.entryMode) === entryMode)
504
+ : null;
505
+ if (matchingStart)
506
+ return matchingStart;
507
+ const bothStart = initialNodes.find((node) => normalizeEntryMode(node.entryMode) === "both");
508
+ if (bothStart)
509
+ return bothStart;
510
+ const startNodeId = (0, utils_1.getString)(graph.startNodeId);
511
+ return (_d = (_c = (_b = nodes.find((node) => (0, utils_1.getString)(node.id) === startNodeId)) !== null && _b !== void 0 ? _b : initialNodes[0]) !== null && _c !== void 0 ? _c : nodes[0]) !== null && _d !== void 0 ? _d : null;
512
+ }
513
+ function isCloudVoiceProvider(value) {
514
+ return value === "openai-realtime"
515
+ || value === "gemini-live"
516
+ || value === "kognitive-voice"
517
+ || value === "xai-realtime";
518
+ }
519
+ function isCloudVoiceTransport(value) {
520
+ return value === "webrtc" || value === "websocket";
521
+ }
522
+ function applyFlowStartRuntimeConfig(config, options = {}) {
523
+ const start = getFlowStartNode(config, options);
524
+ if (!start)
525
+ return config;
526
+ const provider = (0, utils_1.getString)(start.provider);
527
+ const transport = (0, utils_1.getString)(start.transport);
528
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, config), (isCloudVoiceProvider(provider) ? { provider } : {})), ((0, utils_1.getString)(start.model) ? { model: (0, utils_1.getString)(start.model) } : {})), ((0, utils_1.getString)(start.voice) ? { voice: (0, utils_1.getString)(start.voice) } : {})), (isCloudVoiceTransport(transport) ? { transport } : {})), (start.providerOptions && typeof start.providerOptions === "object" && !Array.isArray(start.providerOptions)
529
+ ? { providerOptions: start.providerOptions }
530
+ : {})), (start.transcription === null || (start.transcription && typeof start.transcription === "object" && !Array.isArray(start.transcription))
531
+ ? { transcription: start.transcription }
532
+ : {})), (start.turnDetection === null || (start.turnDetection && typeof start.turnDetection === "object" && !Array.isArray(start.turnDetection))
533
+ ? { turnDetection: start.turnDetection }
534
+ : {})), (start.inputNoiseReduction === null || (start.inputNoiseReduction && typeof start.inputNoiseReduction === "object" && !Array.isArray(start.inputNoiseReduction))
535
+ ? { inputNoiseReduction: start.inputNoiseReduction }
536
+ : {})), (start.humanization && typeof start.humanization === "object" && !Array.isArray(start.humanization)
537
+ ? { humanization: start.humanization }
538
+ : {})), { metadata: Object.assign(Object.assign({}, (0, utils_1.getRecord)(config.metadata)), (start.speech && typeof start.speech === "object" && !Array.isArray(start.speech)
539
+ ? { speech: start.speech }
540
+ : {})) });
541
+ }
542
+ function normalizeClientToolManifests(value) {
543
+ if (!Array.isArray(value))
544
+ return [];
545
+ const tools = [];
546
+ for (const item of value) {
547
+ if (!item || typeof item !== "object" || Array.isArray(item))
548
+ continue;
549
+ const record = item;
550
+ const id = (0, utils_1.getString)(record.id, "");
551
+ if (!id || !/^[A-Za-z0-9_-]{1,64}$/.test(id))
552
+ continue;
553
+ const inputSchema = record.inputSchema && typeof record.inputSchema === "object" && !Array.isArray(record.inputSchema)
554
+ ? record.inputSchema
555
+ : { type: "object", additionalProperties: true };
556
+ tools.push({
557
+ id,
558
+ name: (0, utils_1.getString)(record.name, id),
559
+ description: (0, utils_1.getString)(record.description, (0, utils_1.getString)(record.name, id)),
560
+ inputSchema,
561
+ });
562
+ }
563
+ return tools.slice(0, 32);
564
+ }
565
+ function prepareCloudVoiceSessionConfig(config, input) {
566
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
567
+ const parameters = (_a = input.parameters) !== null && _a !== void 0 ? _a : {};
568
+ const channel = (_b = input.channel) !== null && _b !== void 0 ? _b : "web";
569
+ const entryMode = entryModeForChannel(channel);
570
+ const renderedConfig = (0, cloud_voice_parameters_1.renderCloudVoiceParameterObject)(applyFlowStartRuntimeConfig(config, { entryMode }), parameters);
571
+ const compiledFlow = compileVoiceGraphToInstructions((0, utils_1.getRecord)(renderedConfig.metadata).flowGraph, {
572
+ tools: renderedConfig.tools,
573
+ entryMode,
574
+ });
575
+ const compiledMarker = (0, utils_1.getRecord)((0, utils_1.getRecord)(config.metadata).flowGraphInstructionCompiler);
576
+ const useCompiledFlowAsAuthoredInstructions = Boolean(compiledMarker.version) && Boolean(compiledFlow === null || compiledFlow === void 0 ? void 0 : compiledFlow.instructions);
577
+ const promptConfig = useCompiledFlowAsAuthoredInstructions
578
+ ? Object.assign(Object.assign({}, renderedConfig), { instructions: (_c = compiledFlow === null || compiledFlow === void 0 ? void 0 : compiledFlow.instructions) !== null && _c !== void 0 ? _c : renderedConfig.instructions }) : renderedConfig;
579
+ const instructionsAlreadyIncludeCompiledFlow = Boolean(compiledFlow === null || compiledFlow === void 0 ? void 0 : compiledFlow.instructions)
580
+ && (0, utils_1.getString)(promptConfig.instructions, "").includes((_d = compiledFlow === null || compiledFlow === void 0 ? void 0 : compiledFlow.instructions) !== null && _d !== void 0 ? _d : "");
581
+ const shouldAppendCompiledFlow = Boolean(compiledFlow)
582
+ && !useCompiledFlowAsAuthoredInstructions
583
+ && !instructionsAlreadyIncludeCompiledFlow
584
+ && ((0, utils_1.getString)(compiledMarker.version, "") !== exports.CLOUD_VOICE_FLOW_INSTRUCTION_COMPILER_VERSION
585
+ || (0, utils_1.getString)(compiledMarker.graphSignature, "") !== (compiledFlow === null || compiledFlow === void 0 ? void 0 : compiledFlow.graphSignature)
586
+ || (0, utils_1.getString)(compiledMarker.entryMode, "") !== entryMode);
587
+ const providerOptions = (0, utils_1.getRecord)(renderedConfig.providerOptions);
588
+ const speech = (0, cloud_voice_runtime_service_1.normalizeSpeechConfig)(renderedConfig);
589
+ const languageCode = (0, cloud_voice_runtime_service_1.resolveCloudVoiceSpeechLanguageCode)(renderedConfig);
590
+ const turnDetection = (0, cloud_voice_runtime_service_1.normalizeCloudVoiceTurnDetection)(renderedConfig.provider, channel, renderedConfig.turnDetection);
591
+ const capabilities = (0, cloud_voice_runtime_service_1.getCloudVoiceProviderCapabilities)(renderedConfig.provider);
592
+ const pipeline = renderedConfig.provider === "kognitive-voice" ? (0, cloud_voice_runtime_service_1.normalizeCloudVoicePipelineConfig)(renderedConfig) : undefined;
593
+ const cartesiaTtsOptions = renderedConfig.provider === "kognitive-voice" ? (0, cloud_voice_runtime_service_1.compileCartesiaTtsOptions)(renderedConfig) : undefined;
594
+ const maxOutputTokens = typeof providerOptions.maxOutputTokens === "number" && Number.isFinite(providerOptions.maxOutputTokens)
595
+ ? Math.max(1, Math.round(providerOptions.maxOutputTokens))
596
+ : typeof providerOptions.maxTokens === "number" && Number.isFinite(providerOptions.maxTokens)
597
+ ? Math.max(1, Math.round(providerOptions.maxTokens))
598
+ : "inf";
599
+ const temperature = typeof providerOptions.temperature === "number" && Number.isFinite(providerOptions.temperature)
600
+ ? Math.max(0, Math.min(2, providerOptions.temperature))
601
+ : undefined;
602
+ const toolManifestByName = new Map();
603
+ for (const tool of renderedConfig.tools) {
604
+ toolManifestByName.set(tool.id, {
605
+ type: "function",
606
+ name: tool.id,
607
+ description: (_e = tool.description) !== null && _e !== void 0 ? _e : tool.name,
608
+ parameters: resolveToolInputSchema(tool),
609
+ });
610
+ }
611
+ for (const tool of (_f = input.clientTools) !== null && _f !== void 0 ? _f : []) {
612
+ toolManifestByName.set(tool.id, {
613
+ type: "function",
614
+ name: tool.id,
615
+ description: (_h = (_g = tool.description) !== null && _g !== void 0 ? _g : tool.name) !== null && _h !== void 0 ? _h : tool.id,
616
+ parameters: (_j = tool.inputSchema) !== null && _j !== void 0 ? _j : { type: "object", additionalProperties: true },
617
+ });
618
+ }
619
+ if (shouldInjectPhoneControlTools(channel)) {
620
+ toolManifestByName.set(exports.CLOUD_VOICE_PHONE_HANGUP_TOOL.name, exports.CLOUD_VOICE_PHONE_HANGUP_TOOL);
621
+ }
622
+ if (shouldInjectSipControlTools(config, channel)) {
623
+ toolManifestByName.set(exports.CLOUD_VOICE_SIP_TRANSFER_TOOL.name, exports.CLOUD_VOICE_SIP_TRANSFER_TOOL);
624
+ }
625
+ const toolManifest = Array.from(toolManifestByName.values())
626
+ .sort((left, right) => {
627
+ if (left.name === exports.CLOUD_VOICE_PHONE_HANGUP_TOOL.name)
628
+ return 1;
629
+ if (right.name === exports.CLOUD_VOICE_PHONE_HANGUP_TOOL.name)
630
+ return -1;
631
+ return 0;
632
+ });
633
+ const phoneControlRule = (0, cloud_voice_prompt_service_1.buildPhoneControlRule)({ config: renderedConfig, channel });
634
+ const system = (0, cloud_voice_parameters_1.renderCloudVoiceParameterTemplate)((0, cloud_voice_prompt_service_1.compileCloudVoiceInstructions)({
635
+ config: promptConfig,
636
+ agentName: input.agentName,
637
+ channel,
638
+ toolCount: toolManifest.length,
639
+ phoneControlRule,
640
+ compiledFlowInstructions: shouldAppendCompiledFlow ? (_k = compiledFlow === null || compiledFlow === void 0 ? void 0 : compiledFlow.instructions) !== null && _k !== void 0 ? _k : "" : "",
641
+ }), parameters);
642
+ return {
643
+ name: input.agentName,
644
+ system,
645
+ runtime: Object.assign(Object.assign({ provider: renderedConfig.provider, mode: renderedConfig.provider === "kognitive-voice" ? "pipeline" : "realtime", transport: (_l = pipeline === null || pipeline === void 0 ? void 0 : pipeline.transport.type) !== null && _l !== void 0 ? _l : renderedConfig.transport, model: (_m = pipeline === null || pipeline === void 0 ? void 0 : pipeline.llm.model) !== null && _m !== void 0 ? _m : renderedConfig.model, voice: (_o = pipeline === null || pipeline === void 0 ? void 0 : pipeline.tts.voice) !== null && _o !== void 0 ? _o : renderedConfig.voice, providerOptions: renderedConfig.providerOptions }, (pipeline ? { pipeline } : {})), { capabilities }),
646
+ voiceConfig: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ system, model: (_p = pipeline === null || pipeline === void 0 ? void 0 : pipeline.llm.model) !== null && _p !== void 0 ? _p : renderedConfig.model, voice: (_q = pipeline === null || pipeline === void 0 ? void 0 : pipeline.tts.voice) !== null && _q !== void 0 ? _q : renderedConfig.voice }, (speech ? { speech } : {})), (languageCode ? { languageCode } : {})), { turnDetection, transcription: (0, cloud_voice_runtime_service_1.toPreparedTranscription)(renderedConfig), inputNoiseReduction: (0, cloud_voice_runtime_service_1.normalizeCloudVoiceInputNoiseReduction)(renderedConfig.provider, channel, renderedConfig.inputNoiseReduction), maxOutputTokens }), (temperature !== undefined ? { temperature } : {})), (cartesiaTtsOptions ? { tts: { provider: "cartesia", options: cartesiaTtsOptions } } : {})),
647
+ tools: [],
648
+ toolManifest,
649
+ resourceId: input.resourceId,
650
+ parameters,
651
+ metadata: Object.assign({ cloudVoice: true, sessionId: input.sessionId, cloudVoiceConfigVersion: cloud_voice_runtime_service_1.CLOUD_VOICE_CONFIG_VERSION, promptCompilerVersion: cloud_voice_runtime_service_1.CLOUD_VOICE_PROMPT_COMPILER_VERSION, clientTools: ((_r = input.clientTools) !== null && _r !== void 0 ? _r : []).map((tool) => tool.id), transferDestinations: getTransferDestinations(renderedConfig).map((destination) => destination.id), parameterKeys: Object.keys(parameters), missingRequiredParameters: (_t = (_s = input.parameterResolution) === null || _s === void 0 ? void 0 : _s.missingRequired) !== null && _t !== void 0 ? _t : [], sensitiveParameterKeys: (_v = (_u = input.parameterResolution) === null || _u === void 0 ? void 0 : _u.sensitiveKeys) !== null && _v !== void 0 ? _v : [] }, (compiledFlow
652
+ ? {
653
+ flowGraph: {
654
+ startNodeId: compiledFlow.startNodeId,
655
+ entryMode: compiledFlow.entryMode,
656
+ nodeCount: compiledFlow.nodeCount,
657
+ edgeCount: compiledFlow.edgeCount,
658
+ referencedToolIds: compiledFlow.referencedToolIds,
659
+ missingToolIds: compiledFlow.missingToolIds,
660
+ },
661
+ }
662
+ : {})),
663
+ };
664
+ }
665
+ function createPhonePrepareSnapshot(input) {
666
+ var _a, _b;
667
+ return {
668
+ schemaVersion: 1,
669
+ createdAt: ((_a = input.now) !== null && _a !== void 0 ? _a : new Date()).toISOString(),
670
+ channel: input.channel,
671
+ agent: {
672
+ id: input.agent.id,
673
+ slug: input.agent.slug,
674
+ name: input.agent.name,
675
+ version: (_b = input.agent.publishedVersion) !== null && _b !== void 0 ? _b : input.agent.draftVersion,
676
+ },
677
+ runtime: input.prepare.runtime,
678
+ voiceConfig: input.prepare.voiceConfig,
679
+ toolManifest: input.prepare.toolManifest,
680
+ config: input.config,
681
+ parameters: input.prepare.parameters,
682
+ };
683
+ }