@niadra/sdk 0.1.0 → 0.7.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.
Files changed (133) hide show
  1. package/CHANGELOG.md +161 -20
  2. package/README.md +484 -38
  3. package/dist/ai-sdk.cjs +1037 -0
  4. package/dist/ai-sdk.cjs.map +1 -0
  5. package/dist/ai-sdk.d.cts +118 -0
  6. package/dist/ai-sdk.d.ts +118 -0
  7. package/dist/ai-sdk.js +1030 -0
  8. package/dist/ai-sdk.js.map +1 -0
  9. package/dist/anthropic.cjs +528 -0
  10. package/dist/anthropic.cjs.map +1 -0
  11. package/dist/anthropic.d.cts +35 -0
  12. package/dist/anthropic.d.ts +35 -0
  13. package/dist/anthropic.js +523 -0
  14. package/dist/anthropic.js.map +1 -0
  15. package/dist/bedrock.cjs +392 -0
  16. package/dist/bedrock.cjs.map +1 -0
  17. package/dist/bedrock.d.cts +25 -0
  18. package/dist/bedrock.d.ts +25 -0
  19. package/dist/bedrock.js +388 -0
  20. package/dist/bedrock.js.map +1 -0
  21. package/dist/cli.js +11045 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/client-DsIxZxZk.d.cts +6905 -0
  24. package/dist/client-DsIxZxZk.d.ts +6905 -0
  25. package/dist/cloudflare-agents.cjs +626 -0
  26. package/dist/cloudflare-agents.cjs.map +1 -0
  27. package/dist/cloudflare-agents.d.cts +113 -0
  28. package/dist/cloudflare-agents.d.ts +113 -0
  29. package/dist/cloudflare-agents.js +622 -0
  30. package/dist/cloudflare-agents.js.map +1 -0
  31. package/dist/elevenlabs.cjs +738 -0
  32. package/dist/elevenlabs.cjs.map +1 -0
  33. package/dist/elevenlabs.d.cts +86 -0
  34. package/dist/elevenlabs.d.ts +86 -0
  35. package/dist/elevenlabs.js +733 -0
  36. package/dist/elevenlabs.js.map +1 -0
  37. package/dist/genkit.cjs +323 -0
  38. package/dist/genkit.cjs.map +1 -0
  39. package/dist/genkit.d.cts +67 -0
  40. package/dist/genkit.d.ts +67 -0
  41. package/dist/genkit.js +318 -0
  42. package/dist/genkit.js.map +1 -0
  43. package/dist/google-adk.cjs +705 -0
  44. package/dist/google-adk.cjs.map +1 -0
  45. package/dist/google-adk.d.cts +91 -0
  46. package/dist/google-adk.d.ts +91 -0
  47. package/dist/google-adk.js +701 -0
  48. package/dist/google-adk.js.map +1 -0
  49. package/dist/google-genai.cjs +422 -0
  50. package/dist/google-genai.cjs.map +1 -0
  51. package/dist/google-genai.d.cts +26 -0
  52. package/dist/google-genai.d.ts +26 -0
  53. package/dist/google-genai.js +418 -0
  54. package/dist/google-genai.js.map +1 -0
  55. package/dist/index.cjs +11449 -1796
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +1006 -1247
  58. package/dist/index.d.ts +1006 -1247
  59. package/dist/index.js +11393 -1797
  60. package/dist/index.js.map +1 -1
  61. package/dist/intercept-0_lJE6k1.d.cts +20 -0
  62. package/dist/intercept-D7qFCaRb.d.ts +20 -0
  63. package/dist/langchain.cjs +1077 -0
  64. package/dist/langchain.cjs.map +1 -0
  65. package/dist/langchain.d.cts +102 -0
  66. package/dist/langchain.d.ts +102 -0
  67. package/dist/langchain.js +1068 -0
  68. package/dist/langchain.js.map +1 -0
  69. package/dist/livekit.cjs +404 -0
  70. package/dist/livekit.cjs.map +1 -0
  71. package/dist/livekit.d.cts +113 -0
  72. package/dist/livekit.d.ts +113 -0
  73. package/dist/livekit.js +398 -0
  74. package/dist/livekit.js.map +1 -0
  75. package/dist/llamaindex.cjs +349 -0
  76. package/dist/llamaindex.cjs.map +1 -0
  77. package/dist/llamaindex.d.cts +92 -0
  78. package/dist/llamaindex.d.ts +92 -0
  79. package/dist/llamaindex.js +344 -0
  80. package/dist/llamaindex.js.map +1 -0
  81. package/dist/mastra.cjs +1082 -0
  82. package/dist/mastra.cjs.map +1 -0
  83. package/dist/mastra.d.cts +86 -0
  84. package/dist/mastra.d.ts +86 -0
  85. package/dist/mastra.js +1075 -0
  86. package/dist/mastra.js.map +1 -0
  87. package/dist/openai-agents.cjs +465 -0
  88. package/dist/openai-agents.cjs.map +1 -0
  89. package/dist/openai-agents.d.cts +75 -0
  90. package/dist/openai-agents.d.ts +75 -0
  91. package/dist/openai-agents.js +459 -0
  92. package/dist/openai-agents.js.map +1 -0
  93. package/dist/retell.cjs +846 -0
  94. package/dist/retell.cjs.map +1 -0
  95. package/dist/retell.d.cts +161 -0
  96. package/dist/retell.d.ts +161 -0
  97. package/dist/retell.js +841 -0
  98. package/dist/retell.js.map +1 -0
  99. package/dist/shared-Bb5B59Bu.d.ts +39 -0
  100. package/dist/shared-DTPWVlWm.d.cts +39 -0
  101. package/dist/strands.cjs +352 -0
  102. package/dist/strands.cjs.map +1 -0
  103. package/dist/strands.d.cts +72 -0
  104. package/dist/strands.d.ts +72 -0
  105. package/dist/strands.js +347 -0
  106. package/dist/strands.js.map +1 -0
  107. package/dist/twilio.cjs +174 -0
  108. package/dist/twilio.cjs.map +1 -0
  109. package/dist/twilio.d.cts +64 -0
  110. package/dist/twilio.d.ts +64 -0
  111. package/dist/twilio.js +167 -0
  112. package/dist/twilio.js.map +1 -0
  113. package/dist/vapi.cjs +661 -0
  114. package/dist/vapi.cjs.map +1 -0
  115. package/dist/vapi.d.cts +78 -0
  116. package/dist/vapi.d.ts +78 -0
  117. package/dist/vapi.js +656 -0
  118. package/dist/vapi.js.map +1 -0
  119. package/dist/voltagent.cjs +509 -0
  120. package/dist/voltagent.cjs.map +1 -0
  121. package/dist/voltagent.d.cts +70 -0
  122. package/dist/voltagent.d.ts +70 -0
  123. package/dist/voltagent.js +503 -0
  124. package/dist/voltagent.js.map +1 -0
  125. package/dist/webhook-1ozGyksG.d.ts +37 -0
  126. package/dist/webhook-CG4om_DK.d.cts +37 -0
  127. package/dist/whatsapp.cjs +214 -0
  128. package/dist/whatsapp.cjs.map +1 -0
  129. package/dist/whatsapp.d.cts +81 -0
  130. package/dist/whatsapp.d.ts +81 -0
  131. package/dist/whatsapp.js +207 -0
  132. package/dist/whatsapp.js.map +1 -0
  133. package/package.json +355 -7
@@ -0,0 +1,846 @@
1
+ 'use strict';
2
+
3
+ // src/tools.ts
4
+ var TOOL_NAMES = {
5
+ search: "search_customer_history",
6
+ timeline: "get_customer_timeline",
7
+ open: "open_history_item"
8
+ };
9
+ var AGENT_MEMORY_TOOL_NAMES = {
10
+ search: "search_agent_memory",
11
+ remember: "remember"
12
+ };
13
+ var TOOL_DEFINITIONS = [
14
+ {
15
+ "type": "function",
16
+ "function": {
17
+ "name": "search_customer_history",
18
+ "description": "Search everything that already happened with this customer: past conversations, promises, agent actions, orders and invoices. Use it when the customer refers to something earlier or asks whether a problem happened before. Do not call it when the answer is already in the context block, including its 'Do hist\xF3rico' line, which already counts recurrences. Returns short items with date, channel and outcome, plus a recurrence count. Open one with open_history_item.",
19
+ "parameters": {
20
+ "type": "object",
21
+ "properties": {
22
+ "query": {
23
+ "type": "string",
24
+ "description": "What to look for, in the customer's words."
25
+ },
26
+ "filters": {
27
+ "type": "object",
28
+ "properties": {
29
+ "since": {
30
+ "type": "string",
31
+ "format": "date-time"
32
+ },
33
+ "until": {
34
+ "type": "string",
35
+ "format": "date-time"
36
+ },
37
+ "when": {
38
+ "type": "string",
39
+ "description": "The period in the customer's own words, as they said it: 'last week', 'semana passada', 'en marzo'."
40
+ },
41
+ "channels": {
42
+ "type": "array",
43
+ "items": {
44
+ "type": "string"
45
+ }
46
+ },
47
+ "categories": {
48
+ "type": "array",
49
+ "items": {
50
+ "type": "string"
51
+ }
52
+ },
53
+ "item_kinds": {
54
+ "type": "array",
55
+ "items": {
56
+ "enum": [
57
+ "episode",
58
+ "fact",
59
+ "open_item",
60
+ "action",
61
+ "object",
62
+ "trait"
63
+ ]
64
+ }
65
+ },
66
+ "outcome": {
67
+ "type": "string"
68
+ }
69
+ },
70
+ "additionalProperties": false
71
+ },
72
+ "max_tokens": {
73
+ "type": "integer",
74
+ "minimum": 50,
75
+ "maximum": 4e3
76
+ }
77
+ },
78
+ "required": [
79
+ "query"
80
+ ],
81
+ "additionalProperties": false
82
+ }
83
+ }
84
+ },
85
+ {
86
+ "type": "function",
87
+ "function": {
88
+ "name": "get_customer_timeline",
89
+ "description": "List this customer's conversations and agent actions in order, newest first, one line each. Use it to leaf through the history when you do not know what to search for. Pass next_cursor to continue. Prefer search_customer_history for a specific question.",
90
+ "parameters": {
91
+ "type": "object",
92
+ "properties": {
93
+ "cursor": {
94
+ "type": "string"
95
+ },
96
+ "limit": {
97
+ "type": "integer",
98
+ "minimum": 1,
99
+ "maximum": 100
100
+ },
101
+ "filters": {
102
+ "type": "object",
103
+ "properties": {
104
+ "since": {
105
+ "type": "string",
106
+ "format": "date-time"
107
+ },
108
+ "until": {
109
+ "type": "string",
110
+ "format": "date-time"
111
+ },
112
+ "when": {
113
+ "type": "string",
114
+ "description": "The period in the customer's own words, as they said it: 'last week', 'semana passada', 'en marzo'."
115
+ },
116
+ "channels": {
117
+ "type": "array",
118
+ "items": {
119
+ "type": "string"
120
+ }
121
+ },
122
+ "categories": {
123
+ "type": "array",
124
+ "items": {
125
+ "type": "string"
126
+ }
127
+ },
128
+ "item_kinds": {
129
+ "type": "array",
130
+ "items": {
131
+ "enum": [
132
+ "episode",
133
+ "fact",
134
+ "open_item",
135
+ "action",
136
+ "object",
137
+ "trait"
138
+ ]
139
+ }
140
+ },
141
+ "outcome": {
142
+ "type": "string"
143
+ }
144
+ },
145
+ "additionalProperties": false
146
+ }
147
+ },
148
+ "additionalProperties": false
149
+ }
150
+ }
151
+ },
152
+ {
153
+ "type": "function",
154
+ "function": {
155
+ "name": "open_history_item",
156
+ "description": "Open one conversation or business object returned by search_customer_history or get_customer_timeline: what was asked, what was promised and by whom, the outcome and what memory came from it. Use it only after a search or timeline pointed to the item.",
157
+ "parameters": {
158
+ "type": "object",
159
+ "properties": {
160
+ "id": {
161
+ "type": "string",
162
+ "description": "The item id, e.g. `episode:...`."
163
+ }
164
+ },
165
+ "required": [
166
+ "id"
167
+ ],
168
+ "additionalProperties": false
169
+ }
170
+ }
171
+ }
172
+ ];
173
+ var AGENT_MEMORY_TOOL_DEFINITIONS = [
174
+ {
175
+ "type": "function",
176
+ "function": {
177
+ "name": "search_agent_memory",
178
+ "description": "Search your own working notes: procedures, how the company's tools and processes behave, and known pitfalls. Use it before a task or a tool call you are unsure how to do. It holds nothing about customers; for the customer's history use search_customer_history.",
179
+ "parameters": {
180
+ "type": "object",
181
+ "properties": {
182
+ "query": {
183
+ "type": "string",
184
+ "description": "What you need to know how to do."
185
+ },
186
+ "tags": {
187
+ "type": "array",
188
+ "maxItems": 8,
189
+ "items": {
190
+ "type": "string",
191
+ "pattern": "^[a-z0-9][a-z0-9_.:-]{0,63}$"
192
+ },
193
+ "description": "Object types, operations or systems, e.g. `invoice`, `credit`, `erp`."
194
+ }
195
+ },
196
+ "required": [
197
+ "query"
198
+ ],
199
+ "additionalProperties": false
200
+ }
201
+ }
202
+ },
203
+ {
204
+ "type": "function",
205
+ "function": {
206
+ "name": "remember",
207
+ "description": "Save a working note for yourself and future runs: a procedure that worked, how a tool or process behaves, or a pitfall to avoid. Never write anything about a customer here: no names, phones, e-mails, documents, ids or words from the conversation. A note with personal data is refused. Write it so it helps with any customer.",
208
+ "parameters": {
209
+ "type": "object",
210
+ "properties": {
211
+ "kind": {
212
+ "enum": [
213
+ "procedure",
214
+ "tool_note",
215
+ "process_note",
216
+ "pitfall"
217
+ ]
218
+ },
219
+ "title": {
220
+ "type": "string",
221
+ "maxLength": 120
222
+ },
223
+ "body": {
224
+ "type": "string",
225
+ "maxLength": 2e3
226
+ },
227
+ "tags": {
228
+ "type": "array",
229
+ "maxItems": 8,
230
+ "items": {
231
+ "type": "string",
232
+ "pattern": "^[a-z0-9][a-z0-9_.:-]{0,63}$"
233
+ },
234
+ "description": "Object types, operations or systems, e.g. `invoice`, `credit`, `erp`."
235
+ }
236
+ },
237
+ "required": [
238
+ "kind",
239
+ "title",
240
+ "body"
241
+ ],
242
+ "additionalProperties": false
243
+ }
244
+ }
245
+ }
246
+ ];
247
+
248
+ // src/context.ts
249
+ function emptyResult(error) {
250
+ return { text: "", suffix: "", variables: {}, pack: null, source: "none", response: null, error, constraints: null, state: null, coordination: null };
251
+ }
252
+
253
+ // src/integrations/shared.ts
254
+ var ATTESTED = { A: "V2", B: "V1", C: "V1" };
255
+ function attestationProof(attestation) {
256
+ if (!attestation) return null;
257
+ const value = attestation.trim().toUpperCase();
258
+ if (value.includes("FAILED") || value.startsWith("NO-")) return null;
259
+ const letter = value.length === 1 ? value : /PASSED-([ABC])$/.exec(value)?.[1];
260
+ const level = letter ? ATTESTED[letter] : void 0;
261
+ return level ? { method: "network_attestation", level } : null;
262
+ }
263
+ function isConversation(session) {
264
+ return "customer" in session && typeof session.customer === "function";
265
+ }
266
+ function phoneHandle(value) {
267
+ const raw = value?.trim().replace(/^tel:/i, "").replace(/[\s().-]/g, "");
268
+ if (!raw) return null;
269
+ const e164 = raw.startsWith("+") ? raw : `+${raw}`;
270
+ return /^\+[1-9]\d{6,14}$/.test(e164) ? { type: "phone_e164", value: e164 } : null;
271
+ }
272
+ function errorName(error) {
273
+ return error instanceof Error ? error.name : typeof error;
274
+ }
275
+ var Bridge = class {
276
+ constructor(session, proof, memory = false) {
277
+ this.session = session;
278
+ this.proof = proof;
279
+ this.memory = memory;
280
+ }
281
+ session;
282
+ proof;
283
+ memory;
284
+ proving = null;
285
+ /** `begin()` started the first read of a call: the first `context()` waits for it with `ready()`. */
286
+ begun = false;
287
+ opened = false;
288
+ /**
289
+ * The context and, when enabled, the agent's notes, read side by side within the same budget.
290
+ * Never rejects.
291
+ */
292
+ async read(options = {}) {
293
+ const memoryParams = this.memory === false ? null : this.memory === true ? {} : withoutWrite(this.memory);
294
+ const [context, memory] = await Promise.all([
295
+ this.context(options),
296
+ memoryParams ? this.agentMemory(memoryParams, options) : Promise.resolve("")
297
+ ]);
298
+ return { context, memory, prefix: [memory, context.text].filter(Boolean).join("\n\n"), suffix: context.suffix };
299
+ }
300
+ get logger() {
301
+ return this.session.logger;
302
+ }
303
+ /**
304
+ * Starts the first read of a call now, in the background, after the proof when one was given (the
305
+ * pack depends on the level it proves): at call start, so the read runs while the call is set up.
306
+ * The first `context()` then waits for it within `timeouts.contextVoiceStart`. Never throws.
307
+ */
308
+ begin() {
309
+ const session = this.session;
310
+ if (!isConversation(session)) return;
311
+ const start = () => {
312
+ this.safe("start the first read", () => {
313
+ this.begun = session.begin();
314
+ });
315
+ };
316
+ if (this.proof === void 0 || this.proof === null) start();
317
+ else void this.verifyOnce().then(start);
318
+ }
319
+ /** Verifies once (when a proof was given), then reads the context. Never rejects. */
320
+ async context(options = {}) {
321
+ await this.verifyOnce();
322
+ try {
323
+ const session = this.session;
324
+ if (this.begun && !this.opened && isConversation(session)) {
325
+ this.opened = true;
326
+ await session.ready(options.timeout === void 0 ? {} : { timeout: options.timeout });
327
+ }
328
+ return await this.session.context(options);
329
+ } catch (error) {
330
+ this.logger.warn(`could not read context (${errorName(error)})`);
331
+ return emptyResult(null);
332
+ }
333
+ }
334
+ /** Records that `context` went into the prompt, unless it was empty for a reason other than the holdout. */
335
+ injected(context) {
336
+ if (!context.text && !context.suffix && context.response?.path !== "holdout") return;
337
+ this.safe("mark the injection", () => {
338
+ this.session.markInjected(context);
339
+ });
340
+ }
341
+ customer(text, options = {}) {
342
+ const session = this.session;
343
+ if (!text.trim() || !isConversation(session)) return;
344
+ this.safe("record the customer's turn", () => session.customer(text, options));
345
+ }
346
+ /** Sends the customer's turn so far, while they speak. In the background; never throws. */
347
+ prefetch(text) {
348
+ const session = this.session;
349
+ if (!text.trim() || !isConversation(session)) return;
350
+ this.safe("prefetch the turn", () => session.prefetch(text));
351
+ }
352
+ agent(text, options = {}) {
353
+ if (!text.trim()) return;
354
+ this.safe("record the agent's turn", () => this.session.agent(text, options));
355
+ }
356
+ /** Records a transfer. Tasks have no transfer; the call is ignored for them. */
357
+ async handoff(target, reason) {
358
+ const session = this.session;
359
+ if (!isConversation(session)) return;
360
+ try {
361
+ await session.handoff(reason ? { target, reason } : { target });
362
+ } catch (error) {
363
+ this.logger.warn(`could not record the handoff (${errorName(error)})`);
364
+ }
365
+ }
366
+ async end() {
367
+ try {
368
+ await this.session.end();
369
+ } catch (error) {
370
+ this.logger.warn(`could not end the session (${errorName(error)})`);
371
+ }
372
+ }
373
+ /** The navigation kit as plain specs (with the agent's memory tools when enabled), or none for a task about an object only. */
374
+ tools() {
375
+ let bound;
376
+ try {
377
+ const memory = this.memory;
378
+ bound = this.session.tools(memory === false ? {} : { agentMemory: true, writeAgentMemory: memory !== true && memory.write === true });
379
+ } catch (error) {
380
+ this.logger.warn(`could not build the tools (${errorName(error)})`);
381
+ return [];
382
+ }
383
+ return bound ? toolSpecs(bound) : [];
384
+ }
385
+ async agentMemory(params, options) {
386
+ try {
387
+ const result = await this.session.agentMemory(params, options.timeout === void 0 ? {} : { timeout: options.timeout });
388
+ return result.text;
389
+ } catch (error) {
390
+ this.logger.warn(`could not read the agent's memory (${errorName(error)})`);
391
+ return "";
392
+ }
393
+ }
394
+ async verifyOnce() {
395
+ if (this.proof === void 0 || this.proof === null) return;
396
+ this.proving ??= this.runVerify();
397
+ await this.proving;
398
+ }
399
+ async runVerify() {
400
+ try {
401
+ const source = this.proof;
402
+ const proof = typeof source === "function" ? await source() : source;
403
+ if (!proof) return;
404
+ await this.session.verify(proof);
405
+ } catch (error) {
406
+ this.logger.warn(`could not record the verification (${errorName(error)})`);
407
+ }
408
+ }
409
+ safe(what, run) {
410
+ try {
411
+ run();
412
+ } catch (error) {
413
+ this.logger.warn(`could not ${what} (${errorName(error)})`);
414
+ }
415
+ }
416
+ };
417
+ function withoutWrite(option) {
418
+ const { write: _, ...params } = option;
419
+ return params;
420
+ }
421
+ function toolSpecs(bound) {
422
+ return bound.definitions.map(({ function: definition }) => ({
423
+ name: definition.name,
424
+ description: definition.description,
425
+ parameters: definition.parameters,
426
+ execute: (args) => bound.call(definition.name, args)
427
+ }));
428
+ }
429
+ function isRecord(value) {
430
+ return typeof value === "object" && value !== null;
431
+ }
432
+
433
+ // src/integrations/webhook.ts
434
+ function memoryCallStore(max = 1e4) {
435
+ const calls = /* @__PURE__ */ new Map();
436
+ return {
437
+ get: (id) => calls.get(id),
438
+ set: (id, record) => {
439
+ calls.delete(id);
440
+ calls.set(id, record);
441
+ if (calls.size > max) {
442
+ const oldest = calls.keys().next().value;
443
+ if (oldest !== void 0) calls.delete(oldest);
444
+ }
445
+ }
446
+ };
447
+ }
448
+ function header(headers, name) {
449
+ if (typeof headers.get === "function") return headers.get(name) ?? void 0;
450
+ const wanted = name.toLowerCase();
451
+ for (const [key, value] of Object.entries(headers)) {
452
+ if (key.toLowerCase() !== wanted) continue;
453
+ return Array.isArray(value) ? value[0] : value;
454
+ }
455
+ return void 0;
456
+ }
457
+ function subtle() {
458
+ const crypto = globalThis.crypto;
459
+ if (!crypto?.subtle) throw new Error("Web Crypto is not available on this runtime");
460
+ return crypto.subtle;
461
+ }
462
+ var encoder = new TextEncoder();
463
+ async function hmac(hash, secret, message) {
464
+ const key = await subtle().importKey("raw", encoder.encode(secret), { name: "HMAC", hash }, false, ["sign"]);
465
+ return new Uint8Array(await subtle().sign("HMAC", key, encoder.encode(message)));
466
+ }
467
+ function hex(bytes) {
468
+ let out = "";
469
+ for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
470
+ return out;
471
+ }
472
+ function safeEqual(a, b) {
473
+ const left = encoder.encode(a);
474
+ const right = encoder.encode(b);
475
+ if (left.length !== right.length) return false;
476
+ let diff = 0;
477
+ for (let i = 0; i < left.length; i++) diff |= (left[i] ?? 0) ^ (right[i] ?? 0);
478
+ return diff === 0;
479
+ }
480
+ function bodyText(body) {
481
+ if (typeof body === "string") return body;
482
+ return new TextDecoder().decode(body instanceof Uint8Array ? body : new Uint8Array(body));
483
+ }
484
+ function parseJson(text) {
485
+ try {
486
+ return JSON.parse(text);
487
+ } catch {
488
+ return void 0;
489
+ }
490
+ }
491
+
492
+ // src/integrations/retell.ts
493
+ var OURS = /* @__PURE__ */ new Set([...Object.values(TOOL_NAMES), ...Object.values(AGENT_MEMORY_TOOL_NAMES)]);
494
+ var SIGNATURE_WINDOW_MS = 5 * 60 * 1e3;
495
+ function retell(options) {
496
+ const store = options.store ?? memoryCallStore();
497
+ const now = options.now ?? Date.now;
498
+ const logger = options.niadra.logger;
499
+ const readOptions = options.contextTimeout ? { timeout: options.contextTimeout } : {};
500
+ const transferred = /* @__PURE__ */ new Set();
501
+ const subjectOf = (call) => {
502
+ try {
503
+ if (options.subject) return options.subject(call) ?? null;
504
+ return phoneHandle(call.direction === "outbound" ? call.toNumber : call.fromNumber);
505
+ } catch {
506
+ return null;
507
+ }
508
+ };
509
+ const remember = async (id, record) => {
510
+ try {
511
+ await store.set(id, record);
512
+ } catch (error) {
513
+ logger.warn(`could not write the call store (${errorName(error)})`);
514
+ }
515
+ };
516
+ const recall = async (call) => {
517
+ try {
518
+ const stored = await store.get(call.id);
519
+ if (stored) return stored;
520
+ } catch (error) {
521
+ logger.warn(`could not read the call store (${errorName(error)})`);
522
+ }
523
+ const subject = subjectOf(call);
524
+ return subject ? { subject, verification: "V0" } : null;
525
+ };
526
+ const open = (id, record) => options.niadra.conversation({ subject: record.subject, channel: "voice", conversation_id: id, verification: record.verification });
527
+ const start = (call) => {
528
+ const subject = subjectOf(call);
529
+ if (!subject) return null;
530
+ const conversation = options.niadra.conversation({ subject, channel: "voice", conversation_id: call.id });
531
+ const bridge = new Bridge(conversation, options.verify ? () => options.verify?.(call) : void 0, options.agentMemory);
532
+ bridge.begin();
533
+ return { bridge, conversation };
534
+ };
535
+ const signed = async (text, headers) => validRetellSignature(text, header(headers, "x-retell-signature"), options.apiKey, now());
536
+ async function inbound(rawBody, headers) {
537
+ const text = bodyText(rawBody);
538
+ if (!await signed(text, headers)) return { status: 401, body: { error: "unauthorized" } };
539
+ const body = parseJson(text);
540
+ const data = isRecord(body) && isRecord(body.call_inbound) ? body.call_inbound : null;
541
+ if (!data) return { status: 400, body: { error: "invalid_body" } };
542
+ const call = callOf({ ...data, direction: "inbound" });
543
+ const variables = { niadra_context: "", niadra_turn: "" };
544
+ if (options.agentMemory) variables.niadra_agent_memory = "";
545
+ let extra = {};
546
+ try {
547
+ extra = call && options.inboundFields ? options.inboundFields(call) : {};
548
+ } catch (error) {
549
+ logger.warn(`could not build the inbound fields (${errorName(error)})`);
550
+ }
551
+ const answer = () => {
552
+ const own = isRecord(extra.dynamic_variables) ? extra.dynamic_variables : {};
553
+ return { status: 200, body: { call_inbound: { ...extra, dynamic_variables: { ...own, ...variables } } } };
554
+ };
555
+ const started = call ? start(call) : null;
556
+ if (!call || !started) return answer();
557
+ const read = await started.bridge.read(readOptions);
558
+ started.bridge.injected(read.context);
559
+ variables.niadra_context = read.context.text;
560
+ variables.niadra_turn = read.suffix;
561
+ if (options.agentMemory) variables.niadra_agent_memory = read.memory;
562
+ await remember(call.id, { subject: started.conversation.subject, verification: started.conversation.verification, stamp: started.conversation.contextStamp });
563
+ return answer();
564
+ }
565
+ async function webhook(rawBody, headers) {
566
+ const text = bodyText(rawBody);
567
+ if (!await signed(text, headers)) return { status: 401, body: { error: "unauthorized" } };
568
+ const body = parseJson(text);
569
+ const call = isRecord(body) ? callOf(body.call) : null;
570
+ if (!isRecord(body) || typeof body.event !== "string" || !call) return { status: 400, body: { error: "invalid_body" } };
571
+ switch (body.event) {
572
+ case "call_started":
573
+ return callStarted(call);
574
+ case "transfer_started":
575
+ await transfer(call);
576
+ return { status: 200, body: {} };
577
+ case "call_ended":
578
+ return callEnded(call);
579
+ default:
580
+ return { status: 200, body: { ignored: true } };
581
+ }
582
+ }
583
+ async function callStarted(call) {
584
+ try {
585
+ if (await store.get(call.id)) return { status: 200, body: {} };
586
+ } catch (error) {
587
+ logger.warn(`could not read the call store (${errorName(error)})`);
588
+ }
589
+ const started = start(call);
590
+ if (started) {
591
+ await started.bridge.context(readOptions);
592
+ await remember(call.id, { subject: started.conversation.subject, verification: started.conversation.verification, stamp: started.conversation.contextStamp });
593
+ }
594
+ return { status: 200, body: {} };
595
+ }
596
+ async function transfer(call) {
597
+ if (transferred.has(call.id)) return;
598
+ transferred.add(call.id);
599
+ if (transferred.size > 1e4) transferred.clear();
600
+ const record = await recall(call);
601
+ if (record) await new Bridge(open(call.id, record)).handoff("human", "transfer");
602
+ }
603
+ async function callEnded(call) {
604
+ const record = await recall(call);
605
+ if (!record) return { status: 200, body: { recorded: 0 } };
606
+ const bridge = new Bridge(open(call.id, record));
607
+ const started = typeof call.call.start_timestamp === "number" ? call.call.start_timestamp : null;
608
+ const utterances = Array.isArray(call.call.transcript_object) ? call.call.transcript_object : [];
609
+ let recorded = 0;
610
+ for (const [index, utterance] of utterances.entries()) {
611
+ if (recordUtterance(bridge, call.id, index, utterance, started, record)) recorded++;
612
+ }
613
+ if (call.call.disconnection_reason === "call_transfer") await transfer(call);
614
+ await bridge.end();
615
+ await options.niadra.flush();
616
+ return { status: 200, body: { recorded } };
617
+ }
618
+ async function tool(rawBody, headers) {
619
+ const text = bodyText(rawBody);
620
+ if (!await signed(text, headers)) return { status: 401, body: { error: "unauthorized" } };
621
+ const body = parseJson(text);
622
+ const call = isRecord(body) ? callOf(body.call) : null;
623
+ const name = isRecord(body) && typeof body.name === "string" ? body.name : "";
624
+ if (!isRecord(body) || !call || !name) return { status: 400, body: { error: "invalid_body" } };
625
+ const args = {};
626
+ if (isRecord(body.args)) Object.assign(args, body.args);
627
+ else for (const [key, value] of Object.entries(body)) if (key !== "name" && key !== "call") args[key] = value;
628
+ if (!OURS.has(name)) {
629
+ if (!options.otherTool) return { status: 200, body: { error: `unknown tool: ${name}` } };
630
+ try {
631
+ return { status: 200, body: await options.otherTool(name, args, call) ?? null };
632
+ } catch (error) {
633
+ logger.warn(`a tool outside Niadra failed (${errorName(error)})`);
634
+ return { status: 200, body: { error: "tool failed" } };
635
+ }
636
+ }
637
+ const record = await recall(call);
638
+ const spec = record ? new Bridge(open(call.id, record), void 0, options.agentMemory).tools().find((candidate) => candidate.name === name) : void 0;
639
+ if (!spec) return { status: 200, body: { error: "unavailable", detail: "customer history is unavailable right now" } };
640
+ return { status: 200, body: parseJson(await spec.execute(args)) ?? null };
641
+ }
642
+ function llm(callId, config) {
643
+ let bridge = null;
644
+ let record = null;
645
+ let recorded = 0;
646
+ const send = (event) => {
647
+ try {
648
+ config.send(event);
649
+ } catch (error) {
650
+ logger.warn(`could not send to Retell (${errorName(error)})`);
651
+ }
652
+ };
653
+ const ensure = async (call) => {
654
+ if (bridge) return bridge;
655
+ let stored;
656
+ try {
657
+ stored = await store.get(callId);
658
+ } catch (error) {
659
+ logger.warn(`could not read the call store (${errorName(error)})`);
660
+ }
661
+ if (stored) {
662
+ record = stored;
663
+ bridge = new Bridge(open(callId, stored), void 0, options.agentMemory);
664
+ bridge.begin();
665
+ return bridge;
666
+ }
667
+ const started = call && options.trustCallDetails ? start(call) : null;
668
+ if (!started) return null;
669
+ bridge = started.bridge;
670
+ await bridge.context(readOptions);
671
+ record = { subject: started.conversation.subject, verification: started.conversation.verification, stamp: started.conversation.contextStamp };
672
+ await remember(callId, record);
673
+ return bridge;
674
+ };
675
+ async function receive(event) {
676
+ try {
677
+ if (!isRecord(event) || typeof event.interaction_type !== "string") return null;
678
+ switch (event.interaction_type) {
679
+ case "ping_pong":
680
+ send({ response_type: "ping_pong", timestamp: event.timestamp });
681
+ return null;
682
+ case "call_details":
683
+ await ensure(callOf(event.call));
684
+ return null;
685
+ case "update_only":
686
+ await prefetchFor(event);
687
+ return null;
688
+ case "response_required":
689
+ case "reminder_required":
690
+ return await turnFor(event, event.interaction_type);
691
+ default:
692
+ return null;
693
+ }
694
+ } catch (error) {
695
+ logger.warn(`could not handle a Retell event (${errorName(error)})`);
696
+ return null;
697
+ }
698
+ }
699
+ async function prefetchFor(event) {
700
+ const transcript = Array.isArray(event.transcript) ? event.transcript : [];
701
+ const last = transcript[transcript.length - 1];
702
+ if (!isRecord(last) || last.role !== "user" || typeof last.content !== "string") return;
703
+ const current = await ensure(null);
704
+ current?.prefetch(last.content);
705
+ }
706
+ async function turnFor(event, interactionType) {
707
+ const responseId = typeof event.response_id === "number" ? event.response_id : 0;
708
+ const transcript = Array.isArray(event.transcript) ? event.transcript : [];
709
+ const current = await ensure(null);
710
+ let prefix = "";
711
+ let suffix = "";
712
+ let context = "";
713
+ if (current) {
714
+ for (let index = recorded; index < transcript.length; index++) {
715
+ recordUtterance(current, callId, index, transcript[index], null, record);
716
+ }
717
+ recorded = Math.max(recorded, transcript.length);
718
+ const read = await current.read(readOptions);
719
+ current.injected(read.context);
720
+ ({ prefix, suffix } = read);
721
+ context = read.context.text;
722
+ }
723
+ const messages = [];
724
+ if (config.instructions) messages.push({ role: "system", content: config.instructions });
725
+ if (prefix) messages.push({ role: "system", content: prefix });
726
+ for (const utterance of transcript) {
727
+ if (!isRecord(utterance) || typeof utterance.content !== "string") continue;
728
+ if (utterance.role === "user") messages.push({ role: "user", content: utterance.content });
729
+ else if (utterance.role === "agent") messages.push({ role: "assistant", content: utterance.content });
730
+ }
731
+ if (suffix) {
732
+ const last = messages.map((message2) => message2.role).lastIndexOf("user");
733
+ const message = messages[last];
734
+ if (message) messages[last] = { role: "user", content: `${message.content}
735
+
736
+ ${suffix}` };
737
+ else messages.push({ role: "user", content: suffix });
738
+ }
739
+ return {
740
+ responseId,
741
+ interactionType,
742
+ messages,
743
+ context,
744
+ suffix,
745
+ respond(content, respondOptions = {}) {
746
+ const response = {
747
+ response_type: "response",
748
+ response_id: responseId,
749
+ content,
750
+ content_complete: respondOptions.complete ?? true
751
+ };
752
+ if (respondOptions.endCall) response.end_call = true;
753
+ if (respondOptions.transferNumber) {
754
+ response.transfer_number = respondOptions.transferNumber;
755
+ void transferOnce();
756
+ }
757
+ send(response);
758
+ }
759
+ };
760
+ }
761
+ async function transferOnce() {
762
+ if (transferred.has(callId)) return;
763
+ transferred.add(callId);
764
+ await bridge?.handoff("human", "transfer");
765
+ }
766
+ return {
767
+ open(greeting) {
768
+ send({ response_type: "config", config: { auto_reconnect: true, call_details: true } });
769
+ if (greeting) send({ response_type: "response", response_id: 0, content: greeting, content_complete: true });
770
+ },
771
+ receive,
772
+ async close() {
773
+ try {
774
+ await options.niadra.flush();
775
+ } catch (error) {
776
+ logger.warn(`could not flush (${errorName(error)})`);
777
+ }
778
+ }
779
+ };
780
+ }
781
+ function toolConfigs(config) {
782
+ const memory = options.agentMemory;
783
+ const definitions = [
784
+ ...TOOL_DEFINITIONS,
785
+ ...memory ? AGENT_MEMORY_TOOL_DEFINITIONS.slice(0, memory !== true && memory.write ? 2 : 1) : []
786
+ ];
787
+ return definitions.map(({ function: definition }) => ({
788
+ type: "custom",
789
+ name: definition.name,
790
+ description: definition.description,
791
+ url: config.url,
792
+ method: "POST",
793
+ parameters: definition.parameters,
794
+ speak_during_execution: false,
795
+ speak_after_execution: true,
796
+ timeout_ms: config.timeoutMs ?? 1e4
797
+ }));
798
+ }
799
+ return { inbound, webhook, tool, llm, toolConfigs };
800
+ }
801
+ async function validRetellSignature(body, signature, apiKey, now = Date.now()) {
802
+ if (!signature || !apiKey) return false;
803
+ const match = /^v=(\d+),d=([0-9a-f]{64})$/i.exec(signature.trim());
804
+ if (!match) return false;
805
+ const [, stamp = "", digest = ""] = match;
806
+ if (Math.abs(now - Number(stamp)) > SIGNATURE_WINDOW_MS) return false;
807
+ return safeEqual(digest.toLowerCase(), hex(await hmac("SHA-256", apiKey, body + stamp)));
808
+ }
809
+ function recordUtterance(bridge, callId, index, utterance, started, record) {
810
+ if (!isRecord(utterance) || typeof utterance.content !== "string" || !utterance.content.trim()) return false;
811
+ const words = Array.isArray(utterance.words) ? utterance.words : [];
812
+ const first = isRecord(words[0]) && typeof words[0].start === "number" ? words[0].start : null;
813
+ const at = started !== null && first !== null ? new Date(started + first * 1e3) : void 0;
814
+ const base = { idempotency_key: `retell:${callId}:${String(index)}`, ...at ? { occurred_at: at } : {} };
815
+ if (utterance.role === "user") {
816
+ bridge.customer(utterance.content, base);
817
+ return true;
818
+ }
819
+ if (utterance.role === "agent") {
820
+ bridge.agent(utterance.content, record?.stamp ? { ...base, context_stamp: record.stamp } : base);
821
+ return true;
822
+ }
823
+ return false;
824
+ }
825
+ function callOf(value) {
826
+ if (!isRecord(value) || typeof value.call_id !== "string" || !value.call_id) return null;
827
+ const text = (key) => {
828
+ const field = value[key];
829
+ return typeof field === "string" && field ? field : void 0;
830
+ };
831
+ return {
832
+ id: value.call_id,
833
+ fromNumber: text("from_number"),
834
+ toNumber: text("to_number"),
835
+ direction: text("direction"),
836
+ agentId: text("agent_id"),
837
+ call: value
838
+ };
839
+ }
840
+
841
+ exports.attestationProof = attestationProof;
842
+ exports.memoryCallStore = memoryCallStore;
843
+ exports.retell = retell;
844
+ exports.validRetellSignature = validRetellSignature;
845
+ //# sourceMappingURL=retell.cjs.map
846
+ //# sourceMappingURL=retell.cjs.map