@guava-ai/guava-sdk 0.10.0 → 0.11.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 (65) hide show
  1. package/README.md +1 -1
  2. package/bin/example-runner.ts +4 -4
  3. package/dist/bin/example-runner.js +4 -4
  4. package/dist/bin/example-runner.js.map +1 -1
  5. package/dist/examples/help-desk.js +71 -0
  6. package/dist/examples/help-desk.js.map +1 -0
  7. package/dist/examples/property-insurance.js +14 -22
  8. package/dist/examples/property-insurance.js.map +1 -1
  9. package/dist/examples/restaurant-waitlist.js +74 -0
  10. package/dist/examples/restaurant-waitlist.js.map +1 -0
  11. package/dist/examples/scheduling-outbound.js +30 -54
  12. package/dist/examples/scheduling-outbound.js.map +1 -1
  13. package/dist/src/{action_item.d.ts → action-item.d.ts} +2 -0
  14. package/dist/src/{action_item.js → action-item.js} +3 -1
  15. package/dist/src/action-item.js.map +1 -0
  16. package/dist/src/agent.d.ts +72 -0
  17. package/dist/src/agent.js +444 -0
  18. package/dist/src/agent.js.map +1 -0
  19. package/dist/src/call-controller.d.ts +1 -1
  20. package/dist/src/call-controller.js +1 -1
  21. package/dist/src/call.d.ts +73 -0
  22. package/dist/src/call.js +252 -0
  23. package/dist/src/call.js.map +1 -0
  24. package/dist/src/commands.d.ts +95 -0
  25. package/dist/src/commands.js +24 -2
  26. package/dist/src/commands.js.map +1 -1
  27. package/dist/src/events.d.ts +25 -0
  28. package/dist/src/events.js +12 -1
  29. package/dist/src/events.js.map +1 -1
  30. package/dist/src/example-data.d.ts +1 -0
  31. package/dist/src/example-data.js +41 -1
  32. package/dist/src/example-data.js.map +1 -1
  33. package/dist/src/index.d.ts +14 -5
  34. package/dist/src/index.js +7 -2
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/logging.js +1 -1
  37. package/dist/src/logging.js.map +1 -1
  38. package/dist/src/version.d.ts +1 -1
  39. package/dist/src/version.js +1 -1
  40. package/dist/src/version.js.map +1 -1
  41. package/examples/README.md +6 -0
  42. package/examples/help-desk.ts +60 -0
  43. package/examples/property-insurance.ts +14 -30
  44. package/examples/restaurant-waitlist.ts +47 -0
  45. package/examples/scheduling-outbound.ts +40 -76
  46. package/package.json +2 -1
  47. package/src/{action_item.ts → action-item.ts} +3 -0
  48. package/src/agent.ts +439 -0
  49. package/src/call-controller.ts +1 -1
  50. package/src/call.ts +279 -0
  51. package/src/commands.ts +31 -1
  52. package/src/events.ts +15 -0
  53. package/src/example-data.ts +41 -0
  54. package/src/index.ts +7 -5
  55. package/src/logging.ts +1 -1
  56. package/src/version.ts +1 -1
  57. package/dist/examples/credit-card-activation.js +0 -177
  58. package/dist/examples/credit-card-activation.js.map +0 -1
  59. package/dist/examples/thai-palace.js +0 -94
  60. package/dist/examples/thai-palace.js.map +0 -1
  61. package/dist/src/action_item.js.map +0 -1
  62. package/examples/credit-card-activation.ts +0 -178
  63. package/examples/thai-palace.ts +0 -67
  64. /package/dist/examples/{credit-card-activation.d.ts → help-desk.d.ts} +0 -0
  65. /package/dist/examples/{thai-palace.d.ts → restaurant-waitlist.d.ts} +0 -0
package/src/call.ts ADDED
@@ -0,0 +1,279 @@
1
+ import { type Logger, getDefaultLogger } from "./logging.ts";
2
+ import {
3
+ type Command,
4
+ SetPersona,
5
+ SetLanguageModeCommand,
6
+ type Language,
7
+ SetTaskCommand,
8
+ SendInstructionCommand,
9
+ TransferCommand,
10
+ ReadScriptCommand,
11
+ RetryTaskCommand,
12
+ } from "./commands.ts";
13
+ import type * as z from "zod";
14
+ import type {
15
+ ActionItem,
16
+ FieldItem,
17
+ SayItem,
18
+ SerializableFieldItem,
19
+ TodoItem,
20
+ } from "./action-item.ts";
21
+ import { Say } from "./action-item.ts";
22
+ import { telemetryClient } from "./telemetry.ts";
23
+
24
+ export type TaskObjective =
25
+ | { objective: string }
26
+ | { objective?: string; checklist: (FieldItem | SayItem | string)[] };
27
+
28
+ export type ReachPersonOutcome = {
29
+ key: string;
30
+ description?: string;
31
+ nextActionPreview?: string;
32
+ };
33
+
34
+ @telemetryClient.trackClass()
35
+ export class Call {
36
+ private _commandQueue: Command[] = [];
37
+ private _variables: Record<string, any> = {};
38
+ protected logger: Logger;
39
+
40
+ // drain functions are expected to cleanup
41
+ // the part of the queue that is successfully sent from its
42
+ // input (mutating it) (i.e. _drain should use Array.splice)
43
+ private _drain?: (_: Command[]) => Promise<void>;
44
+ _fieldValues: Record<string, unknown> = {};
45
+
46
+ constructor(variables: Record<string, any> = {}, logger: Logger = getDefaultLogger()) {
47
+ // Set initial variables.
48
+ this._variables = { ...variables };
49
+
50
+ // Set up the default logger.
51
+ this.logger = logger;
52
+ }
53
+
54
+ /**
55
+ * @description Supply a function used to consume commands from the internal command queue.
56
+ *
57
+ * The function is expected to remove from the argument array commands that it has handled (iterating
58
+ * through the result of `Array.splice(0)` is sufficient)
59
+ */
60
+ async setDrain(newDrain: (_: Command[]) => Promise<void>) {
61
+ this._drain = newDrain;
62
+ await this.flush();
63
+ }
64
+
65
+ private async flush() {
66
+ await this._drain?.call(this, this._commandQueue);
67
+ }
68
+
69
+ async getField(key: string) {
70
+ // Async since the implementation is likely to become async in teh future.
71
+ if (key in this._fieldValues) {
72
+ return this._fieldValues[key];
73
+ } else {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ async sendCommand<C extends Command, Schema extends z.ZodType<C>>(
79
+ schema: Schema,
80
+ data: z.input<Schema>,
81
+ ) {
82
+ const command = schema.parse(data);
83
+ this._commandQueue.push(command);
84
+ await this.flush();
85
+ }
86
+
87
+ async setLanguageMode(args: { primary?: Language; secondary?: Language[] }) {
88
+ await this.sendCommand(SetLanguageModeCommand, {
89
+ command_type: "set-language-mode",
90
+ primary: args.primary ?? "english",
91
+ secondary: args.secondary ?? [],
92
+ });
93
+ }
94
+
95
+ /**
96
+ * @description provide identifiers the agent will use to identify the virtual agent
97
+ */
98
+ async setPersona(args: {
99
+ organizationName?: string;
100
+ agentName?: string;
101
+ agentPurpose?: string;
102
+ voice?: string;
103
+ }) {
104
+ await this.sendCommand(SetPersona, {
105
+ command_type: "set-persona",
106
+ organization_name: args.organizationName,
107
+ agent_name: args.agentName,
108
+ agent_purpose: args.agentPurpose,
109
+ voice: args.voice,
110
+ });
111
+ }
112
+
113
+ /**
114
+ * @description direct the agent to collect information
115
+ * @param taskArgs.task_id unique identifier for this task
116
+ * @param taskArgs.objective high-level goal for the agent
117
+ * @param taskArgs.checklist ordered list of fields, statements, or instructions to collect
118
+ */
119
+ async setTask(taskArgs: {
120
+ taskId: string;
121
+ objective?: string;
122
+ checklist?: (FieldItem | SayItem | string)[];
123
+ completionCriteria?: string;
124
+ }) {
125
+ const { taskId, objective = "", checklist = [], completionCriteria } = taskArgs;
126
+
127
+ if (!objective && checklist.length === 0) {
128
+ throw new Error("At least one of ['objective', 'checklist'] must be provided.");
129
+ }
130
+
131
+ const action_items = checklist.map((item): ActionItem => {
132
+ if (typeof item === "string") {
133
+ return { item_type: "todo", description: item } satisfies TodoItem;
134
+ }
135
+ if (item.item_type === "field") {
136
+ if (item.choiceGenerator) {
137
+ throw new Error(
138
+ "choiceGenerator is not compatible with the Agent / Call API. Use searchable=true and register a handler.",
139
+ );
140
+ }
141
+ const { choiceGenerator: _, ...fieldData } = item;
142
+ return { ...fieldData, is_search_field: item.searchable } satisfies SerializableFieldItem;
143
+ }
144
+ return item;
145
+ });
146
+
147
+ await this.sendCommand(SetTaskCommand, {
148
+ command_type: "set-task",
149
+ task_id: taskId,
150
+ objective,
151
+ action_items,
152
+ completion_criteria: completionCriteria,
153
+ });
154
+ }
155
+
156
+ async transfer(destination: string, instructions?: string) {
157
+ await this.sendCommand(TransferCommand, {
158
+ command_type: "transfer-call",
159
+ to_number: destination,
160
+ transfer_message:
161
+ instructions ?? "Notify the caller that you will be transferring them, and then transfer.",
162
+ soft_transfer: true,
163
+ });
164
+ }
165
+
166
+ async addInfo(label: string, info: unknown) {
167
+ await this.sendInstruction(
168
+ `Here is some information about the following topic ${label}:\n${JSON.stringify(info, null, 2)}`,
169
+ );
170
+ }
171
+
172
+ async retryTask(reason: string) {
173
+ await this.sendCommand(RetryTaskCommand, {
174
+ command_type: "retry-task",
175
+ reason,
176
+ });
177
+ }
178
+
179
+ async readScript(script: string) {
180
+ await this.sendCommand(ReadScriptCommand, {
181
+ command_type: "read-script",
182
+ script,
183
+ });
184
+ }
185
+
186
+ async sendInstruction(instruction: string) {
187
+ await this.sendCommand(SendInstructionCommand, {
188
+ command_type: "send-instruction",
189
+ instruction: instruction,
190
+ });
191
+ }
192
+
193
+ /**
194
+ * @description hang up an accepted call
195
+ */
196
+ async hangup(final_instructions: string = "") {
197
+ let instructions: string;
198
+ if (final_instructions) {
199
+ instructions = `Start ending the conversation. Here are your final instructions: ${final_instructions} Once you've completed the final instructions, naturally end the conversation and hang up the call.`;
200
+ } else {
201
+ instructions = "Naturally end the conversation and hang up the call.";
202
+ }
203
+
204
+ await this.sendInstruction(instructions);
205
+ }
206
+
207
+ async reachPerson(
208
+ contactFullName: string,
209
+ options: { outcomes?: ReachPersonOutcome[]; greeting?: string } = {},
210
+ ) {
211
+ const outcomes = options.outcomes ?? [
212
+ { key: "available", description: "The contact is available to speak." },
213
+ {
214
+ key: "unavailable",
215
+ description:
216
+ "The contact is not available to speak. This includes reaching a wrong number.",
217
+ },
218
+ ];
219
+
220
+ const availabilityDescription =
221
+ `The availability of ${contactFullName}` +
222
+ (outcomes.some((o) => o.description)
223
+ ? "\nDetailed descriptions of each choice:\n" +
224
+ outcomes
225
+ .filter((o) => o.description)
226
+ .map((o) => ` - ${o.key}: ${o.description}`)
227
+ .join("\n")
228
+ : "");
229
+
230
+ const checklist: (FieldItem | SayItem | string)[] = [
231
+ options.greeting !== undefined
232
+ ? Say(options.greeting)
233
+ : `Greet the person who answered the phone. Notify them who you are calling on behalf of and the purpose of the call. Ask to speak with ${contactFullName}`,
234
+ {
235
+ item_type: "field",
236
+ key: "contact_availability",
237
+ field_type: "multiple_choice",
238
+ description: availabilityDescription,
239
+ choices: outcomes.map((o) => o.key),
240
+ } satisfies FieldItem,
241
+ ];
242
+
243
+ const nextActionLines = outcomes
244
+ .filter((o) => o.nextActionPreview)
245
+ .map((o) => `- ${o.key} → ${o.nextActionPreview}`);
246
+ if (nextActionLines.length > 0) {
247
+ checklist.push(
248
+ "If a next action is defined below for the value of `contact_availability`, briefly ask the contact to wait just a second while you perform it.\n" +
249
+ nextActionLines.join("\n"),
250
+ );
251
+ }
252
+
253
+ const objective = `\
254
+ OBJECTIVE:
255
+ Your goal is to reach ${contactFullName} and determine their availability to proceed with this call.
256
+
257
+ RULES:
258
+ 1. If the initial respondent is NOT ${contactFullName}:
259
+ - Politely ask to speak with ${contactFullName}
260
+ - Wait to be transferred or for ${contactFullName} to come to the phone
261
+ 2. Once you have ${contactFullName} on the line:
262
+ - Briefly restate who you are and the purpose of your call
263
+ - Determine and record their current availability status
264
+ 3. DO NOT hang up the call under any circumstances, unless it's a wrong number.
265
+
266
+ TASK COMPLETION REQUIREMENTS:
267
+ - The availability of ${contactFullName} must be recorded in \`contact_availability\`.`;
268
+
269
+ await this.setTask({ taskId: "reach_person", objective, checklist });
270
+ }
271
+
272
+ async setVariable(variableName: string, variableValue: any) {
273
+ this._variables[variableName] = variableValue;
274
+ }
275
+
276
+ async getVariable(variableName: string) {
277
+ return this._variables[variableName] ?? null;
278
+ }
279
+ }
package/src/commands.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as z from "zod";
2
- import { ActionItem } from "./action_item.ts";
2
+ import { ActionItem } from "./action-item.ts";
3
3
 
4
4
  export const StartOutboundCallCommand = z.strictObject({
5
5
  command_type: z.literal("start-outbound"),
@@ -39,6 +39,7 @@ export const SetTaskCommand = z.strictObject({
39
39
  task_id: z.string(),
40
40
  objective: z.string(),
41
41
  action_items: z.array(ActionItem),
42
+ completion_criteria: z.string().optional(),
42
43
  });
43
44
  export type SetTaskCommand = z.input<typeof SetTaskCommand>;
44
45
 
@@ -64,6 +65,16 @@ export const SetPersona = z.strictObject({
64
65
  });
65
66
  export type SetPersona = z.input<typeof SetPersona>;
66
67
 
68
+ export const Language = z.enum(["english", "spanish", "french", "german", "italian"]);
69
+ export type Language = z.infer<typeof Language>;
70
+
71
+ export const SetLanguageModeCommand = z.strictObject({
72
+ command_type: z.literal("set-language-mode"),
73
+ primary: Language.default("english"),
74
+ secondary: z.array(Language).default([]),
75
+ });
76
+ export type SetLanguageModeCommand = z.input<typeof SetLanguageModeCommand>;
77
+
67
78
  export const SendInstructionCommand = z.strictObject({
68
79
  command_type: z.literal("send-instruction"),
69
80
  instruction: z.string(),
@@ -74,6 +85,7 @@ export const TransferCommand = z.strictObject({
74
85
  command_type: z.literal("transfer-call"),
75
86
  transfer_message: z.string(),
76
87
  to_number: z.string(),
88
+ soft_transfer: z.boolean().optional().default(false),
77
89
  });
78
90
  export type TransferCommand = z.input<typeof TransferCommand>;
79
91
 
@@ -81,9 +93,18 @@ export const RegisteredHooksCommand = z.strictObject({
81
93
  command_type: z.literal("registered-hooks"),
82
94
  has_on_question: z.boolean(),
83
95
  has_on_intent: z.boolean(),
96
+ has_on_action_requested: z.boolean().optional().default(false),
84
97
  });
85
98
  export type RegisteredHooksCommand = z.input<typeof RegisteredHooksCommand>;
86
99
 
100
+ export const ActionSuggestionCommand = z.strictObject({
101
+ command_type: z.literal("action-suggestion"),
102
+ intent_id: z.string(),
103
+ action_key: z.string().nullable(),
104
+ action_description: z.string().default(""),
105
+ });
106
+ export type ActionSuggestionCommand = z.input<typeof ActionSuggestionCommand>;
107
+
87
108
  export const ChoiceResultCommand = z.strictObject({
88
109
  command_type: z.literal("choice-query-result"),
89
110
  field_key: z.string(),
@@ -93,6 +114,12 @@ export const ChoiceResultCommand = z.strictObject({
93
114
  });
94
115
  export type ChoiceResultCommand = z.input<typeof ChoiceResultCommand>;
95
116
 
117
+ export const RetryTaskCommand = z.strictObject({
118
+ command_type: z.literal("retry-task"),
119
+ reason: z.string(),
120
+ });
121
+ export type RetryTaskCommand = z.input<typeof RetryTaskCommand>;
122
+
96
123
  export const AnyCommand = z.union([
97
124
  StartOutboundCallCommand,
98
125
  ListenInboundCommand,
@@ -102,10 +129,13 @@ export const AnyCommand = z.union([
102
129
  ReadScriptCommand,
103
130
  AnswerQuestionCommand,
104
131
  SetPersona,
132
+ SetLanguageModeCommand,
105
133
  SendInstructionCommand,
106
134
  TransferCommand,
107
135
  RegisteredHooksCommand,
108
136
  ChoiceResultCommand,
137
+ ActionSuggestionCommand,
138
+ RetryTaskCommand,
109
139
  ]);
110
140
  export type Command = z.input<typeof AnyCommand>;
111
141
 
package/src/events.ts CHANGED
@@ -100,6 +100,19 @@ export const ChoiceQueryEvent = z.object({
100
100
  });
101
101
  export type ChoiceQueryEvent = z.infer<typeof ChoiceQueryEvent>;
102
102
 
103
+ export const ActionRequestEvent = z.object({
104
+ event_type: z.literal("action-request"),
105
+ intent_id: z.string(),
106
+ intent_summary: z.string(),
107
+ });
108
+ export type ActionRequestEvent = z.infer<typeof ActionRequestEvent>;
109
+
110
+ export const ExecuteActionEvent = z.object({
111
+ event_type: z.literal("execute-action"),
112
+ action_key: z.string(),
113
+ });
114
+ export type ExecuteActionEvent = z.infer<typeof ExecuteActionEvent>;
115
+
103
116
  export const GuavaEvent = z.union([
104
117
  SessionStartedEvent,
105
118
  InboundCallEvent,
@@ -115,6 +128,8 @@ export const GuavaEvent = z.union([
115
128
  OutboundCallFailed,
116
129
  BotSessionEnded,
117
130
  ChoiceQueryEvent,
131
+ ActionRequestEvent,
132
+ ExecuteActionEvent,
118
133
  ]);
119
134
  export type GuavaEvent = z.infer<typeof GuavaEvent>;
120
135
 
@@ -649,3 +649,44 @@ The actual insurance policy, including Declarations, core forms, endorsements, a
649
649
 
650
650
  End of Harper Valley Property Insurance
651
651
  Comprehensive Residential Program Manual.`;
652
+
653
+ export const FURNITURE_RETAILER_QA = `
654
+ CLEARFIELD HOME & LIVING — HELP DESK Q&A DOCUMENT
655
+ ==================================================
656
+
657
+ Q: What are your store hours?
658
+ A: Most Clearfield locations are open Monday–Saturday, 10 AM–8 PM, and Sunday, 11 AM–6 PM. Hours may vary by location and on holidays. Customers can check the store locator on the website for exact hours.
659
+
660
+ Q: How long does delivery take?
661
+ A: Standard delivery is 5–10 business days. Express delivery (available in select areas) is 2–3 business days. Furniture and large appliances require a scheduled delivery window.
662
+
663
+ Q: Can I track my order?
664
+ A: Yes. Customers can track their order at clearfieldhome.com/track using their order number and the email address used at checkout. A tracking link is also sent once the order ships.
665
+
666
+ Q: Can I change or cancel my order?
667
+ A: Orders can be modified or cancelled within 24 hours of placement at no charge. After 24 hours, a restocking fee may apply if the item has already been processed for shipment.
668
+
669
+ Q: What is your return policy?
670
+ A: Items can be returned within 30 days of delivery in original condition with receipt. Mattresses, custom/special-order furniture, and final-sale items are non-returnable.
671
+
672
+ Q: What do I do if my item arrived damaged?
673
+ A: Customers should photograph the damage and contact Clearfield within 48 hours of delivery. Clearfield will arrange a replacement, repair, or refund depending on the situation.
674
+
675
+ Q: Do you offer assembly or installation services?
676
+ A: Yes. White-glove delivery with in-home assembly is available for most furniture and large appliances for an additional fee. It can be added at checkout or when scheduling delivery.
677
+
678
+ Q: How does the warranty work?
679
+ A: All Clearfield products include a 1-year limited warranty covering manufacturing defects. Extended 2- or 5-year warranties are available for purchase. Normal wear, accidental damage, and misuse are not covered.
680
+
681
+ Q: Do you offer financing?
682
+ A: Yes. Clearfield offers financing through ClearPay with 6, 12, and 24-month plans. Customers can apply online or in-store, subject to credit approval.
683
+
684
+ Q: How do I earn and redeem rewards points?
685
+ A: Rewards members earn 1 point per $1 spent. Every 100 points = $5 off at checkout. Points expire after 12 months of account inactivity.
686
+
687
+ Q: Do you offer price matching?
688
+ A: Yes. Clearfield matches a competitor's current advertised price on an identical in-stock item within 14 days of purchase. Proof of price is required. Excludes auction sites, wholesale clubs, and marketplace sellers.
689
+
690
+ Q: Can businesses place bulk orders?
691
+ A: Yes. Clearfield supports bulk purchases and interior design partnerships through corporate accounts.
692
+ `;
package/src/index.ts CHANGED
@@ -13,8 +13,10 @@ import { getBaseUrl, fetchOrThrow } from "./utils.ts";
13
13
  import { telemetryClient } from "./telemetry.ts";
14
14
  import type { CallController } from "./call-controller.ts";
15
15
  export { CallController, type TaskObjective } from "./call-controller.ts";
16
- export { Say, Field } from "./action_item.ts";
17
- export { Logger, getConsoleLogger } from "./logging.ts";
16
+ export { Say, Field } from "./action-item.ts";
17
+ export { Logger, getConsoleLogger, getDefaultLogger } from "./logging.ts";
18
+ export { Agent, CallInfo } from "./agent.ts";
19
+ export { Call } from "./call.ts";
18
20
 
19
21
  const SDK_NAME = "typescript-sdk";
20
22
 
@@ -81,7 +83,7 @@ export class Client {
81
83
  }
82
84
  }
83
85
 
84
- private getWebsocketBase() {
86
+ getWebsocketBase() {
85
87
  if (http_start.test(this._baseUrl)) {
86
88
  return `ws://${this._baseUrl.substring("ws://".length)}`;
87
89
  } else if (https_start.test(this._baseUrl)) {
@@ -91,11 +93,11 @@ export class Client {
91
93
  }
92
94
  }
93
95
 
94
- private getHttpBase() {
96
+ getHttpBase() {
95
97
  return this._baseUrl;
96
98
  }
97
99
 
98
- private headers() {
100
+ headers() {
99
101
  return {
100
102
  Authorization: `Bearer ${this._apiKey}`,
101
103
  "x-guava-platform": os.platform(),
package/src/logging.ts CHANGED
@@ -44,7 +44,7 @@ function makeColoredMethod(
44
44
  ): (format: string, ...args: unknown[]) => void {
45
45
  if (!useColor) return fn.bind(console);
46
46
  return (format: string, ...args: unknown[]) =>
47
- fn(`${LEVEL_COLORS[level]}[${level}] ${format}${ANSI_RESET}`, ...args);
47
+ fn(`${LEVEL_COLORS[level]}[${level.toLocaleUpperCase()}] ${format}${ANSI_RESET}`, ...args);
48
48
  }
49
49
 
50
50
  export function getConsoleLogger(loggerLevel: LogLevel, useColor = false): Logger {
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const SDK_VERSION = "0.9.0";
1
+ export const SDK_VERSION = "0.11.0";
@@ -1,177 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.run = run;
37
- const guava = __importStar(require("@guava-ai/guava-sdk"));
38
- const openai_1 = require("@guava-ai/guava-sdk/helpers/openai");
39
- const CUSTOMER_DB = [
40
- {
41
- name: "John Smith",
42
- ssn: "123456789",
43
- unactivated_cards: {
44
- "6011002980139424": 567,
45
- },
46
- },
47
- ];
48
- function findCustomerBySSN(ssn) {
49
- return CUSTOMER_DB.find((c) => c.ssn === ssn);
50
- }
51
- const ORGANIZATION_NAME = "Harper Valley Bank";
52
- class CreditCardActivationController extends guava.CallController {
53
- choices = ["activate credit card", "anything else"];
54
- intentRecognizer;
55
- constructor(logger) {
56
- super(logger);
57
- this.intentRecognizer = new openai_1.IntentRecognizer(this.choices, logger);
58
- this.setPersona({
59
- organizationName: ORGANIZATION_NAME,
60
- agentPurpose: `You are a customer service voice agent that activates credit cards for customers of ${ORGANIZATION_NAME}.`,
61
- });
62
- this.readScript(`Hello, thank you for calling the credit card activation line for ${ORGANIZATION_NAME}. My name is Grace. Are you here to activate your credit card?`);
63
- this.acceptCall();
64
- }
65
- async onIntent(intent) {
66
- const choice = await this.intentRecognizer.classify(intent);
67
- this.logger.info(`Chosen intent: ${choice}`);
68
- if (choice === "activate credit card") {
69
- await this.activateCreditCard();
70
- return null;
71
- }
72
- else {
73
- return "Unfortunately I'm not able to help with that.";
74
- }
75
- }
76
- async findCustomer() {
77
- let customer;
78
- let cardNumber;
79
- while (true) {
80
- await this.awaitTask({
81
- checklist: [
82
- guava.Field({
83
- description: "Could you give me your social security number?",
84
- key: "social_security_number",
85
- fieldType: "integer",
86
- required: true,
87
- }),
88
- ],
89
- });
90
- const ssn_data = this.getField("social_security_number");
91
- let ssn;
92
- if (typeof ssn_data === "string") {
93
- ssn = ssn_data;
94
- }
95
- else {
96
- // Should we assume all payloads are strings? or leave room by returning unknown
97
- ssn = JSON.stringify(ssn_data);
98
- }
99
- customer = findCustomerBySSN(ssn);
100
- if (!customer) {
101
- this.sendInstruction("We were unable to identify the customer using the SSN they provided. Let the caller know this, and ask if they have the correct social security number.");
102
- }
103
- else {
104
- await this.awaitTask({
105
- objective: "We were able to identify the customer using the Social Security Number they have provided. We're going to confirm the client's name.",
106
- checklist: [
107
- guava.Field({
108
- description: `We're going to confirm the client's name. Am I speaking with ${customer.name}?`,
109
- key: "is_client",
110
- fieldType: "multiple_choice",
111
- choices: ["yes", "no"],
112
- required: true,
113
- }),
114
- ],
115
- });
116
- if (this.getField("is_client") === "no") {
117
- this.sendInstruction("We were unable to identify the client's name in our files. Let the caller know this, and re-ask their social security number.");
118
- }
119
- else {
120
- break;
121
- }
122
- }
123
- }
124
- this.sendInstruction("We were able to find the client's name in our files. Proceed to ask for their card number.");
125
- while (true) {
126
- await this.awaitTask({
127
- checklist: [
128
- guava.Field({
129
- fieldType: "integer",
130
- description: "Could you read me the digits on the front of your credit card?",
131
- key: "credit_card_number",
132
- required: true,
133
- }),
134
- ],
135
- });
136
- cardNumber = this.getField("credit_card_number");
137
- if (!(cardNumber in customer.unactivated_cards)) {
138
- this.sendInstruction("We were unable to find the matching card number in our system. Let the caller know this, and re-ask for the credit card number.");
139
- }
140
- else {
141
- this.sendInstruction("We were able to find the matching card number in our system. Let the caller know this, and ask for security code on their card.");
142
- break;
143
- }
144
- }
145
- const correctCvv = customer.unactivated_cards[cardNumber];
146
- while (true) {
147
- await this.awaitTask({
148
- checklist: [
149
- guava.Field({
150
- fieldType: "integer",
151
- key: "security_code",
152
- description: "To wrap up, could I get the security code on your card?",
153
- required: true,
154
- }),
155
- ],
156
- });
157
- const security_code = this.getField("security_code");
158
- if (security_code !== correctCvv.toString()) {
159
- this.sendInstruction("We were unable to match the security code to the credit card. Let the caller know this and re-ask for the security code.");
160
- }
161
- else {
162
- break;
163
- }
164
- }
165
- this.hangup("Explain to the caller that their credit card has now been activated. Thank them for using the bank's services, and hang up.");
166
- }
167
- async activateCreditCard() {
168
- this.sendInstruction("We are starting the credit card activation process, which starts with asking the caller for their social security number.");
169
- await this.findCustomer();
170
- }
171
- }
172
- async function run(_args) {
173
- new guava.Client().listenInbound({
174
- agent_number: process.env.GUAVA_AGENT_NUMBER,
175
- }, (logger) => new CreditCardActivationController(logger));
176
- }
177
- //# sourceMappingURL=credit-card-activation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credit-card-activation.js","sourceRoot":"","sources":["../../examples/credit-card-activation.ts"],"names":[],"mappings":"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"}