@guava-ai/guava-sdk 0.22.0 → 0.24.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 (57) hide show
  1. package/dist/examples/help-desk.js +22 -8
  2. package/dist/examples/help-desk.js.map +1 -1
  3. package/dist/examples/property-insurance.js +14 -3
  4. package/dist/examples/property-insurance.js.map +1 -1
  5. package/dist/examples/restaurant-waitlist.js +9 -1
  6. package/dist/examples/restaurant-waitlist.js.map +1 -1
  7. package/dist/examples/scheduling-outbound.js +2 -4
  8. package/dist/examples/scheduling-outbound.js.map +1 -1
  9. package/dist/src/action-item.d.ts +4 -4
  10. package/dist/src/action-item.js +1 -1
  11. package/dist/src/action-item.js.map +1 -1
  12. package/dist/src/agent.d.ts +21 -7
  13. package/dist/src/agent.js +275 -123
  14. package/dist/src/agent.js.map +1 -1
  15. package/dist/src/call.d.ts +9 -1
  16. package/dist/src/call.js +24 -1
  17. package/dist/src/call.js.map +1 -1
  18. package/dist/src/commands.d.ts +37 -9
  19. package/dist/src/commands.js +13 -3
  20. package/dist/src/commands.js.map +1 -1
  21. package/dist/src/events.d.ts +31 -1
  22. package/dist/src/events.js +11 -2
  23. package/dist/src/events.js.map +1 -1
  24. package/dist/src/health.d.ts +35 -0
  25. package/dist/src/health.js +99 -0
  26. package/dist/src/health.js.map +1 -0
  27. package/dist/src/helpers/index.d.ts +1 -0
  28. package/dist/src/helpers/index.js +9 -0
  29. package/dist/src/helpers/index.js.map +1 -0
  30. package/dist/src/helpers/llm.d.ts +33 -1
  31. package/dist/src/helpers/llm.js +220 -0
  32. package/dist/src/helpers/llm.js.map +1 -1
  33. package/dist/src/helpers/server-rag.d.ts +25 -0
  34. package/dist/src/helpers/server-rag.js +119 -0
  35. package/dist/src/helpers/server-rag.js.map +1 -0
  36. package/dist/src/socket/protocol.d.ts +4 -4
  37. package/dist/src/testing/mocks.d.ts +6 -0
  38. package/dist/src/testing/mocks.js +12 -0
  39. package/dist/src/testing/mocks.js.map +1 -1
  40. package/dist/src/version.d.ts +1 -1
  41. package/dist/src/version.js +1 -1
  42. package/examples/help-desk.ts +21 -12
  43. package/examples/property-insurance.ts +15 -3
  44. package/examples/restaurant-waitlist.ts +10 -1
  45. package/examples/scheduling-outbound.ts +2 -4
  46. package/package.json +5 -1
  47. package/src/action-item.ts +1 -1
  48. package/src/agent.ts +271 -129
  49. package/src/call.ts +37 -1
  50. package/src/commands.ts +16 -2
  51. package/src/events.ts +12 -1
  52. package/src/health.ts +120 -0
  53. package/src/helpers/index.ts +2 -0
  54. package/src/helpers/llm.ts +178 -1
  55. package/src/helpers/server-rag.ts +132 -0
  56. package/src/testing/mocks.ts +17 -0
  57. package/src/version.ts +1 -1
package/dist/src/agent.js CHANGED
@@ -124,20 +124,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
124
124
  Object.defineProperty(exports, "__esModule", { value: true });
125
125
  exports.Agent = void 0;
126
126
  const ws_1 = __importDefault(require("ws"));
127
- const index_ts_1 = require("./index.js");
128
- const logging_ts_1 = require("./logging.js");
129
- const utils_ts_1 = require("./utils.js");
130
- const webrtc_helper_ts_1 = require("./webrtc-helper.js");
131
127
  const commands_ts_1 = require("./commands.js");
132
128
  const events_ts_1 = require("./events.js");
133
- const telemetry_ts_1 = require("./telemetry.js");
134
- const client_ts_1 = require("./socket/client.js");
135
129
  const guavadialer_events_ts_1 = require("./guavadialer-events.js");
130
+ const health_ts_1 = require("./health.js");
131
+ const llm_ts_1 = require("./helpers/llm.js");
132
+ const index_ts_1 = require("./index.js");
133
+ const logging_ts_1 = require("./logging.js");
134
+ const client_ts_1 = require("./socket/client.js");
136
135
  const ListenInbound = __importStar(require("./socket/listen-inbound.js"));
137
- const session_ts_1 = require("./testing/session.js");
138
- const protocol_ts_1 = require("./testing/protocol.js");
136
+ const telemetry_ts_1 = require("./telemetry.js");
139
137
  const chat_ts_1 = require("./testing/chat.js");
140
- const llm_ts_1 = require("./helpers/llm.js");
138
+ const protocol_ts_1 = require("./testing/protocol.js");
139
+ const session_ts_1 = require("./testing/session.js");
140
+ const utils_ts_1 = require("./utils.js");
141
+ const webrtc_helper_ts_1 = require("./webrtc-helper.js");
141
142
  let Agent = (() => {
142
143
  let _classDecorators = [telemetry_ts_1.telemetryClient.trackClass()];
143
144
  let _classDescriptor;
@@ -155,6 +156,8 @@ let Agent = (() => {
155
156
  _name;
156
157
  _organization;
157
158
  _purpose;
159
+ _voice;
160
+ _acceptDtmfForNumbers;
158
161
  _logger;
159
162
  _client = new index_ts_1.Client();
160
163
  _onCallReceived = async () => ({
@@ -170,12 +173,16 @@ let Agent = (() => {
170
173
  _onActionRequested;
171
174
  _onActionGeneric;
172
175
  _onActionHandlers = {};
176
+ _onValidateHandlers = {};
173
177
  _onSessionEnd;
178
+ _onEscalate;
174
179
  _onDtmf;
175
180
  constructor(args) {
176
181
  this._name = args?.name;
177
182
  this._organization = args?.organization;
178
183
  this._purpose = args?.purpose;
184
+ this._voice = args?.voice;
185
+ this._acceptDtmfForNumbers = args?.acceptDtmf ?? true;
179
186
  this._logger = (0, logging_ts_1.getDefaultLogger)();
180
187
  }
181
188
  onCallReceived(callback) {
@@ -206,6 +213,9 @@ let Agent = (() => {
206
213
  this._onTaskCompleteGeneric = callbackOrTaskName;
207
214
  }
208
215
  }
216
+ onValidate(fieldKey, callback) {
217
+ this._onValidateHandlers[fieldKey] = callback;
218
+ }
209
219
  onSearchQuery(fieldKey, callback) {
210
220
  this._searchQueryHandlers[fieldKey] = callback;
211
221
  }
@@ -228,6 +238,9 @@ let Agent = (() => {
228
238
  onSessionEnd(callback) {
229
239
  this._onSessionEnd = callback;
230
240
  }
241
+ onEscalate(callback) {
242
+ this._onEscalate = callback;
243
+ }
231
244
  onDtmf(callback) {
232
245
  this._onDtmf = callback;
233
246
  }
@@ -292,18 +305,64 @@ let Agent = (() => {
292
305
  });
293
306
  }
294
307
  async listenPhone(phoneNumber) {
295
- return this._listenInbound({ agent_number: phoneNumber });
308
+ const env_1 = { stack: [], error: void 0, hasError: false };
309
+ try {
310
+ const healthCtx = new health_ts_1.HealthContext();
311
+ const _server = __addDisposableResource(env_1, await (0, health_ts_1.getHealthServer)(healthCtx), true);
312
+ return this._listenInbound(healthCtx, { agent_number: phoneNumber });
313
+ }
314
+ catch (e_1) {
315
+ env_1.error = e_1;
316
+ env_1.hasError = true;
317
+ }
318
+ finally {
319
+ const result_1 = __disposeResources(env_1);
320
+ if (result_1)
321
+ await result_1;
322
+ }
296
323
  }
297
324
  async listenWebrtc(webrtcCode) {
298
- if (!webrtcCode) {
299
- this._logger.info("No WebRTC code provided. Creating a temporary one.");
300
- webrtcCode = await this._client.createWebrtcAgent(3600);
325
+ const env_2 = { stack: [], error: void 0, hasError: false };
326
+ try {
327
+ if (!webrtcCode) {
328
+ this._logger.info("No WebRTC code provided. Creating a temporary one.");
329
+ webrtcCode = await this._client.createWebrtcAgent(3600);
330
+ }
331
+ const healthCtx = new health_ts_1.HealthContext();
332
+ const _server = __addDisposableResource(env_2, await (0, health_ts_1.getHealthServer)(healthCtx), true);
333
+ return this._listenInbound(healthCtx, { webrtc_code: webrtcCode });
334
+ }
335
+ catch (e_2) {
336
+ env_2.error = e_2;
337
+ env_2.hasError = true;
338
+ }
339
+ finally {
340
+ const result_2 = __disposeResources(env_2);
341
+ if (result_2)
342
+ await result_2;
343
+ }
344
+ }
345
+ async listenSip(sipCode) {
346
+ const env_3 = { stack: [], error: void 0, hasError: false };
347
+ try {
348
+ const healthCtx = new health_ts_1.HealthContext();
349
+ const _server = __addDisposableResource(env_3, await (0, health_ts_1.getHealthServer)(healthCtx), true);
350
+ return this._listenInbound(healthCtx, { sip_code: sipCode });
351
+ }
352
+ catch (e_3) {
353
+ env_3.error = e_3;
354
+ env_3.hasError = true;
355
+ }
356
+ finally {
357
+ const result_3 = __disposeResources(env_3);
358
+ if (result_3)
359
+ await result_3;
301
360
  }
302
- return this._listenInbound({ webrtc_code: webrtcCode });
303
361
  }
304
362
  async callLocal() {
305
363
  const webrtcCode = await this._client.createWebrtcAgent(300);
306
- this._listenInbound({ webrtc_code: webrtcCode }).catch((err) => {
364
+ // No health-server for call_local.
365
+ this._listenInbound(new health_ts_1.HealthContext(), { webrtc_code: webrtcCode }).catch((err) => {
307
366
  this._logger.error("Listen loop error: %s", err);
308
367
  });
309
368
  await (0, webrtc_helper_ts_1.runWebrtcHelper)(webrtcCode, (0, utils_ts_1.getBaseUrl)());
@@ -320,15 +379,31 @@ let Agent = (() => {
320
379
  }
321
380
  }
322
381
  else if (event.event_type === "task-done") {
323
- this._logger.info(`Task ${event.task_id} completed.`);
324
- if (this._onTaskCompleteGeneric !== undefined) {
325
- await this._onTaskCompleteGeneric(call, event.task_id);
382
+ const errors = [];
383
+ for (const fieldKey of call._fieldKeysByTaskId[event.task_id] ?? []) {
384
+ const handler = this._onValidateHandlers[fieldKey];
385
+ if (handler) {
386
+ const result = await handler(call, await call.getField(fieldKey));
387
+ if (result !== true) {
388
+ const [, error] = result;
389
+ errors.push(error);
390
+ }
391
+ }
326
392
  }
327
- else if (event.task_id in this._onTaskCompleteHandlers) {
328
- await this._onTaskCompleteHandlers[event.task_id](call);
393
+ if (errors.length > 0) {
394
+ await call.retryTask(errors.join(" "));
329
395
  }
330
396
  else {
331
- this._logger.warn(`No handler registered for completion of task '${event.task_id}'`);
397
+ this._logger.info(`Task ${event.task_id} completed.`);
398
+ if (this._onTaskCompleteGeneric !== undefined) {
399
+ await this._onTaskCompleteGeneric(call, event.task_id);
400
+ }
401
+ else if (event.task_id in this._onTaskCompleteHandlers) {
402
+ await this._onTaskCompleteHandlers[event.task_id](call);
403
+ }
404
+ else {
405
+ this._logger.warn(`No handler registered for completion of task '${event.task_id}'`);
406
+ }
332
407
  }
333
408
  }
334
409
  else if (event.event_type === "agent-question") {
@@ -379,15 +454,20 @@ let Agent = (() => {
379
454
  }
380
455
  else if (event.event_type === "action-request") {
381
456
  this._logger.info(`Received action request ${event.intent_id}: ${event.intent_summary}`);
382
- let suggestion;
457
+ let suggestions = [];
383
458
  if (this._onActionRequested !== undefined) {
384
- suggestion = await this._onActionRequested(call, event.intent_summary);
459
+ const result = await this._onActionRequested(call, event.intent_summary);
460
+ if (Array.isArray(result)) {
461
+ suggestions = result;
462
+ }
463
+ else if (result !== null && result !== undefined) {
464
+ suggestions = [result];
465
+ }
385
466
  }
386
467
  await call.sendCommand(commands_ts_1.ActionSuggestionCommand, {
387
468
  command_type: "action-suggestion",
388
469
  intent_id: event.intent_id,
389
- action_key: suggestion?.key ?? null,
390
- action_description: suggestion?.description ?? "",
470
+ actions: suggestions.map((s) => ({ key: s.key, description: s.description ?? "" })),
391
471
  });
392
472
  }
393
473
  else if (event.event_type === "execute-action") {
@@ -421,6 +501,17 @@ let Agent = (() => {
421
501
  await this._onDtmf(call, event);
422
502
  }
423
503
  }
504
+ else if (event.event_type === "escalate") {
505
+ if (this._onEscalate !== undefined) {
506
+ await this._onEscalate(call, event);
507
+ }
508
+ else if (event.requested_by === "agent") {
509
+ await call.sendInstruction("No escalation target set. Apologize for not being able to help, ask them to try calling another time, and hang up the call immediately.");
510
+ }
511
+ else {
512
+ await call.sendInstruction("Let them know there are no representatives available to take their call. Ask them if they would prefer to continue or to call another time.");
513
+ }
514
+ }
424
515
  else if (event.event_type === "error") {
425
516
  this._logger.error(`The Guava agent reported an error: ${event.content}`);
426
517
  }
@@ -428,30 +519,33 @@ let Agent = (() => {
428
519
  this._logger.warn(`The Guava agent reported a warning: ${event.content}`);
429
520
  }
430
521
  }
431
- async _initCall(variables = {}) {
432
- const call = new index_ts_1.Call(variables);
522
+ async _initCall(callId, callInfo, variables = {}) {
523
+ const call = new index_ts_1.Call(callId, callInfo, variables);
433
524
  await call.setPersona({
434
525
  agentName: this._name,
435
526
  agentPurpose: this._purpose,
436
527
  organizationName: this._organization,
528
+ voice: this._voice,
437
529
  });
438
530
  await call.sendCommand(commands_ts_1.RegisteredHooksCommand, {
439
531
  command_type: "registered-hooks",
440
532
  has_on_question: this._onQuestion !== undefined,
441
533
  has_on_intent: false,
442
534
  has_on_action_requested: this._onActionRequested !== undefined,
535
+ has_on_escalate: this._onEscalate !== undefined,
536
+ accept_dtmf_for_numbers: this._acceptDtmfForNumbers,
443
537
  });
444
538
  if (this._onCallStart !== undefined) {
445
539
  await this._onCallStart(call);
446
540
  }
447
541
  return call;
448
542
  }
449
- async _attachToCall(callId, initialVariables = {}, testSession, route = "v2/connect-call") {
450
- const env_1 = { stack: [], error: void 0, hasError: false };
543
+ async _attachToCall(callId, callInfo, initialVariables = {}, testSession, route = "v2/connect-call") {
544
+ const env_4 = { stack: [], error: void 0, hasError: false };
451
545
  try {
452
- const call = await this._initCall(initialVariables);
546
+ const call = await this._initCall(callId, callInfo, initialVariables);
453
547
  const url = new URL(`${route}/${callId}`, this._client.getWebsocketBase());
454
- const socket = __addDisposableResource(env_1, await new client_ts_1.GuavaSocket(`call-connection-${callId}`, url.toString(), this._client, (cmd) => cmd, (payload) => (0, events_ts_1.decodeEventDict)(payload), 18000).connect(), true);
548
+ const socket = __addDisposableResource(env_4, await new client_ts_1.GuavaSocket(`call-connection-${callId}`, url.toString(), this._client, (cmd) => cmd, (payload) => (0, events_ts_1.decodeEventDict)(payload), 18000).connect(), true);
455
549
  await call.setDrain(async (commands) => {
456
550
  for (const command of commands.splice(0)) {
457
551
  socket.send(command);
@@ -473,67 +567,79 @@ let Agent = (() => {
473
567
  throw e;
474
568
  }
475
569
  }
476
- catch (e_1) {
477
- env_1.error = e_1;
478
- env_1.hasError = true;
570
+ catch (e_4) {
571
+ env_4.error = e_4;
572
+ env_4.hasError = true;
479
573
  }
480
574
  finally {
481
- const result_1 = __disposeResources(env_1);
482
- if (result_1)
483
- await result_1;
575
+ const result_4 = __disposeResources(env_4);
576
+ if (result_4)
577
+ await result_4;
484
578
  }
485
579
  }
486
- async _listenInbound(conn) {
487
- const env_2 = { stack: [], error: void 0, hasError: false };
580
+ async _listenInbound(healthCtx, conn) {
581
+ const url = new URL("v2/listen-inbound", this._client.getWebsocketBase());
582
+ if ("agent_number" in conn) {
583
+ url.searchParams.set("phone_number", conn.agent_number);
584
+ }
585
+ else if ("webrtc_code" in conn) {
586
+ url.searchParams.set("webrtc_code", conn.webrtc_code);
587
+ }
588
+ else {
589
+ url.searchParams.set("sip_code", conn.sip_code);
590
+ }
488
591
  try {
489
- const url = new URL("v2/listen-inbound", this._client.getWebsocketBase());
490
- if ("agent_number" in conn) {
491
- url.searchParams.set("phone_number", conn.agent_number);
492
- }
493
- else {
494
- url.searchParams.set("webrtc_code", conn.webrtc_code);
495
- }
496
- const socket = __addDisposableResource(env_2, await new client_ts_1.GuavaSocket("listen-inbound", url.toString(), this._client, (msg) => msg, ListenInbound.decodeServerMessage).connect(), true);
592
+ const env_5 = { stack: [], error: void 0, hasError: false };
497
593
  try {
498
- for await (const msg of socket) {
499
- switch (msg.message_type) {
500
- case "listen-started":
501
- if ("agent_number" in conn) {
502
- this._logger.info("Listening on %s (%d other listeners).", conn.agent_number, msg.other_listeners);
503
- }
504
- else {
505
- this._logger.info("Listening on WebRTC code %s (%d other listeners).", conn.webrtc_code, msg.other_listeners);
506
- const debugUrl = new URL(`debug-webrtc?webrtc_code=${conn.webrtc_code}`, this._client.getHttpBase());
507
- this._logger.info("Call your agent at: %s", debugUrl);
594
+ const socket = __addDisposableResource(env_5, await new client_ts_1.GuavaSocket("listen-inbound", url.toString(), this._client, (msg) => msg, ListenInbound.decodeServerMessage).connect(), true);
595
+ try {
596
+ for await (const msg of socket) {
597
+ switch (msg.message_type) {
598
+ case "listen-started":
599
+ healthCtx.ready();
600
+ if ("agent_number" in conn) {
601
+ this._logger.info("Listening on %s (%d other listeners).", conn.agent_number, msg.other_listeners);
602
+ }
603
+ else if ("webrtc_code" in conn) {
604
+ this._logger.info("Listening on WebRTC code %s (%d other listeners).", conn.webrtc_code, msg.other_listeners);
605
+ const debugUrl = new URL(`debug-webrtc?webrtc_code=${conn.webrtc_code}`, this._client.getHttpBase());
606
+ this._logger.info("Call your agent at: %s", debugUrl);
607
+ }
608
+ else {
609
+ this._logger.info("Listening on SIP code %s (%d other listeners).", conn.sip_code, msg.other_listeners);
610
+ }
611
+ break;
612
+ case "incoming-call":
613
+ socket.send({ message_type: "claim-call", call_id: msg.call_id });
614
+ break;
615
+ case "assign-call": {
616
+ const { call_id, call_info } = msg;
617
+ this._logger.info("Received call (session ID: %s)", call_id);
618
+ this._handleAssignedCall(call_id, call_info, socket).catch((err) => {
619
+ this._logger.error("Error handling assigned call %s: %s", call_id, err);
620
+ });
621
+ break;
508
622
  }
509
- break;
510
- case "incoming-call":
511
- socket.send({ message_type: "claim-call", call_id: msg.call_id });
512
- break;
513
- case "assign-call": {
514
- const { call_id, call_info } = msg;
515
- this._logger.info("Received call (session ID: %s)", call_id);
516
- this._handleAssignedCall(call_id, call_info, socket).catch((err) => {
517
- this._logger.error("Error handling assigned call %s: %s", call_id, err);
518
- });
519
- break;
520
623
  }
521
624
  }
522
625
  }
626
+ catch (e) {
627
+ if (!(e instanceof client_ts_1.GuavaSocketClosedError))
628
+ throw e;
629
+ }
523
630
  }
524
- catch (e) {
525
- if (!(e instanceof client_ts_1.GuavaSocketClosedError))
526
- throw e;
631
+ catch (e_5) {
632
+ env_5.error = e_5;
633
+ env_5.hasError = true;
634
+ }
635
+ finally {
636
+ const result_5 = __disposeResources(env_5);
637
+ if (result_5)
638
+ await result_5;
527
639
  }
528
- }
529
- catch (e_2) {
530
- env_2.error = e_2;
531
- env_2.hasError = true;
532
640
  }
533
641
  finally {
534
- const result_2 = __disposeResources(env_2);
535
- if (result_2)
536
- await result_2;
642
+ healthCtx.stopped();
537
643
  }
538
644
  }
539
645
  async _handleAssignedCall(callId, callInfo, socket, initialVariables = {}) {
@@ -545,7 +651,7 @@ let Agent = (() => {
545
651
  else {
546
652
  this._logger.info("Accepting call %s.", callId);
547
653
  socket.send({ message_type: "answer-call", call_id: callId });
548
- await this._attachToCall(callId, initialVariables);
654
+ await this._attachToCall(callId, callInfo, initialVariables);
549
655
  }
550
656
  }
551
657
  /**
@@ -562,7 +668,13 @@ let Agent = (() => {
562
668
  });
563
669
  const { call_id } = (await response.json());
564
670
  this._logger.info("Outbound call created with session ID: %s", call_id);
565
- await this._attachToCall(call_id, variables);
671
+ const callInfo = {
672
+ call_type: "pstn",
673
+ from_number: fromNumber ?? null,
674
+ to_number: toNumber,
675
+ caller_id: null,
676
+ };
677
+ await this._attachToCall(call_id, callInfo, variables);
566
678
  }
567
679
  /**
568
680
  * Run the agent against a live test session.
@@ -594,7 +706,13 @@ let Agent = (() => {
594
706
  });
595
707
  const sessionStarted = protocol_ts_1.SessionStarted.parse(JSON.parse(rawFirst));
596
708
  const testSession = new session_ts_1.TestSession(ws, this._client);
597
- const attachPromise = this._attachToCall(sessionStarted.session_id, variables, testSession).catch((err) => {
709
+ const testCallInfo = {
710
+ call_type: "pstn",
711
+ from_number: null,
712
+ to_number: "+15555555555",
713
+ caller_id: null,
714
+ };
715
+ const attachPromise = this._attachToCall(sessionStarted.session_id, testCallInfo, variables, testSession).catch((err) => {
598
716
  this._logger.error("Error in _attachToCall during test: %s", err);
599
717
  });
600
718
  try {
@@ -620,12 +738,12 @@ let Agent = (() => {
620
738
  * pass/fail criteria, or `session.getTranscript()` to inspect the conversation.
621
739
  *
622
740
  * @example
623
- * const session = await agent.testRoleplay(
741
+ * const session = await agent.roleplay(
624
742
  * "You are a caller trying to buy a new table.",
625
743
  * );
626
744
  * assert(session.executedActions.includes("sales"));
627
745
  */
628
- async testRoleplay(roleplayPrompt, variables = {}) {
746
+ async roleplay(roleplayPrompt, variables = {}) {
629
747
  const roleplaySchema = {
630
748
  type: "object",
631
749
  properties: {
@@ -682,6 +800,10 @@ Choose "speak" and provide your next utterance, or choose "hangup" if the conver
682
800
  }
683
801
  }, variables);
684
802
  }
803
+ /** @deprecated Use {@link roleplay} instead. */
804
+ async testRoleplay(roleplayPrompt, variables = {}) {
805
+ return this.roleplay(roleplayPrompt, variables);
806
+ }
685
807
  /**
686
808
  * Start an interactive terminal chat session with the agent.
687
809
  *
@@ -712,6 +834,8 @@ Choose "speak" and provide your next utterance, or choose "hangup" if the conver
712
834
  name: this._name,
713
835
  organization: this._organization,
714
836
  purpose: this._purpose,
837
+ voice: this._voice,
838
+ acceptDtmf: this._acceptDtmfForNumbers,
715
839
  });
716
840
  cloned._onCallReceived = this._onCallReceived;
717
841
  cloned._onCallStart = this._onCallStart;
@@ -721,61 +845,75 @@ Choose "speak" and provide your next utterance, or choose "hangup" if the conver
721
845
  cloned._onTaskCompleteGeneric = this._onTaskCompleteGeneric;
722
846
  cloned._onTaskCompleteHandlers = { ...this._onTaskCompleteHandlers };
723
847
  cloned._searchQueryHandlers = { ...this._searchQueryHandlers };
848
+ cloned._onValidateHandlers = { ...this._onValidateHandlers };
724
849
  cloned._onActionRequested = this._onActionRequested;
725
850
  cloned._onActionGeneric = this._onActionGeneric;
726
851
  cloned._onActionHandlers = { ...this._onActionHandlers };
727
852
  cloned._onSessionEnd = this._onSessionEnd;
853
+ cloned._onEscalate = this._onEscalate;
728
854
  cloned._onDtmf = this._onDtmf;
729
855
  return cloned;
730
856
  }
731
- async _serveCampaign(campaignCode) {
732
- const env_3 = { stack: [], error: void 0, hasError: false };
857
+ async _serveCampaign(healthCtx, campaignCode) {
733
858
  try {
734
- const campaignUrl = new URL(`v1/campaigns/${campaignCode}`, this._client.getHttpBase());
735
- const campaignResponse = await (0, utils_ts_1.fetchOrThrow)(campaignUrl, {
736
- headers: await this._client.headers(),
737
- });
738
- const campaign = (await campaignResponse.json());
739
- const wsUrl = new URL(`v1/serve-campaign/${campaign.id}`, this._client.getWebsocketBase());
740
- this._logger.info("Connecting to campaign '%s' (id: %s).", campaign.name, campaign.id);
741
- const socket = __addDisposableResource(env_3, await new client_ts_1.GuavaSocket("serve-campaign", wsUrl.toString(), this._client, (msg) => msg, guavadialer_events_ts_1.decodeServerMessage).connect(), true);
742
- const activeCalls = [];
859
+ const env_6 = { stack: [], error: void 0, hasError: false };
743
860
  try {
744
- for await (const msg of socket) {
745
- switch (msg.message_type) {
746
- case "listen-started":
747
- this._logger.info("Listening for calls on campaign '%s'. Ready.", campaign.name);
748
- break;
749
- case "initiate-and-assign-call": {
750
- const { call_id, contact_data } = msg;
751
- const data = contact_data;
752
- const logPhone = data?.phone_number ?? "?";
753
- this._logger.info("Ready to make call, id %s — initiating call setup and dispatch for contact %s.", call_id, logPhone);
754
- activeCalls.push((async () => {
755
- socket.send({ message_type: "controller-ready", call_id });
756
- const variables = data?.data ?? {};
757
- await this._attachToCall(call_id, variables, undefined, "v2/connect-campaign-call");
758
- })());
759
- break;
861
+ const campaignUrl = new URL(`v1/campaigns/${campaignCode}`, this._client.getHttpBase());
862
+ const campaignResponse = await (0, utils_ts_1.fetchOrThrow)(campaignUrl, {
863
+ headers: await this._client.headers(),
864
+ });
865
+ const campaign = (await campaignResponse.json());
866
+ const wsUrl = new URL(`v1/serve-campaign/${campaign.id}`, this._client.getWebsocketBase());
867
+ this._logger.info("Connecting to campaign '%s' (id: %s).", campaign.name, campaign.id);
868
+ const socket = __addDisposableResource(env_6, await new client_ts_1.GuavaSocket("serve-campaign", wsUrl.toString(), this._client, (msg) => msg, guavadialer_events_ts_1.decodeServerMessage).connect(), true);
869
+ const activeCalls = [];
870
+ try {
871
+ for await (const msg of socket) {
872
+ switch (msg.message_type) {
873
+ case "listen-started":
874
+ this._logger.info("Listening for calls on campaign '%s'. Ready.", campaign.name);
875
+ healthCtx.ready();
876
+ break;
877
+ case "initiate-and-assign-call": {
878
+ const { call_id, contact_data } = msg;
879
+ const data = contact_data;
880
+ const logPhone = data?.phone_number ?? "?";
881
+ this._logger.info("Ready to make call, id %s — initiating call setup and dispatch for contact %s.", call_id, logPhone);
882
+ activeCalls.push((async () => {
883
+ socket.send({ message_type: "controller-ready", call_id });
884
+ const variables = data?.data ?? {};
885
+ const campaignCallInfo = {
886
+ call_type: "pstn",
887
+ from_number: null,
888
+ to_number: data?.phone_number ?? "",
889
+ caller_id: null,
890
+ };
891
+ await this._attachToCall(call_id, campaignCallInfo, variables, undefined, "v2/connect-campaign-call");
892
+ })());
893
+ break;
894
+ }
760
895
  }
761
896
  }
762
897
  }
898
+ catch (e) {
899
+ if (!(e instanceof client_ts_1.GuavaSocketClosedError))
900
+ throw e;
901
+ this._logger.info("Campaign '%s' disconnected.", campaign.name);
902
+ }
903
+ await Promise.all(activeCalls);
763
904
  }
764
- catch (e) {
765
- if (!(e instanceof client_ts_1.GuavaSocketClosedError))
766
- throw e;
767
- this._logger.info("Campaign '%s' disconnected.", campaign.name);
905
+ catch (e_6) {
906
+ env_6.error = e_6;
907
+ env_6.hasError = true;
908
+ }
909
+ finally {
910
+ const result_6 = __disposeResources(env_6);
911
+ if (result_6)
912
+ await result_6;
768
913
  }
769
- await Promise.all(activeCalls);
770
- }
771
- catch (e_3) {
772
- env_3.error = e_3;
773
- env_3.hasError = true;
774
914
  }
775
915
  finally {
776
- const result_3 = __disposeResources(env_3);
777
- if (result_3)
778
- await result_3;
916
+ healthCtx.stopped();
779
917
  }
780
918
  }
781
919
  /**
@@ -790,7 +928,21 @@ Choose "speak" and provide your next utterance, or choose "hangup" if the conver
790
928
  * await agent.attachCampaign("gcmp-abc123");
791
929
  */
792
930
  async attachCampaign(campaignCode) {
793
- return this._serveCampaign(campaignCode);
931
+ const env_7 = { stack: [], error: void 0, hasError: false };
932
+ try {
933
+ const healthCtx = new health_ts_1.HealthContext();
934
+ const _server = __addDisposableResource(env_7, await (0, health_ts_1.getHealthServer)(healthCtx), true);
935
+ return this._serveCampaign(healthCtx, campaignCode);
936
+ }
937
+ catch (e_7) {
938
+ env_7.error = e_7;
939
+ env_7.hasError = true;
940
+ }
941
+ finally {
942
+ const result_7 = __disposeResources(env_7);
943
+ if (result_7)
944
+ await result_7;
945
+ }
794
946
  }
795
947
  /* ===== Aliases to be removed at some point. ===== */
796
948
  /** @deprecated Use {@link listenPhone} instead. */