@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.
- package/dist/examples/help-desk.js +22 -8
- package/dist/examples/help-desk.js.map +1 -1
- package/dist/examples/property-insurance.js +14 -3
- package/dist/examples/property-insurance.js.map +1 -1
- package/dist/examples/restaurant-waitlist.js +9 -1
- package/dist/examples/restaurant-waitlist.js.map +1 -1
- package/dist/examples/scheduling-outbound.js +2 -4
- package/dist/examples/scheduling-outbound.js.map +1 -1
- package/dist/src/action-item.d.ts +4 -4
- package/dist/src/action-item.js +1 -1
- package/dist/src/action-item.js.map +1 -1
- package/dist/src/agent.d.ts +21 -7
- package/dist/src/agent.js +275 -123
- package/dist/src/agent.js.map +1 -1
- package/dist/src/call.d.ts +9 -1
- package/dist/src/call.js +24 -1
- package/dist/src/call.js.map +1 -1
- package/dist/src/commands.d.ts +37 -9
- package/dist/src/commands.js +13 -3
- package/dist/src/commands.js.map +1 -1
- package/dist/src/events.d.ts +31 -1
- package/dist/src/events.js +11 -2
- package/dist/src/events.js.map +1 -1
- package/dist/src/health.d.ts +35 -0
- package/dist/src/health.js +99 -0
- package/dist/src/health.js.map +1 -0
- package/dist/src/helpers/index.d.ts +1 -0
- package/dist/src/helpers/index.js +9 -0
- package/dist/src/helpers/index.js.map +1 -0
- package/dist/src/helpers/llm.d.ts +33 -1
- package/dist/src/helpers/llm.js +220 -0
- package/dist/src/helpers/llm.js.map +1 -1
- package/dist/src/helpers/server-rag.d.ts +25 -0
- package/dist/src/helpers/server-rag.js +119 -0
- package/dist/src/helpers/server-rag.js.map +1 -0
- package/dist/src/socket/protocol.d.ts +4 -4
- package/dist/src/testing/mocks.d.ts +6 -0
- package/dist/src/testing/mocks.js +12 -0
- package/dist/src/testing/mocks.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/examples/help-desk.ts +21 -12
- package/examples/property-insurance.ts +15 -3
- package/examples/restaurant-waitlist.ts +10 -1
- package/examples/scheduling-outbound.ts +2 -4
- package/package.json +5 -1
- package/src/action-item.ts +1 -1
- package/src/agent.ts +271 -129
- package/src/call.ts +37 -1
- package/src/commands.ts +16 -2
- package/src/events.ts +12 -1
- package/src/health.ts +120 -0
- package/src/helpers/index.ts +2 -0
- package/src/helpers/llm.ts +178 -1
- package/src/helpers/server-rag.ts +132 -0
- package/src/testing/mocks.ts +17 -0
- 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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
328
|
-
await
|
|
393
|
+
if (errors.length > 0) {
|
|
394
|
+
await call.retryTask(errors.join(" "));
|
|
329
395
|
}
|
|
330
396
|
else {
|
|
331
|
-
this._logger.
|
|
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
|
|
457
|
+
let suggestions = [];
|
|
383
458
|
if (this._onActionRequested !== undefined) {
|
|
384
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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 (
|
|
477
|
-
|
|
478
|
-
|
|
570
|
+
catch (e_4) {
|
|
571
|
+
env_4.error = e_4;
|
|
572
|
+
env_4.hasError = true;
|
|
479
573
|
}
|
|
480
574
|
finally {
|
|
481
|
-
const
|
|
482
|
-
if (
|
|
483
|
-
await
|
|
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
|
|
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
|
|
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
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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 (
|
|
525
|
-
|
|
526
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
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 (
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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. */
|