@fonoster/autopilot 0.7.16 → 0.7.18

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/README.md CHANGED
@@ -88,8 +88,9 @@ The Autopilot supports multiple language model providers. The following is a lis
88
88
 
89
89
  | Provider | Description | Supported models
90
90
  |------------|------------------------------------------------------------|------------------------------------------------------------------------------|
91
- | OpenAI | OpenAI provides various GPT models for conversational AI | `gpt-4o`, `gpt-40-mini` |
91
+ | OpenAI | OpenAI provides various GPT models for conversational AI | `gpt-4o`, `gpt-4o-mini` |
92
92
  | Groq | Groq offers high-performance AI models optimized for speed | `gemm-7b-it`, `llama3-groq-70b-8192-tool-use-preview`, `llama3-1-8b-instant` |
93
+ | Ollama | Self-hosted Ollama models | `lama3.1` |
93
94
 
94
95
  ## Adding Knowledge Base
95
96
 
@@ -141,7 +142,7 @@ You can configure a new tool by adding a new entry in the `tools` array in the c
141
142
 
142
143
  In addition to the `get` operation type, you can use the `post` operation type. The `post` operation type is used when sending data to the tool. When sending a post, you can optionally set `waitForResponse` to false, which will "fire and forget" the request. The default behavior is to wait for the response.
143
144
 
144
- If your tool needs the number of the caller or the number that received the call, you can use the reserved variables `ingressNumber` and `callerNumber`. Similarly, you can use the reserved variable `callReceivedAt` to get the date and time when the call was received in `ISO 8601` format.
145
+ If your tool needs the number of the caller or the number that received the call, you can use the reserved variables `ingressNumber` and `callerNumber`. Similarly, you can use the reserved variable `callReceivedAt` to get the date and time when the call was received in `ISO 8601` format and the `callDirection` variable to check if the call was originated from the PSTN.
145
146
 
146
147
  The expected format for the response is a JSON object with the following structure:
147
148
 
@@ -33,8 +33,8 @@ declare const conversationSettingsSchema: z.ZodObject<{
33
33
  maxTimeoutCount: number;
34
34
  }>>>;
35
35
  }, "strip", z.ZodTypeAny, {
36
- systemTemplate: string;
37
36
  firstMessage: string;
37
+ systemTemplate: string;
38
38
  goodbyeMessage: string;
39
39
  systemErrorMessage: string;
40
40
  initialDtmf?: string | null | undefined;
@@ -49,8 +49,8 @@ declare const conversationSettingsSchema: z.ZodObject<{
49
49
  maxTimeoutCount: number;
50
50
  } | null | undefined;
51
51
  }, {
52
- systemTemplate: string;
53
52
  firstMessage: string;
53
+ systemTemplate: string;
54
54
  goodbyeMessage: string;
55
55
  systemErrorMessage: string;
56
56
  initialDtmf?: string | null | undefined;
@@ -129,6 +129,7 @@ declare const languageModelConfigSchema: z.ZodObject<{
129
129
  }>;
130
130
  required?: string[] | undefined;
131
131
  }>;
132
+ requestStartMessage: z.ZodOptional<z.ZodString>;
132
133
  operation: z.ZodEffects<z.ZodObject<{
133
134
  type: z.ZodNativeEnum<typeof import("../tools/ToolSchema").AllowedOperations>;
134
135
  url: z.ZodOptional<z.ZodString>;
@@ -173,6 +174,7 @@ declare const languageModelConfigSchema: z.ZodObject<{
173
174
  waitForResponse?: boolean | undefined;
174
175
  headers?: Record<string, string> | undefined;
175
176
  };
177
+ requestStartMessage?: string | undefined;
176
178
  }, {
177
179
  name: string;
178
180
  description: string;
@@ -191,6 +193,7 @@ declare const languageModelConfigSchema: z.ZodObject<{
191
193
  waitForResponse?: boolean | undefined;
192
194
  headers?: Record<string, string> | undefined;
193
195
  };
196
+ requestStartMessage?: string | undefined;
194
197
  }>, "many">;
195
198
  }, "strip", z.ZodTypeAny, {
196
199
  model: string;
@@ -217,6 +220,7 @@ declare const languageModelConfigSchema: z.ZodObject<{
217
220
  waitForResponse?: boolean | undefined;
218
221
  headers?: Record<string, string> | undefined;
219
222
  };
223
+ requestStartMessage?: string | undefined;
220
224
  }[];
221
225
  temperature: number;
222
226
  maxTokens: number;
@@ -248,6 +252,7 @@ declare const languageModelConfigSchema: z.ZodObject<{
248
252
  waitForResponse?: boolean | undefined;
249
253
  headers?: Record<string, string> | undefined;
250
254
  };
255
+ requestStartMessage?: string | undefined;
251
256
  }[];
252
257
  temperature: number;
253
258
  maxTokens: number;
@@ -289,8 +294,8 @@ declare const assistantSchema: z.ZodObject<{
289
294
  maxTimeoutCount: number;
290
295
  }>>>;
291
296
  }, "strip", z.ZodTypeAny, {
292
- systemTemplate: string;
293
297
  firstMessage: string;
298
+ systemTemplate: string;
294
299
  goodbyeMessage: string;
295
300
  systemErrorMessage: string;
296
301
  initialDtmf?: string | null | undefined;
@@ -305,8 +310,8 @@ declare const assistantSchema: z.ZodObject<{
305
310
  maxTimeoutCount: number;
306
311
  } | null | undefined;
307
312
  }, {
308
- systemTemplate: string;
309
313
  firstMessage: string;
314
+ systemTemplate: string;
310
315
  goodbyeMessage: string;
311
316
  systemErrorMessage: string;
312
317
  initialDtmf?: string | null | undefined;
@@ -385,6 +390,7 @@ declare const assistantSchema: z.ZodObject<{
385
390
  }>;
386
391
  required?: string[] | undefined;
387
392
  }>;
393
+ requestStartMessage: z.ZodOptional<z.ZodString>;
388
394
  operation: z.ZodEffects<z.ZodObject<{
389
395
  type: z.ZodNativeEnum<typeof import("../tools/ToolSchema").AllowedOperations>;
390
396
  url: z.ZodOptional<z.ZodString>;
@@ -429,6 +435,7 @@ declare const assistantSchema: z.ZodObject<{
429
435
  waitForResponse?: boolean | undefined;
430
436
  headers?: Record<string, string> | undefined;
431
437
  };
438
+ requestStartMessage?: string | undefined;
432
439
  }, {
433
440
  name: string;
434
441
  description: string;
@@ -447,6 +454,7 @@ declare const assistantSchema: z.ZodObject<{
447
454
  waitForResponse?: boolean | undefined;
448
455
  headers?: Record<string, string> | undefined;
449
456
  };
457
+ requestStartMessage?: string | undefined;
450
458
  }>, "many">;
451
459
  }, "strip", z.ZodTypeAny, {
452
460
  model: string;
@@ -473,6 +481,7 @@ declare const assistantSchema: z.ZodObject<{
473
481
  waitForResponse?: boolean | undefined;
474
482
  headers?: Record<string, string> | undefined;
475
483
  };
484
+ requestStartMessage?: string | undefined;
476
485
  }[];
477
486
  temperature: number;
478
487
  maxTokens: number;
@@ -504,6 +513,7 @@ declare const assistantSchema: z.ZodObject<{
504
513
  waitForResponse?: boolean | undefined;
505
514
  headers?: Record<string, string> | undefined;
506
515
  };
516
+ requestStartMessage?: string | undefined;
507
517
  }[];
508
518
  temperature: number;
509
519
  maxTokens: number;
@@ -513,8 +523,8 @@ declare const assistantSchema: z.ZodObject<{
513
523
  }>;
514
524
  }, "strip", z.ZodTypeAny, {
515
525
  conversationSettings: {
516
- systemTemplate: string;
517
526
  firstMessage: string;
527
+ systemTemplate: string;
518
528
  goodbyeMessage: string;
519
529
  systemErrorMessage: string;
520
530
  initialDtmf?: string | null | undefined;
@@ -554,6 +564,7 @@ declare const assistantSchema: z.ZodObject<{
554
564
  waitForResponse?: boolean | undefined;
555
565
  headers?: Record<string, string> | undefined;
556
566
  };
567
+ requestStartMessage?: string | undefined;
557
568
  }[];
558
569
  temperature: number;
559
570
  maxTokens: number;
@@ -563,8 +574,8 @@ declare const assistantSchema: z.ZodObject<{
563
574
  };
564
575
  }, {
565
576
  conversationSettings: {
566
- systemTemplate: string;
567
577
  firstMessage: string;
578
+ systemTemplate: string;
568
579
  goodbyeMessage: string;
569
580
  systemErrorMessage: string;
570
581
  initialDtmf?: string | null | undefined;
@@ -604,6 +615,7 @@ declare const assistantSchema: z.ZodObject<{
604
615
  waitForResponse?: boolean | undefined;
605
616
  headers?: Record<string, string> | undefined;
606
617
  };
618
+ requestStartMessage?: string | undefined;
607
619
  }[];
608
620
  temperature: number;
609
621
  maxTokens: number;
@@ -1,3 +1,8 @@
1
- import { AssistantConfig, FilesKnowledgeBase, TelephonyContext } from ".";
2
- declare function createLanguageModel(assistantConfig: AssistantConfig, knowledgeBase: FilesKnowledgeBase, telephonyContext: TelephonyContext): import("./models/AbstractLanguageModel").AbstractLanguageModel;
1
+ import { AssistantConfig, FilesKnowledgeBase, TelephonyContext, Voice } from ".";
2
+ declare function createLanguageModel(params: {
3
+ voice: Voice;
4
+ assistantConfig: AssistantConfig;
5
+ knowledgeBase: FilesKnowledgeBase;
6
+ telephonyContext: TelephonyContext;
7
+ }): import("./models/AbstractLanguageModel").AbstractLanguageModel;
3
8
  export { createLanguageModel };
@@ -20,14 +20,16 @@ exports.createLanguageModel = createLanguageModel;
20
20
  * limitations under the License.
21
21
  */
22
22
  const _1 = require(".");
23
- function createLanguageModel(assistantConfig, knowledgeBase, telephonyContext) {
23
+ function createLanguageModel(params) {
24
+ const { voice, assistantConfig, knowledgeBase, telephonyContext } = params;
24
25
  const { languageModel: languageModelSettings, conversationSettings } = assistantConfig;
25
26
  return _1.LanguageModelFactory.getLanguageModel(languageModelSettings.provider, {
26
- apiKey: languageModelSettings.apiKey,
27
27
  // @ts-expect-error don't know the model type here
28
28
  model: languageModelSettings.model,
29
+ apiKey: languageModelSettings.apiKey,
29
30
  maxTokens: languageModelSettings.maxTokens,
30
31
  temperature: languageModelSettings.temperature,
32
+ firstMessage: conversationSettings.firstMessage,
31
33
  systemTemplate: conversationSettings.systemTemplate,
32
34
  baseUrl: languageModelSettings.baseUrl,
33
35
  knowledgeBase,
@@ -36,5 +38,5 @@ function createLanguageModel(assistantConfig, knowledgeBase, telephonyContext) {
36
38
  _1.hangupToolDefinition,
37
39
  _1.transferToolDefinition
38
40
  ]
39
- }, telephonyContext);
41
+ }, voice, telephonyContext);
40
42
  }
package/dist/envs.d.ts CHANGED
@@ -1,3 +1 @@
1
1
  export declare const ASSISTANT: string | undefined;
2
- export declare const GROQ_API_KEY: string | undefined;
3
- export declare const OPENAI_API_KEY: string | undefined;
package/dist/envs.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.OPENAI_API_KEY = exports.GROQ_API_KEY = exports.ASSISTANT = void 0;
6
+ exports.ASSISTANT = void 0;
7
7
  /*
8
8
  * Copyright (C) 2024 by Fonoster Inc (https://fonoster.com)
9
9
  * http://github.com/fonoster/fonoster
@@ -31,5 +31,3 @@ if (process.env.NODE_ENV === "dev") {
31
31
  (0, common_1.assertEnvsAreSet)(["ASSISTANT"]);
32
32
  (0, common_1.assertFileExists)(process.env.ASSISTANT);
33
33
  exports.ASSISTANT = process.env.ASSISTANT;
34
- exports.GROQ_API_KEY = process.env.GROQ_API_KEY;
35
- exports.OPENAI_API_KEY = process.env.OPENAI_API_KEY;
@@ -50,15 +50,26 @@ const loadKnowledgeBase_1 = require("./loadKnowledgeBase");
50
50
  const _1 = __importStar(require("."));
51
51
  const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
52
52
  async function handleVoiceRequest(req, res) {
53
- const { ingressNumber, sessionRef, appRef } = req;
54
- logger.verbose("voice request", { ingressNumber, sessionRef, appRef });
53
+ const { ingressNumber, sessionRef, appRef, callDirection } = req;
54
+ logger.verbose("voice request", {
55
+ ingressNumber,
56
+ sessionRef,
57
+ appRef,
58
+ metadata: req.metadata
59
+ });
55
60
  const assistantConfig = (0, loadAssistantConfig_1.loadAssistantConfig)();
56
61
  const knowledgeBase = await (0, loadKnowledgeBase_1.loadKnowledgeBase)();
57
62
  const voice = new _1.VoiceImpl(sessionRef, res);
58
63
  const vad = new _1.SileroVad();
59
- const languageModel = (0, createLanguageModel_1.createLanguageModel)(assistantConfig, knowledgeBase, {
60
- ingressNumber: req.ingressNumber,
61
- callerNumber: req.callerNumber
64
+ const languageModel = (0, createLanguageModel_1.createLanguageModel)({
65
+ voice,
66
+ assistantConfig,
67
+ knowledgeBase,
68
+ telephonyContext: {
69
+ callDirection,
70
+ ingressNumber: req.ingressNumber,
71
+ callerNumber: req.callerNumber
72
+ }
62
73
  });
63
74
  const autopilot = new _1.default({
64
75
  conversationSettings: assistantConfig.conversationSettings,
@@ -1,25 +1,8 @@
1
+ import { AutopilotContext } from "./types";
1
2
  import { ConversationSettings } from "../assistants";
2
3
  import { LanguageModel } from "../models";
3
4
  import { Voice } from "../voice";
4
- declare const machine: import("xstate").StateMachine<{
5
- sessionRef: string;
6
- languageModel: LanguageModel;
7
- voice: Voice;
8
- firstMessage: string;
9
- goodbyeMessage: string;
10
- transferMessage?: string;
11
- transferPhoneNumber?: string;
12
- systemErrorMessage: string;
13
- idleMessage: string;
14
- idleTimeout: number;
15
- idleTimeoutCount: number;
16
- maxIdleTimeoutCount: number;
17
- speechBuffer: string;
18
- speechResponseStartTime: number;
19
- speechResponseTime: number;
20
- isSpeaking: boolean;
21
- knowledgeBaseSourceUrl?: string;
22
- }, {
5
+ declare const machine: import("xstate").StateMachine<AutopilotContext, {
23
6
  type: "SPEECH_START";
24
7
  } | {
25
8
  type: "SPEECH_END";
@@ -28,7 +11,17 @@ declare const machine: import("xstate").StateMachine<{
28
11
  speech: string;
29
12
  } | {
30
13
  type: "USER_REQUEST_PROCESSED";
31
- }, {}, never, import("xstate").Values<{
14
+ }, {
15
+ [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<void, {
16
+ context: AutopilotContext;
17
+ }, import("xstate").EventObject>> | undefined;
18
+ }, {
19
+ src: "doProcessUserRequest";
20
+ logic: import("xstate").PromiseActorLogic<void, {
21
+ context: AutopilotContext;
22
+ }, import("xstate").EventObject>;
23
+ id: string | undefined;
24
+ }, import("xstate").Values<{
32
25
  greetUser: {
33
26
  type: "greetUser";
34
27
  params: unknown;
@@ -45,10 +38,6 @@ declare const machine: import("xstate").StateMachine<{
45
38
  type: "interruptPlayback";
46
39
  params: unknown;
47
40
  };
48
- processUserRequest: {
49
- type: "processUserRequest";
50
- params: unknown;
51
- };
52
41
  announceIdleTimeout: {
53
42
  type: "announceIdleTimeout";
54
43
  params: unknown;
@@ -90,14 +79,39 @@ declare const machine: import("xstate").StateMachine<{
90
79
  type: "isNotSpeaking";
91
80
  params: unknown;
92
81
  };
93
- }>, "IDLE_TIMEOUT", "hangup" | "greeting" | "idle" | "waitingForUserRequest" | "hackingTimeout" | "updatingSpeech" | "processingUserRequest", string, {
82
+ }>, "IDLE_TIMEOUT", "hangup" | "greeting" | "idle" | "waitingForUserRequest" | "transitioningToIdle" | "updatingSpeech" | "processingUserRequest", string, {
94
83
  conversationSettings: ConversationSettings;
95
84
  languageModel: LanguageModel;
96
85
  voice: Voice;
97
86
  }, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
98
87
  readonly context: ({ input }: {
99
88
  spawn: {
100
- <TSrc extends never>(logic: TSrc, ...[options]: never): import("xstate").ActorRefFromLogic<never>;
89
+ <TSrc extends "doProcessUserRequest">(logic: TSrc, ...[options]: {
90
+ src: "doProcessUserRequest";
91
+ logic: import("xstate").PromiseActorLogic<void, {
92
+ context: AutopilotContext;
93
+ }, import("xstate").EventObject>;
94
+ id: string | undefined;
95
+ } extends infer T ? T extends {
96
+ src: "doProcessUserRequest";
97
+ logic: import("xstate").PromiseActorLogic<void, {
98
+ context: AutopilotContext;
99
+ }, import("xstate").EventObject>;
100
+ id: string | undefined;
101
+ } ? T extends {
102
+ src: TSrc;
103
+ } ? import("xstate").ConditionalRequired<[options?: ({
104
+ id?: T["id"] | undefined;
105
+ systemId?: string;
106
+ input?: import("xstate").InputFrom<T["logic"]> | undefined;
107
+ syncSnapshot?: boolean;
108
+ } & { [K in import("xstate").RequiredActorOptions<T>]: unknown; }) | undefined], import("xstate").IsNotNever<import("xstate").RequiredActorOptions<T>>> : never : never : never): import("xstate").ActorRefFromLogic<import("xstate").GetConcreteByKey<{
109
+ src: "doProcessUserRequest";
110
+ logic: import("xstate").PromiseActorLogic<void, {
111
+ context: AutopilotContext;
112
+ }, import("xstate").EventObject>;
113
+ id: string | undefined;
114
+ }, "src", TSrc>["logic"]>;
101
115
  <TLogic extends import("xstate").AnyActorLogic>(src: TLogic, options?: {
102
116
  id?: never;
103
117
  systemId?: string;
@@ -110,25 +124,7 @@ declare const machine: import("xstate").StateMachine<{
110
124
  languageModel: LanguageModel;
111
125
  voice: Voice;
112
126
  };
113
- self: import("xstate").ActorRef<import("xstate").MachineSnapshot<{
114
- sessionRef: string;
115
- languageModel: LanguageModel;
116
- voice: Voice;
117
- firstMessage: string;
118
- goodbyeMessage: string;
119
- transferMessage?: string;
120
- transferPhoneNumber?: string;
121
- systemErrorMessage: string;
122
- idleMessage: string;
123
- idleTimeout: number;
124
- idleTimeoutCount: number;
125
- maxIdleTimeoutCount: number;
126
- speechBuffer: string;
127
- speechResponseStartTime: number;
128
- speechResponseTime: number;
129
- isSpeaking: boolean;
130
- knowledgeBaseSourceUrl?: string;
131
- }, {
127
+ self: import("xstate").ActorRef<import("xstate").MachineSnapshot<AutopilotContext, {
132
128
  type: "SPEECH_START";
133
129
  } | {
134
130
  type: "SPEECH_END";
@@ -193,7 +189,7 @@ declare const machine: import("xstate").StateMachine<{
193
189
  readonly type: "idleTimeoutCountExceedsMax";
194
190
  };
195
191
  }, {
196
- readonly target: "hackingTimeout";
192
+ readonly target: "transitioningToIdle";
197
193
  readonly actions: readonly [{
198
194
  readonly type: "increaseIdleTimeoutCount";
199
195
  }, {
@@ -219,7 +215,7 @@ declare const machine: import("xstate").StateMachine<{
219
215
  readonly hangup: {
220
216
  readonly type: "final";
221
217
  };
222
- readonly hackingTimeout: {
218
+ readonly transitioningToIdle: {
223
219
  readonly always: {
224
220
  readonly target: "idle";
225
221
  };
@@ -264,14 +260,47 @@ declare const machine: import("xstate").StateMachine<{
264
260
  readonly target: "waitingForUserRequest";
265
261
  readonly description: "Event from VAD or similar system.";
266
262
  };
267
- readonly USER_REQUEST_PROCESSED: {
263
+ };
264
+ readonly invoke: {
265
+ readonly src: "doProcessUserRequest";
266
+ readonly input: ({ context }: {
267
+ context: AutopilotContext;
268
+ event: {
269
+ type: "SPEECH_START";
270
+ } | {
271
+ type: "SPEECH_END";
272
+ } | {
273
+ type: "SPEECH_RESULT";
274
+ speech: string;
275
+ } | {
276
+ type: "USER_REQUEST_PROCESSED";
277
+ };
278
+ self: import("xstate").ActorRef<import("xstate").MachineSnapshot<AutopilotContext, {
279
+ type: "SPEECH_START";
280
+ } | {
281
+ type: "SPEECH_END";
282
+ } | {
283
+ type: "SPEECH_RESULT";
284
+ speech: string;
285
+ } | {
286
+ type: "USER_REQUEST_PROCESSED";
287
+ }, Record<string, import("xstate").AnyActorRef>, import("xstate").StateValue, string, unknown, any, any>, {
288
+ type: "SPEECH_START";
289
+ } | {
290
+ type: "SPEECH_END";
291
+ } | {
292
+ type: "SPEECH_RESULT";
293
+ speech: string;
294
+ } | {
295
+ type: "USER_REQUEST_PROCESSED";
296
+ }, import("xstate").AnyEventObject>;
297
+ }) => {
298
+ context: AutopilotContext;
299
+ };
300
+ readonly onDone: {
268
301
  readonly target: "idle";
269
- readonly description: "Go back home.";
270
302
  };
271
303
  };
272
- readonly entry: {
273
- readonly type: "processUserRequest";
274
- };
275
304
  };
276
305
  };
277
306
  }>;
@@ -56,55 +56,6 @@ const machine = (0, xstate_1.setup)({
56
56
  });
57
57
  await context.voice.stopSpeech();
58
58
  },
59
- processUserRequest: async ({ context }) => {
60
- logger.verbose("called processUserRequest action", {
61
- speechBuffer: context.speechBuffer
62
- });
63
- // Stop any speech that might be playing
64
- await context.voice.stopSpeech();
65
- const speech = context.speechBuffer.trim();
66
- const languageModel = context.languageModel;
67
- const response = await languageModel.invoke(speech);
68
- const speechResponseTime = Date.now() - context.speechResponseStartTime;
69
- context.speechResponseTime = speechResponseTime;
70
- context.speechResponseStartTime = 0;
71
- logger.verbose("response from language model", {
72
- speechResponseTime
73
- });
74
- try {
75
- if (response.type === "say" && !response.content) {
76
- logger.verbose("call might already be hung up");
77
- (0, xstate_1.raise)({ type: "USER_REQUEST_PROCESSED" });
78
- return;
79
- }
80
- else if (response.type === "hangup") {
81
- const message = context.goodbyeMessage;
82
- await context.voice.say(message);
83
- await context.voice.hangup();
84
- return;
85
- }
86
- else if (response.type === "transfer") {
87
- logger.verbose("transferring call to a number in the pstn", {
88
- phoneNumber: context.transferPhoneNumber
89
- });
90
- const message = context.transferMessage;
91
- await context.voice.say(message);
92
- await context.voice.transfer(context.transferPhoneNumber, {
93
- record: true,
94
- timeout: 30
95
- });
96
- return;
97
- }
98
- await context.voice.say(response.content);
99
- }
100
- catch (error) {
101
- logger.error("error processing user request", {
102
- error
103
- });
104
- await context.voice.say(context.systemErrorMessage);
105
- }
106
- (0, xstate_1.raise)({ type: "USER_REQUEST_PROCESSED" });
107
- },
108
59
  announceIdleTimeout: async ({ context }) => {
109
60
  logger.verbose("called announceIdleTimeout action", {
110
61
  idleMessage: context.idleMessage
@@ -174,6 +125,56 @@ const machine = (0, xstate_1.setup)({
174
125
  IDLE_TIMEOUT: ({ context }) => {
175
126
  return context.idleTimeout;
176
127
  }
128
+ },
129
+ actors: {
130
+ doProcessUserRequest: (0, xstate_1.fromPromise)(async ({ input }) => {
131
+ const { context } = input;
132
+ logger.verbose("called processUserRequest action", {
133
+ speechBuffer: context.speechBuffer
134
+ });
135
+ // Stop any speech that might be playing
136
+ await context.voice.stopSpeech();
137
+ const speech = context.speechBuffer.trim();
138
+ const languageModel = context.languageModel;
139
+ const response = await languageModel.invoke(speech);
140
+ const speechResponseTime = Date.now() - context.speechResponseStartTime;
141
+ context.speechResponseTime = speechResponseTime;
142
+ context.speechResponseStartTime = 0;
143
+ logger.verbose("response from language model", {
144
+ speechResponseTime
145
+ });
146
+ try {
147
+ if (response.type === "say" && !response.content) {
148
+ logger.verbose("call might already be hung up");
149
+ return;
150
+ }
151
+ else if (response.type === "hangup") {
152
+ const message = context.goodbyeMessage;
153
+ await context.voice.say(message);
154
+ await context.voice.hangup();
155
+ return;
156
+ }
157
+ else if (response.type === "transfer") {
158
+ logger.verbose("transferring call to a number in the pstn", {
159
+ phoneNumber: context.transferPhoneNumber
160
+ });
161
+ const message = context.transferMessage;
162
+ await context.voice.say(message);
163
+ await context.voice.transfer(context.transferPhoneNumber, {
164
+ record: true,
165
+ timeout: 30
166
+ });
167
+ return;
168
+ }
169
+ await context.voice.say(response.content);
170
+ }
171
+ catch (error) {
172
+ logger.error("error processing user request", {
173
+ error
174
+ });
175
+ await context.voice.say(context.systemErrorMessage);
176
+ }
177
+ })
177
178
  }
178
179
  }).createMachine({
179
180
  context: ({ input }) => ({
@@ -224,7 +225,7 @@ const machine = (0, xstate_1.setup)({
224
225
  }
225
226
  },
226
227
  {
227
- target: "hackingTimeout",
228
+ target: "transitioningToIdle",
228
229
  actions: [
229
230
  {
230
231
  type: "increaseIdleTimeoutCount"
@@ -259,7 +260,7 @@ const machine = (0, xstate_1.setup)({
259
260
  hangup: {
260
261
  type: "final"
261
262
  },
262
- hackingTimeout: {
263
+ transitioningToIdle: {
263
264
  always: {
264
265
  target: "idle"
265
266
  }
@@ -309,14 +310,14 @@ const machine = (0, xstate_1.setup)({
309
310
  SPEECH_START: {
310
311
  target: "waitingForUserRequest",
311
312
  description: "Event from VAD or similar system."
312
- },
313
- USER_REQUEST_PROCESSED: {
314
- target: "idle",
315
- description: "Go back home."
316
313
  }
317
314
  },
318
- entry: {
319
- type: "processUserRequest"
315
+ invoke: {
316
+ src: "doProcessUserRequest",
317
+ input: ({ context }) => ({ context }),
318
+ onDone: {
319
+ target: "idle"
320
+ }
320
321
  }
321
322
  }
322
323
  }
@@ -0,0 +1,22 @@
1
+ import { LanguageModel } from "../models";
2
+ import { Voice } from "../voice";
3
+ type AutopilotContext = {
4
+ sessionRef: string;
5
+ languageModel: LanguageModel;
6
+ voice: Voice;
7
+ firstMessage: string;
8
+ goodbyeMessage: string;
9
+ transferMessage?: string;
10
+ transferPhoneNumber?: string;
11
+ systemErrorMessage: string;
12
+ idleMessage: string;
13
+ idleTimeout: number;
14
+ idleTimeoutCount: number;
15
+ maxIdleTimeoutCount: number;
16
+ speechBuffer: string;
17
+ speechResponseStartTime: number;
18
+ speechResponseTime: number;
19
+ isSpeaking: boolean;
20
+ knowledgeBaseSourceUrl?: string;
21
+ };
22
+ export { AutopilotContext };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,9 +1,11 @@
1
1
  import { InvocationResult, LanguageModel, LanguageModelParams, TelephonyContext } from "./types";
2
+ import { Voice } from "../voice";
2
3
  declare abstract class AbstractLanguageModel implements LanguageModel {
3
4
  private chain;
4
5
  private chatHistory;
5
6
  private toolsCatalog;
6
- constructor(params: LanguageModelParams, telephonyContext: TelephonyContext);
7
+ private voice;
8
+ constructor(params: LanguageModelParams, voice: Voice, telephonyContext: TelephonyContext);
7
9
  invoke(text: string): Promise<InvocationResult>;
8
10
  }
9
11
  export { AbstractLanguageModel };
@@ -23,24 +23,33 @@ const logger_1 = require("@fonoster/logger");
23
23
  const chatHistory_1 = require("./chatHistory");
24
24
  const createChain_1 = require("./createChain");
25
25
  const createPromptTemplate_1 = require("./createPromptTemplate");
26
+ const toolInvocation_1 = require("./toolInvocation");
26
27
  const tools_1 = require("../tools");
27
28
  const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
28
29
  class AbstractLanguageModel {
29
- constructor(params, telephonyContext) {
30
- const { model, systemTemplate, knowledgeBase, tools } = params;
31
- const promptTemplate = (0, createPromptTemplate_1.createPromptTemplate)(systemTemplate, telephonyContext);
30
+ constructor(params, voice, telephonyContext) {
31
+ const { model, firstMessage, systemTemplate, knowledgeBase, tools } = params;
32
32
  this.chatHistory = (0, chatHistory_1.createChatHistory)();
33
33
  this.toolsCatalog = new tools_1.ToolsCatalog(tools);
34
+ this.voice = voice;
35
+ const promptTemplate = (0, createPromptTemplate_1.createPromptTemplate)({
36
+ firstMessage,
37
+ systemTemplate,
38
+ telephonyContext
39
+ });
34
40
  this.chain = (0, createChain_1.createChain)(model, knowledgeBase, promptTemplate, this.chatHistory);
35
41
  }
36
42
  async invoke(text) {
37
43
  const { chain, chatHistory, toolsCatalog } = this;
38
44
  const response = (await chain.invoke({ text }));
45
+ let firstInvocation = true;
39
46
  if (response.additional_kwargs?.tool_calls) {
40
47
  // eslint-disable-next-line no-loops/no-loops
41
48
  for (const toolCall of response.additional_kwargs.tool_calls) {
42
49
  const { arguments: args, name } = toolCall.function;
43
- logger.verbose(`invoking tool: ${name} with args: ${args}`);
50
+ logger.verbose(`invoking tool: ${name} with args: ${args}`, {
51
+ firstInvocation
52
+ });
44
53
  switch (name) {
45
54
  case "hangup":
46
55
  await chatHistory.addAIMessage("tool result: call hangup initiated");
@@ -49,15 +58,15 @@ class AbstractLanguageModel {
49
58
  await chatHistory.addAIMessage("tool result: call transfer initiated");
50
59
  return { type: "transfer" };
51
60
  default:
52
- try {
53
- const toolResult = await toolsCatalog.invokeTool(name, JSON.parse(args));
54
- logger.verbose("tool result: ", toolResult);
55
- await chatHistory.addAIMessage(`tool result: ${toolResult.result}`);
56
- }
57
- catch (error) {
58
- logger.error(`tool error: ${error.message}`);
59
- await chatHistory.addAIMessage(`tool error: ${error.message}`);
60
- }
61
+ await (0, toolInvocation_1.toolInvocation)({
62
+ args,
63
+ chatHistory,
64
+ firstInvocation,
65
+ toolName: name,
66
+ toolsCatalog,
67
+ voice: this.voice
68
+ });
69
+ firstInvocation = false;
61
70
  }
62
71
  }
63
72
  const finalResponse = (await chain.invoke({
@@ -4,7 +4,8 @@ import { OllamaParams } from "./ollama";
4
4
  import { OpenAIParams } from "./openai";
5
5
  import { BaseModelParams, TelephonyContext } from "./types";
6
6
  import { LANGUAGE_MODEL_PROVIDER } from "../types";
7
- type LanguageModelConstructor<T extends BaseModelParams = BaseModelParams> = new (options: T, telephonyContext: TelephonyContext) => AbstractLanguageModel;
7
+ import { Voice } from "../voice";
8
+ type LanguageModelConstructor<T extends BaseModelParams = BaseModelParams> = new (options: T, voice: Voice, telephonyContext: TelephonyContext) => AbstractLanguageModel;
8
9
  type LanguageModelConfigMap = {
9
10
  [LANGUAGE_MODEL_PROVIDER.OPENAI]: OpenAIParams;
10
11
  [LANGUAGE_MODEL_PROVIDER.GROQ]: GroqParams;
@@ -13,6 +14,6 @@ type LanguageModelConfigMap = {
13
14
  declare class LanguageModelFactory {
14
15
  private static languageModels;
15
16
  static registerLanguageModel<T extends BaseModelParams>(name: string, ctor: LanguageModelConstructor<T>): void;
16
- static getLanguageModel<T extends keyof LanguageModelConfigMap>(languageModel: T, config: LanguageModelConfigMap[T], telephonyContext: TelephonyContext): AbstractLanguageModel;
17
+ static getLanguageModel<T extends keyof LanguageModelConfigMap>(languageModel: T, config: LanguageModelConfigMap[T], voice: Voice, telephonyContext: TelephonyContext): AbstractLanguageModel;
17
18
  }
18
19
  export { LanguageModelFactory };
@@ -30,12 +30,12 @@ class LanguageModelFactory {
30
30
  logger.verbose("registering llm provider", { name });
31
31
  this.languageModels.set(name, ctor);
32
32
  }
33
- static getLanguageModel(languageModel, config, telephonyContext) {
33
+ static getLanguageModel(languageModel, config, voice, telephonyContext) {
34
34
  const LanguageModelConstructor = this.languageModels.get(`llm.${languageModel}`);
35
35
  if (!LanguageModelConstructor) {
36
36
  throw new Error(`Language model ${languageModel} not found`);
37
37
  }
38
- return new LanguageModelConstructor(config, telephonyContext);
38
+ return new LanguageModelConstructor(config, voice, telephonyContext);
39
39
  }
40
40
  }
41
41
  exports.LanguageModelFactory = LanguageModelFactory;
@@ -1,3 +1,7 @@
1
1
  import { ChatPromptTemplate } from "@langchain/core/prompts";
2
2
  import { TelephonyContext } from "./types";
3
- export declare function createPromptTemplate(systemTemplate: string, telephonyContext: TelephonyContext): ChatPromptTemplate<any, any>;
3
+ export declare function createPromptTemplate(params: {
4
+ firstMessage: string;
5
+ systemTemplate: string;
6
+ telephonyContext: TelephonyContext;
7
+ }): ChatPromptTemplate<any, any>;
@@ -20,14 +20,17 @@ exports.createPromptTemplate = createPromptTemplate;
20
20
  * limitations under the License.
21
21
  */
22
22
  const prompts_1 = require("@langchain/core/prompts");
23
- function createPromptTemplate(systemTemplate, telephonyContext) {
23
+ function createPromptTemplate(params) {
24
+ const { firstMessage, systemTemplate, telephonyContext } = params;
24
25
  return prompts_1.ChatPromptTemplate.fromMessages([
25
26
  new prompts_1.MessagesPlaceholder("history"),
27
+ prompts_1.SystemMessagePromptTemplate.fromTemplate(`firstMessage: ${firstMessage}`),
26
28
  prompts_1.SystemMessagePromptTemplate.fromTemplate(systemTemplate),
27
29
  prompts_1.SystemMessagePromptTemplate.fromTemplate("{context}"),
28
30
  prompts_1.SystemMessagePromptTemplate.fromTemplate(`callReceivedAt:${new Date().toISOString()}
29
31
  ingressNumber:${telephonyContext.ingressNumber}
30
- callerNumber:${telephonyContext.callerNumber}`),
32
+ callerNumber:${telephonyContext.callerNumber}
33
+ callDirection:${telephonyContext.callDirection}`),
31
34
  prompts_1.HumanMessagePromptTemplate.fromTemplate("{input}")
32
35
  ]);
33
36
  }
@@ -1,8 +1,9 @@
1
1
  import { GroqParams } from "./types";
2
+ import { Voice } from "../../voice";
2
3
  import { AbstractLanguageModel } from "../AbstractLanguageModel";
3
4
  import { TelephonyContext } from "../types";
4
5
  declare const LANGUAGE_MODEL_NAME = "llm.groq";
5
6
  declare class Groq extends AbstractLanguageModel {
6
- constructor(params: GroqParams, telephonyContext: TelephonyContext);
7
+ constructor(params: GroqParams, voice: Voice, telephonyContext: TelephonyContext);
7
8
  }
8
9
  export { Groq, LANGUAGE_MODEL_NAME };
@@ -7,7 +7,7 @@ const AbstractLanguageModel_1 = require("../AbstractLanguageModel");
7
7
  const LANGUAGE_MODEL_NAME = "llm.groq";
8
8
  exports.LANGUAGE_MODEL_NAME = LANGUAGE_MODEL_NAME;
9
9
  class Groq extends AbstractLanguageModel_1.AbstractLanguageModel {
10
- constructor(params, telephonyContext) {
10
+ constructor(params, voice, telephonyContext) {
11
11
  const model = new groq_1.ChatGroq({
12
12
  ...params
13
13
  }).bind({
@@ -16,7 +16,7 @@ class Groq extends AbstractLanguageModel_1.AbstractLanguageModel {
16
16
  super({
17
17
  ...params,
18
18
  model
19
- }, telephonyContext);
19
+ }, voice, telephonyContext);
20
20
  }
21
21
  }
22
22
  exports.Groq = Groq;
@@ -1,8 +1,9 @@
1
1
  import { OllamaParams } from "./types";
2
+ import { Voice } from "../../voice";
2
3
  import { AbstractLanguageModel } from "../AbstractLanguageModel";
3
4
  import { TelephonyContext } from "../types";
4
5
  declare const LANGUAGE_MODEL_NAME = "llm.ollama";
5
6
  declare class Ollama extends AbstractLanguageModel {
6
- constructor(params: OllamaParams, telephonyContext: TelephonyContext);
7
+ constructor(params: OllamaParams, voice: Voice, telephonyContext: TelephonyContext);
7
8
  }
8
9
  export { LANGUAGE_MODEL_NAME, Ollama };
@@ -7,7 +7,7 @@ const AbstractLanguageModel_1 = require("../AbstractLanguageModel");
7
7
  const LANGUAGE_MODEL_NAME = "llm.ollama";
8
8
  exports.LANGUAGE_MODEL_NAME = LANGUAGE_MODEL_NAME;
9
9
  class Ollama extends AbstractLanguageModel_1.AbstractLanguageModel {
10
- constructor(params, telephonyContext) {
10
+ constructor(params, voice, telephonyContext) {
11
11
  const model = new ollama_1.ChatOllama({
12
12
  ...params
13
13
  }).bind({
@@ -16,7 +16,7 @@ class Ollama extends AbstractLanguageModel_1.AbstractLanguageModel {
16
16
  super({
17
17
  ...params,
18
18
  model
19
- }, telephonyContext);
19
+ }, voice, telephonyContext);
20
20
  }
21
21
  }
22
22
  exports.Ollama = Ollama;
@@ -1,8 +1,9 @@
1
1
  import { OpenAIParams } from "./types";
2
+ import { Voice } from "../../voice";
2
3
  import { AbstractLanguageModel } from "../AbstractLanguageModel";
3
4
  import { TelephonyContext } from "../types";
4
5
  declare const LANGUAGE_MODEL_NAME = "llm.openai";
5
6
  declare class OpenAI extends AbstractLanguageModel {
6
- constructor(params: OpenAIParams, telephonyContext: TelephonyContext);
7
+ constructor(params: OpenAIParams, voice: Voice, telephonyContext: TelephonyContext);
7
8
  }
8
9
  export { LANGUAGE_MODEL_NAME, OpenAI };
@@ -7,7 +7,7 @@ const AbstractLanguageModel_1 = require("../AbstractLanguageModel");
7
7
  const LANGUAGE_MODEL_NAME = "llm.openai";
8
8
  exports.LANGUAGE_MODEL_NAME = LANGUAGE_MODEL_NAME;
9
9
  class OpenAI extends AbstractLanguageModel_1.AbstractLanguageModel {
10
- constructor(params, telephonyContext) {
10
+ constructor(params, voice, telephonyContext) {
11
11
  const model = new openai_1.ChatOpenAI({
12
12
  ...params
13
13
  }).bind({
@@ -16,7 +16,7 @@ class OpenAI extends AbstractLanguageModel_1.AbstractLanguageModel {
16
16
  super({
17
17
  ...params,
18
18
  model
19
- }, telephonyContext);
19
+ }, voice, telephonyContext);
20
20
  }
21
21
  }
22
22
  exports.OpenAI = OpenAI;
@@ -0,0 +1,12 @@
1
+ import { createChatHistory } from "./chatHistory";
2
+ import { ToolsCatalog } from "../tools";
3
+ import { Voice } from "../voice";
4
+ declare function toolInvocation(params: {
5
+ toolName: string;
6
+ chatHistory: ReturnType<typeof createChatHistory>;
7
+ toolsCatalog: ToolsCatalog;
8
+ firstInvocation: boolean;
9
+ args: string;
10
+ voice: Voice;
11
+ }): Promise<void>;
12
+ export { toolInvocation };
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolInvocation = toolInvocation;
4
+ /*
5
+ * Copyright (C) 2024 by Fonoster Inc (https://fonoster.com)
6
+ * http://github.com/fonoster/fonoster
7
+ *
8
+ * This file is part of Fonoster
9
+ *
10
+ * Licensed under the MIT License (the "License");
11
+ * you may not use this file except in compliance with
12
+ * the License. You may obtain a copy of the License at
13
+ *
14
+ * https://opensource.org/licenses/MIT
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+ const logger_1 = require("@fonoster/logger");
23
+ const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
24
+ async function toolInvocation(params) {
25
+ const { firstInvocation, voice, args, toolName, chatHistory, toolsCatalog } = params;
26
+ try {
27
+ if (firstInvocation) {
28
+ const tool = toolsCatalog.getTool(toolName);
29
+ const message = tool?.requestStartMessage ?? "";
30
+ if (message) {
31
+ await voice.say(message);
32
+ }
33
+ }
34
+ const toolResult = await toolsCatalog.invokeTool(toolName, JSON.parse(args));
35
+ logger.verbose("tool result: ", toolResult);
36
+ await chatHistory.addAIMessage(`tool result: ${toolResult.result}`);
37
+ }
38
+ catch (error) {
39
+ logger.error(`tool error: ${error.message}`);
40
+ await chatHistory.addAIMessage(`tool error: ${error.message}`);
41
+ }
42
+ }
@@ -1,3 +1,4 @@
1
+ import { CallDirection } from "@fonoster/types";
1
2
  import { BaseChatModel } from "@langchain/core/language_models/chat_models";
2
3
  import { KnowledgeBase } from "../knowledge";
3
4
  import { Tool } from "../tools/type";
@@ -5,6 +6,7 @@ type LanguageModel = {
5
6
  invoke: (text: string) => Promise<InvocationResult>;
6
7
  };
7
8
  type BaseModelParams = {
9
+ firstMessage: string;
8
10
  systemTemplate: string;
9
11
  knowledgeBase: KnowledgeBase;
10
12
  tools: Tool[];
@@ -18,6 +20,7 @@ type InvocationResult = {
18
20
  content?: string;
19
21
  };
20
22
  type TelephonyContext = {
23
+ callDirection: CallDirection;
21
24
  ingressNumber: string;
22
25
  callerNumber: string;
23
26
  };
@@ -48,6 +48,7 @@ declare const toolSchema: z.ZodObject<{
48
48
  }>;
49
49
  required?: string[] | undefined;
50
50
  }>;
51
+ requestStartMessage: z.ZodOptional<z.ZodString>;
51
52
  operation: z.ZodEffects<z.ZodObject<{
52
53
  type: z.ZodNativeEnum<typeof AllowedOperations>;
53
54
  url: z.ZodOptional<z.ZodString>;
@@ -92,6 +93,7 @@ declare const toolSchema: z.ZodObject<{
92
93
  waitForResponse?: boolean | undefined;
93
94
  headers?: Record<string, string> | undefined;
94
95
  };
96
+ requestStartMessage?: string | undefined;
95
97
  }, {
96
98
  name: string;
97
99
  description: string;
@@ -110,5 +112,6 @@ declare const toolSchema: z.ZodObject<{
110
112
  waitForResponse?: boolean | undefined;
111
113
  headers?: Record<string, string> | undefined;
112
114
  };
115
+ requestStartMessage?: string | undefined;
113
116
  }>;
114
117
  export { AllowedOperations, toolSchema };
@@ -45,6 +45,7 @@ const toolSchema = zod_1.z.object({
45
45
  properties: zod_1.z.record(propertySchema),
46
46
  required: zod_1.z.array(zod_1.z.string()).optional()
47
47
  }),
48
+ requestStartMessage: zod_1.z.string().optional(),
48
49
  operation: zod_1.z
49
50
  .object({
50
51
  type: zod_1.z.nativeEnum(AllowedOperations),
@@ -5,6 +5,7 @@ declare class ToolsCatalog {
5
5
  invokeTool(toolName: string, args: Record<string, unknown>): Promise<{
6
6
  result: string;
7
7
  }>;
8
+ getTool(toolName: string): Tool | undefined;
8
9
  addTool(toolDef: Tool): void;
9
10
  listTools(): Tool[];
10
11
  }
@@ -43,6 +43,9 @@ class ToolsCatalog {
43
43
  body: args
44
44
  });
45
45
  }
46
+ getTool(toolName) {
47
+ return this.tools.get(toolName);
48
+ }
46
49
  addTool(toolDef) {
47
50
  this.tools.set(toolDef.name, toolDef);
48
51
  }
@@ -19,18 +19,24 @@ exports.sendRequest = sendRequest;
19
19
  * See the License for the specific language governing permissions and
20
20
  * limitations under the License.
21
21
  */
22
+ const logger_1 = require("@fonoster/logger");
22
23
  const zod_1 = require("zod");
23
24
  const ToolSchema_1 = require("./ToolSchema");
24
25
  const responseSchema = zod_1.z.object({
25
26
  result: zod_1.z.string()
26
27
  });
28
+ const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
27
29
  async function sendRequest(input) {
28
30
  const { url, method, body, headers, waitForResponse } = input;
29
31
  const options = {
30
32
  method,
31
- headers,
33
+ headers: {
34
+ "Content-Type": "application/json",
35
+ ...headers
36
+ },
32
37
  body: method === ToolSchema_1.AllowedOperations.POST ? JSON.stringify(body) : undefined
33
38
  };
39
+ logger.verbose(`sending request to ${url}`, { body, method });
34
40
  if (waitForResponse && method === ToolSchema_1.AllowedOperations.POST) {
35
41
  setTimeout(() => fetch(url, options), 0);
36
42
  return { result: "request sent" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fonoster/autopilot",
3
- "version": "0.7.16",
3
+ "version": "0.7.18",
4
4
  "description": "Voice AI for the Fonoster platform",
5
5
  "author": "Pedro Sanders <psanders@fonoster.com>",
6
6
  "homepage": "https://github.com/fonoster/fonoster#readme",
@@ -35,10 +35,10 @@
35
35
  "url": "https://github.com/fonoster/fonoster/issues"
36
36
  },
37
37
  "dependencies": {
38
- "@fonoster/common": "^0.7.16",
39
- "@fonoster/logger": "^0.7.16",
40
- "@fonoster/types": "^0.7.16",
41
- "@fonoster/voice": "^0.7.16",
38
+ "@fonoster/common": "^0.7.18",
39
+ "@fonoster/logger": "^0.7.18",
40
+ "@fonoster/types": "^0.7.18",
41
+ "@fonoster/voice": "^0.7.18",
42
42
  "@langchain/community": "^0.2.31",
43
43
  "@langchain/core": "^0.2.32",
44
44
  "@langchain/groq": "^0.0.17",
@@ -56,5 +56,5 @@
56
56
  "devDependencies": {
57
57
  "typescript": "^5.5.4"
58
58
  },
59
- "gitHead": "1d2898f38de4690f0b9c2dac5506c2ddaeebedbb"
59
+ "gitHead": "4150dcb8086de182d0650df0c6d990ee76658058"
60
60
  }