@fonoster/autopilot 0.7.14 → 0.7.16

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
@@ -40,7 +40,8 @@ The configuration file has two major sections: `conversationSettings` and `langu
40
40
  "initialDtmf": "6589",
41
41
  "transferOptions": {
42
42
  "phoneNumber": "+15555555555",
43
- "message": "Please hold while I transfer you to a live agent."
43
+ "message": "Please hold while I transfer you to a live agent.",
44
+ "timeout": 30000
44
45
  },
45
46
  "idleOptions": {
46
47
  "message": "Are you still there?",
@@ -127,7 +128,10 @@ You can configure a new tool by adding a new entry in the `tools` array in the c
127
128
  },
128
129
  "operation": {
129
130
  "type": "get",
130
- "url": "https://api.example.com/appointment-times"
131
+ "url": "https://api.example.com/appointment-times",
132
+ "headers": {
133
+ "x-api-key": "your-api-key"
134
+ }
131
135
  }
132
136
  }
133
137
  ]
@@ -137,6 +141,8 @@ You can configure a new tool by adding a new entry in the `tools` array in the c
137
141
 
138
142
  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.
139
143
 
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
+
140
146
  The expected format for the response is a JSON object with the following structure:
141
147
 
142
148
  ```json
@@ -67,9 +67,11 @@ declare const conversationSettingsSchema: z.ZodObject<{
67
67
  }>;
68
68
  declare const languageModelConfigSchema: z.ZodObject<{
69
69
  provider: z.ZodNativeEnum<typeof LANGUAGE_MODEL_PROVIDER>;
70
+ apiKey: z.ZodOptional<z.ZodString>;
70
71
  model: z.ZodString;
71
72
  temperature: z.ZodNumber;
72
73
  maxTokens: z.ZodNumber;
74
+ baseUrl: z.ZodOptional<z.ZodString>;
73
75
  knowledgeBase: z.ZodArray<z.ZodObject<{
74
76
  type: z.ZodEnum<["s3", "file"]>;
75
77
  title: z.ZodString;
@@ -131,22 +133,27 @@ declare const languageModelConfigSchema: z.ZodObject<{
131
133
  type: z.ZodNativeEnum<typeof import("../tools/ToolSchema").AllowedOperations>;
132
134
  url: z.ZodOptional<z.ZodString>;
133
135
  waitForResponse: z.ZodOptional<z.ZodBoolean>;
136
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
134
137
  }, "strip", z.ZodTypeAny, {
135
138
  type: import("../tools/ToolSchema").AllowedOperations;
136
139
  url?: string | undefined;
137
140
  waitForResponse?: boolean | undefined;
141
+ headers?: Record<string, string> | undefined;
138
142
  }, {
139
143
  type: import("../tools/ToolSchema").AllowedOperations;
140
144
  url?: string | undefined;
141
145
  waitForResponse?: boolean | undefined;
146
+ headers?: Record<string, string> | undefined;
142
147
  }>, {
143
148
  type: import("../tools/ToolSchema").AllowedOperations;
144
149
  url?: string | undefined;
145
150
  waitForResponse?: boolean | undefined;
151
+ headers?: Record<string, string> | undefined;
146
152
  }, {
147
153
  type: import("../tools/ToolSchema").AllowedOperations;
148
154
  url?: string | undefined;
149
155
  waitForResponse?: boolean | undefined;
156
+ headers?: Record<string, string> | undefined;
150
157
  }>;
151
158
  }, "strip", z.ZodTypeAny, {
152
159
  name: string;
@@ -164,6 +171,7 @@ declare const languageModelConfigSchema: z.ZodObject<{
164
171
  type: import("../tools/ToolSchema").AllowedOperations;
165
172
  url?: string | undefined;
166
173
  waitForResponse?: boolean | undefined;
174
+ headers?: Record<string, string> | undefined;
167
175
  };
168
176
  }, {
169
177
  name: string;
@@ -181,6 +189,7 @@ declare const languageModelConfigSchema: z.ZodObject<{
181
189
  type: import("../tools/ToolSchema").AllowedOperations;
182
190
  url?: string | undefined;
183
191
  waitForResponse?: boolean | undefined;
192
+ headers?: Record<string, string> | undefined;
184
193
  };
185
194
  }>, "many">;
186
195
  }, "strip", z.ZodTypeAny, {
@@ -206,11 +215,14 @@ declare const languageModelConfigSchema: z.ZodObject<{
206
215
  type: import("../tools/ToolSchema").AllowedOperations;
207
216
  url?: string | undefined;
208
217
  waitForResponse?: boolean | undefined;
218
+ headers?: Record<string, string> | undefined;
209
219
  };
210
220
  }[];
211
221
  temperature: number;
212
222
  maxTokens: number;
213
223
  provider: LANGUAGE_MODEL_PROVIDER;
224
+ apiKey?: string | undefined;
225
+ baseUrl?: string | undefined;
214
226
  }, {
215
227
  model: string;
216
228
  knowledgeBase: {
@@ -234,11 +246,14 @@ declare const languageModelConfigSchema: z.ZodObject<{
234
246
  type: import("../tools/ToolSchema").AllowedOperations;
235
247
  url?: string | undefined;
236
248
  waitForResponse?: boolean | undefined;
249
+ headers?: Record<string, string> | undefined;
237
250
  };
238
251
  }[];
239
252
  temperature: number;
240
253
  maxTokens: number;
241
254
  provider: LANGUAGE_MODEL_PROVIDER;
255
+ apiKey?: string | undefined;
256
+ baseUrl?: string | undefined;
242
257
  }>;
243
258
  declare const assistantSchema: z.ZodObject<{
244
259
  conversationSettings: z.ZodObject<{
@@ -308,9 +323,11 @@ declare const assistantSchema: z.ZodObject<{
308
323
  }>;
309
324
  languageModel: z.ZodObject<{
310
325
  provider: z.ZodNativeEnum<typeof LANGUAGE_MODEL_PROVIDER>;
326
+ apiKey: z.ZodOptional<z.ZodString>;
311
327
  model: z.ZodString;
312
328
  temperature: z.ZodNumber;
313
329
  maxTokens: z.ZodNumber;
330
+ baseUrl: z.ZodOptional<z.ZodString>;
314
331
  knowledgeBase: z.ZodArray<z.ZodObject<{
315
332
  type: z.ZodEnum<["s3", "file"]>;
316
333
  title: z.ZodString;
@@ -372,22 +389,27 @@ declare const assistantSchema: z.ZodObject<{
372
389
  type: z.ZodNativeEnum<typeof import("../tools/ToolSchema").AllowedOperations>;
373
390
  url: z.ZodOptional<z.ZodString>;
374
391
  waitForResponse: z.ZodOptional<z.ZodBoolean>;
392
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
375
393
  }, "strip", z.ZodTypeAny, {
376
394
  type: import("../tools/ToolSchema").AllowedOperations;
377
395
  url?: string | undefined;
378
396
  waitForResponse?: boolean | undefined;
397
+ headers?: Record<string, string> | undefined;
379
398
  }, {
380
399
  type: import("../tools/ToolSchema").AllowedOperations;
381
400
  url?: string | undefined;
382
401
  waitForResponse?: boolean | undefined;
402
+ headers?: Record<string, string> | undefined;
383
403
  }>, {
384
404
  type: import("../tools/ToolSchema").AllowedOperations;
385
405
  url?: string | undefined;
386
406
  waitForResponse?: boolean | undefined;
407
+ headers?: Record<string, string> | undefined;
387
408
  }, {
388
409
  type: import("../tools/ToolSchema").AllowedOperations;
389
410
  url?: string | undefined;
390
411
  waitForResponse?: boolean | undefined;
412
+ headers?: Record<string, string> | undefined;
391
413
  }>;
392
414
  }, "strip", z.ZodTypeAny, {
393
415
  name: string;
@@ -405,6 +427,7 @@ declare const assistantSchema: z.ZodObject<{
405
427
  type: import("../tools/ToolSchema").AllowedOperations;
406
428
  url?: string | undefined;
407
429
  waitForResponse?: boolean | undefined;
430
+ headers?: Record<string, string> | undefined;
408
431
  };
409
432
  }, {
410
433
  name: string;
@@ -422,6 +445,7 @@ declare const assistantSchema: z.ZodObject<{
422
445
  type: import("../tools/ToolSchema").AllowedOperations;
423
446
  url?: string | undefined;
424
447
  waitForResponse?: boolean | undefined;
448
+ headers?: Record<string, string> | undefined;
425
449
  };
426
450
  }>, "many">;
427
451
  }, "strip", z.ZodTypeAny, {
@@ -447,11 +471,14 @@ declare const assistantSchema: z.ZodObject<{
447
471
  type: import("../tools/ToolSchema").AllowedOperations;
448
472
  url?: string | undefined;
449
473
  waitForResponse?: boolean | undefined;
474
+ headers?: Record<string, string> | undefined;
450
475
  };
451
476
  }[];
452
477
  temperature: number;
453
478
  maxTokens: number;
454
479
  provider: LANGUAGE_MODEL_PROVIDER;
480
+ apiKey?: string | undefined;
481
+ baseUrl?: string | undefined;
455
482
  }, {
456
483
  model: string;
457
484
  knowledgeBase: {
@@ -475,11 +502,14 @@ declare const assistantSchema: z.ZodObject<{
475
502
  type: import("../tools/ToolSchema").AllowedOperations;
476
503
  url?: string | undefined;
477
504
  waitForResponse?: boolean | undefined;
505
+ headers?: Record<string, string> | undefined;
478
506
  };
479
507
  }[];
480
508
  temperature: number;
481
509
  maxTokens: number;
482
510
  provider: LANGUAGE_MODEL_PROVIDER;
511
+ apiKey?: string | undefined;
512
+ baseUrl?: string | undefined;
483
513
  }>;
484
514
  }, "strip", z.ZodTypeAny, {
485
515
  conversationSettings: {
@@ -522,11 +552,14 @@ declare const assistantSchema: z.ZodObject<{
522
552
  type: import("../tools/ToolSchema").AllowedOperations;
523
553
  url?: string | undefined;
524
554
  waitForResponse?: boolean | undefined;
555
+ headers?: Record<string, string> | undefined;
525
556
  };
526
557
  }[];
527
558
  temperature: number;
528
559
  maxTokens: number;
529
560
  provider: LANGUAGE_MODEL_PROVIDER;
561
+ apiKey?: string | undefined;
562
+ baseUrl?: string | undefined;
530
563
  };
531
564
  }, {
532
565
  conversationSettings: {
@@ -569,11 +602,14 @@ declare const assistantSchema: z.ZodObject<{
569
602
  type: import("../tools/ToolSchema").AllowedOperations;
570
603
  url?: string | undefined;
571
604
  waitForResponse?: boolean | undefined;
605
+ headers?: Record<string, string> | undefined;
572
606
  };
573
607
  }[];
574
608
  temperature: number;
575
609
  maxTokens: number;
576
610
  provider: LANGUAGE_MODEL_PROVIDER;
611
+ apiKey?: string | undefined;
612
+ baseUrl?: string | undefined;
577
613
  };
578
614
  }>;
579
615
  export { assistantSchema, conversationSettingsSchema, languageModelConfigSchema };
@@ -48,9 +48,11 @@ const conversationSettingsSchema = zod_1.z.object({
48
48
  exports.conversationSettingsSchema = conversationSettingsSchema;
49
49
  const languageModelConfigSchema = zod_1.z.object({
50
50
  provider: zod_1.z.nativeEnum(types_1.LANGUAGE_MODEL_PROVIDER),
51
+ apiKey: zod_1.z.string().optional(),
51
52
  model: zod_1.z.string(),
52
53
  temperature: zod_1.z.number(),
53
54
  maxTokens: zod_1.z.number(),
55
+ baseUrl: zod_1.z.string().optional(),
54
56
  knowledgeBase: zod_1.z.array(zod_1.z.object({
55
57
  type: zod_1.z.enum(["s3", "file"]),
56
58
  title: zod_1.z.string(),
@@ -1,3 +1,3 @@
1
- import { AssistantConfig, FilesKnowledgeBase } from ".";
2
- declare function createLanguageModel(assistantConfig: AssistantConfig, knowledgeBase: FilesKnowledgeBase): import("./models/AbstractLanguageModel").AbstractLanguageModel;
1
+ import { AssistantConfig, FilesKnowledgeBase, TelephonyContext } from ".";
2
+ declare function createLanguageModel(assistantConfig: AssistantConfig, knowledgeBase: FilesKnowledgeBase, telephonyContext: TelephonyContext): import("./models/AbstractLanguageModel").AbstractLanguageModel;
3
3
  export { createLanguageModel };
@@ -19,22 +19,22 @@ exports.createLanguageModel = createLanguageModel;
19
19
  * See the License for the specific language governing permissions and
20
20
  * limitations under the License.
21
21
  */
22
- const envs_1 = require("./envs");
23
22
  const _1 = require(".");
24
- function createLanguageModel(assistantConfig, knowledgeBase) {
23
+ function createLanguageModel(assistantConfig, knowledgeBase, telephonyContext) {
25
24
  const { languageModel: languageModelSettings, conversationSettings } = assistantConfig;
26
25
  return _1.LanguageModelFactory.getLanguageModel(languageModelSettings.provider, {
27
- apiKey: envs_1.OPENAI_API_KEY,
26
+ apiKey: languageModelSettings.apiKey,
28
27
  // @ts-expect-error don't know the model type here
29
28
  model: languageModelSettings.model,
30
29
  maxTokens: languageModelSettings.maxTokens,
31
30
  temperature: languageModelSettings.temperature,
32
31
  systemTemplate: conversationSettings.systemTemplate,
32
+ baseUrl: languageModelSettings.baseUrl,
33
33
  knowledgeBase,
34
34
  tools: [
35
35
  ...languageModelSettings.tools,
36
36
  _1.hangupToolDefinition,
37
37
  _1.transferToolDefinition
38
38
  ]
39
- });
39
+ }, telephonyContext);
40
40
  }
@@ -56,7 +56,10 @@ async function handleVoiceRequest(req, res) {
56
56
  const knowledgeBase = await (0, loadKnowledgeBase_1.loadKnowledgeBase)();
57
57
  const voice = new _1.VoiceImpl(sessionRef, res);
58
58
  const vad = new _1.SileroVad();
59
- const languageModel = (0, createLanguageModel_1.createLanguageModel)(assistantConfig, knowledgeBase);
59
+ const languageModel = (0, createLanguageModel_1.createLanguageModel)(assistantConfig, knowledgeBase, {
60
+ ingressNumber: req.ingressNumber,
61
+ callerNumber: req.callerNumber
62
+ });
60
63
  const autopilot = new _1.default({
61
64
  conversationSettings: assistantConfig.conversationSettings,
62
65
  voice,
@@ -84,6 +84,9 @@ const machine = (0, xstate_1.setup)({
84
84
  return;
85
85
  }
86
86
  else if (response.type === "transfer") {
87
+ logger.verbose("transferring call to a number in the pstn", {
88
+ phoneNumber: context.transferPhoneNumber
89
+ });
87
90
  const message = context.transferMessage;
88
91
  await context.voice.say(message);
89
92
  await context.voice.transfer(context.transferPhoneNumber, {
@@ -1,11 +1,9 @@
1
- import { InvocationResult, LanguageModel, LanguageModelParams } from "./types";
2
- import { ToolsCatalog } from "../tools";
1
+ import { InvocationResult, LanguageModel, LanguageModelParams, TelephonyContext } from "./types";
3
2
  declare abstract class AbstractLanguageModel implements LanguageModel {
4
- private params;
5
3
  private chain;
6
4
  private chatHistory;
7
- toolsCatalog: ToolsCatalog;
8
- constructor(params: LanguageModelParams);
5
+ private toolsCatalog;
6
+ constructor(params: LanguageModelParams, telephonyContext: TelephonyContext);
9
7
  invoke(text: string): Promise<InvocationResult>;
10
8
  }
11
9
  export { AbstractLanguageModel };
@@ -26,10 +26,9 @@ const createPromptTemplate_1 = require("./createPromptTemplate");
26
26
  const tools_1 = require("../tools");
27
27
  const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
28
28
  class AbstractLanguageModel {
29
- constructor(params) {
30
- this.params = params;
31
- const { model, systemTemplate, knowledgeBase, tools } = this.params;
32
- const promptTemplate = (0, createPromptTemplate_1.createPromptTemplate)(systemTemplate);
29
+ constructor(params, telephonyContext) {
30
+ const { model, systemTemplate, knowledgeBase, tools } = params;
31
+ const promptTemplate = (0, createPromptTemplate_1.createPromptTemplate)(systemTemplate, telephonyContext);
33
32
  this.chatHistory = (0, chatHistory_1.createChatHistory)();
34
33
  this.toolsCatalog = new tools_1.ToolsCatalog(tools);
35
34
  this.chain = (0, createChain_1.createChain)(model, knowledgeBase, promptTemplate, this.chatHistory);
@@ -1,16 +1,18 @@
1
1
  import { AbstractLanguageModel } from "./AbstractLanguageModel";
2
2
  import { GroqParams } from "./groq";
3
+ import { OllamaParams } from "./ollama";
3
4
  import { OpenAIParams } from "./openai";
4
- import { BaseModelParams } from "./types";
5
+ import { BaseModelParams, TelephonyContext } from "./types";
5
6
  import { LANGUAGE_MODEL_PROVIDER } from "../types";
6
- type LanguageModelConstructor<T extends BaseModelParams = BaseModelParams> = new (options: T) => AbstractLanguageModel;
7
+ type LanguageModelConstructor<T extends BaseModelParams = BaseModelParams> = new (options: T, telephonyContext: TelephonyContext) => AbstractLanguageModel;
7
8
  type LanguageModelConfigMap = {
8
9
  [LANGUAGE_MODEL_PROVIDER.OPENAI]: OpenAIParams;
9
10
  [LANGUAGE_MODEL_PROVIDER.GROQ]: GroqParams;
11
+ [LANGUAGE_MODEL_PROVIDER.OLLAMA]: OllamaParams;
10
12
  };
11
13
  declare class LanguageModelFactory {
12
14
  private static languageModels;
13
15
  static registerLanguageModel<T extends BaseModelParams>(name: string, ctor: LanguageModelConstructor<T>): void;
14
- static getLanguageModel<T extends keyof LanguageModelConfigMap>(languageModel: T, config: LanguageModelConfigMap[T]): AbstractLanguageModel;
16
+ static getLanguageModel<T extends keyof LanguageModelConfigMap>(languageModel: T, config: LanguageModelConfigMap[T], telephonyContext: TelephonyContext): AbstractLanguageModel;
15
17
  }
16
18
  export { LanguageModelFactory };
@@ -21,6 +21,7 @@ exports.LanguageModelFactory = void 0;
21
21
  */
22
22
  const logger_1 = require("@fonoster/logger");
23
23
  const groq_1 = require("./groq");
24
+ const ollama_1 = require("./ollama");
24
25
  const openai_1 = require("./openai");
25
26
  const types_1 = require("../types");
26
27
  const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
@@ -29,12 +30,12 @@ class LanguageModelFactory {
29
30
  logger.verbose("registering llm provider", { name });
30
31
  this.languageModels.set(name, ctor);
31
32
  }
32
- static getLanguageModel(languageModel, config) {
33
+ static getLanguageModel(languageModel, config, telephonyContext) {
33
34
  const LanguageModelConstructor = this.languageModels.get(`llm.${languageModel}`);
34
35
  if (!LanguageModelConstructor) {
35
36
  throw new Error(`Language model ${languageModel} not found`);
36
37
  }
37
- return new LanguageModelConstructor(config);
38
+ return new LanguageModelConstructor(config, telephonyContext);
38
39
  }
39
40
  }
40
41
  exports.LanguageModelFactory = LanguageModelFactory;
@@ -42,3 +43,4 @@ LanguageModelFactory.languageModels = new Map();
42
43
  // Register language models
43
44
  LanguageModelFactory.registerLanguageModel(openai_1.LANGUAGE_MODEL_NAME, openai_1.OpenAI);
44
45
  LanguageModelFactory.registerLanguageModel(groq_1.LANGUAGE_MODEL_NAME, groq_1.Groq);
46
+ LanguageModelFactory.registerLanguageModel(ollama_1.LANGUAGE_MODEL_NAME, ollama_1.Ollama);
@@ -1,2 +1,3 @@
1
1
  import { ChatPromptTemplate } from "@langchain/core/prompts";
2
- export declare function createPromptTemplate(systemTemplate: string): ChatPromptTemplate<any, any>;
2
+ import { TelephonyContext } from "./types";
3
+ export declare function createPromptTemplate(systemTemplate: string, telephonyContext: TelephonyContext): ChatPromptTemplate<any, any>;
@@ -20,13 +20,14 @@ exports.createPromptTemplate = createPromptTemplate;
20
20
  * limitations under the License.
21
21
  */
22
22
  const prompts_1 = require("@langchain/core/prompts");
23
- function createPromptTemplate(systemTemplate) {
23
+ function createPromptTemplate(systemTemplate, telephonyContext) {
24
24
  return prompts_1.ChatPromptTemplate.fromMessages([
25
25
  new prompts_1.MessagesPlaceholder("history"),
26
26
  prompts_1.SystemMessagePromptTemplate.fromTemplate(systemTemplate),
27
27
  prompts_1.SystemMessagePromptTemplate.fromTemplate("{context}"),
28
- // This is how the model will know the current date
29
- prompts_1.SystemMessagePromptTemplate.fromTemplate(`current date:${new Date().toISOString()}`),
28
+ prompts_1.SystemMessagePromptTemplate.fromTemplate(`callReceivedAt:${new Date().toISOString()}
29
+ ingressNumber:${telephonyContext.ingressNumber}
30
+ callerNumber:${telephonyContext.callerNumber}`),
30
31
  prompts_1.HumanMessagePromptTemplate.fromTemplate("{input}")
31
32
  ]);
32
33
  }
@@ -1,7 +1,8 @@
1
1
  import { GroqParams } from "./types";
2
2
  import { AbstractLanguageModel } from "../AbstractLanguageModel";
3
+ import { TelephonyContext } from "../types";
3
4
  declare const LANGUAGE_MODEL_NAME = "llm.groq";
4
5
  declare class Groq extends AbstractLanguageModel {
5
- constructor(params: GroqParams);
6
+ constructor(params: GroqParams, telephonyContext: TelephonyContext);
6
7
  }
7
8
  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) {
10
+ constructor(params, 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
- });
19
+ }, telephonyContext);
20
20
  }
21
21
  }
22
22
  exports.Groq = Groq;
@@ -0,0 +1,8 @@
1
+ import { OllamaParams } from "./types";
2
+ import { AbstractLanguageModel } from "../AbstractLanguageModel";
3
+ import { TelephonyContext } from "../types";
4
+ declare const LANGUAGE_MODEL_NAME = "llm.ollama";
5
+ declare class Ollama extends AbstractLanguageModel {
6
+ constructor(params: OllamaParams, telephonyContext: TelephonyContext);
7
+ }
8
+ export { LANGUAGE_MODEL_NAME, Ollama };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Ollama = exports.LANGUAGE_MODEL_NAME = void 0;
4
+ const ollama_1 = require("@langchain/ollama");
5
+ const tools_1 = require("../../tools");
6
+ const AbstractLanguageModel_1 = require("../AbstractLanguageModel");
7
+ const LANGUAGE_MODEL_NAME = "llm.ollama";
8
+ exports.LANGUAGE_MODEL_NAME = LANGUAGE_MODEL_NAME;
9
+ class Ollama extends AbstractLanguageModel_1.AbstractLanguageModel {
10
+ constructor(params, telephonyContext) {
11
+ const model = new ollama_1.ChatOllama({
12
+ ...params
13
+ }).bind({
14
+ tools: params.tools.map(tools_1.convertToolToOpenAITool)
15
+ });
16
+ super({
17
+ ...params,
18
+ model
19
+ }, telephonyContext);
20
+ }
21
+ }
22
+ exports.Ollama = Ollama;
@@ -0,0 +1,2 @@
1
+ export * from "./Ollama";
2
+ export * from "./types";
@@ -0,0 +1,36 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /*
18
+ * Copyright (C) 2024 by Fonoster Inc (https://fonoster.com)
19
+ * http://github.com/fonoster/fonoster
20
+ *
21
+ * This file is part of Fonoster
22
+ *
23
+ * Licensed under the MIT License (the "License");
24
+ * you may not use this file except in compliance with
25
+ * the License. You may obtain a copy of the License at
26
+ *
27
+ * https://opensource.org/licenses/MIT
28
+ *
29
+ * Unless required by applicable law or agreed to in writing, software
30
+ * distributed under the License is distributed on an "AS IS" BASIS,
31
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32
+ * See the License for the specific language governing permissions and
33
+ * limitations under the License.
34
+ */
35
+ __exportStar(require("./Ollama"), exports);
36
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,11 @@
1
+ import { BaseModelParams } from "../types";
2
+ declare enum OllamaModel {
3
+ LLAMA3_1 = "llama3.1"
4
+ }
5
+ type OllamaParams = BaseModelParams & {
6
+ model: OllamaModel;
7
+ baseUrl: string;
8
+ maxTokens: number;
9
+ temperature: number;
10
+ };
11
+ export { OllamaModel, OllamaParams };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OllamaModel = void 0;
4
+ var OllamaModel;
5
+ (function (OllamaModel) {
6
+ OllamaModel["LLAMA3_1"] = "llama3.1";
7
+ })(OllamaModel || (exports.OllamaModel = OllamaModel = {}));
@@ -1,7 +1,8 @@
1
1
  import { OpenAIParams } from "./types";
2
2
  import { AbstractLanguageModel } from "../AbstractLanguageModel";
3
+ import { TelephonyContext } from "../types";
3
4
  declare const LANGUAGE_MODEL_NAME = "llm.openai";
4
5
  declare class OpenAI extends AbstractLanguageModel {
5
- constructor(params: OpenAIParams);
6
+ constructor(params: OpenAIParams, telephonyContext: TelephonyContext);
6
7
  }
7
8
  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) {
10
+ constructor(params, 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
- });
19
+ }, telephonyContext);
20
20
  }
21
21
  }
22
22
  exports.OpenAI = OpenAI;
@@ -8,6 +8,7 @@ type BaseModelParams = {
8
8
  systemTemplate: string;
9
9
  knowledgeBase: KnowledgeBase;
10
10
  tools: Tool[];
11
+ telephonyContext: TelephonyContext;
11
12
  };
12
13
  type LanguageModelParams = BaseModelParams & {
13
14
  model: BaseChatModel;
@@ -16,4 +17,8 @@ type InvocationResult = {
16
17
  type: "say" | "hangup" | "transfer";
17
18
  content?: string;
18
19
  };
19
- export { BaseModelParams, InvocationResult, LanguageModel, LanguageModelParams };
20
+ type TelephonyContext = {
21
+ ingressNumber: string;
22
+ callerNumber: string;
23
+ };
24
+ export { BaseModelParams, InvocationResult, LanguageModel, LanguageModelParams, TelephonyContext };
@@ -52,22 +52,27 @@ declare const toolSchema: z.ZodObject<{
52
52
  type: z.ZodNativeEnum<typeof AllowedOperations>;
53
53
  url: z.ZodOptional<z.ZodString>;
54
54
  waitForResponse: z.ZodOptional<z.ZodBoolean>;
55
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
55
56
  }, "strip", z.ZodTypeAny, {
56
57
  type: AllowedOperations;
57
58
  url?: string | undefined;
58
59
  waitForResponse?: boolean | undefined;
60
+ headers?: Record<string, string> | undefined;
59
61
  }, {
60
62
  type: AllowedOperations;
61
63
  url?: string | undefined;
62
64
  waitForResponse?: boolean | undefined;
65
+ headers?: Record<string, string> | undefined;
63
66
  }>, {
64
67
  type: AllowedOperations;
65
68
  url?: string | undefined;
66
69
  waitForResponse?: boolean | undefined;
70
+ headers?: Record<string, string> | undefined;
67
71
  }, {
68
72
  type: AllowedOperations;
69
73
  url?: string | undefined;
70
74
  waitForResponse?: boolean | undefined;
75
+ headers?: Record<string, string> | undefined;
71
76
  }>;
72
77
  }, "strip", z.ZodTypeAny, {
73
78
  name: string;
@@ -85,6 +90,7 @@ declare const toolSchema: z.ZodObject<{
85
90
  type: AllowedOperations;
86
91
  url?: string | undefined;
87
92
  waitForResponse?: boolean | undefined;
93
+ headers?: Record<string, string> | undefined;
88
94
  };
89
95
  }, {
90
96
  name: string;
@@ -102,6 +108,7 @@ declare const toolSchema: z.ZodObject<{
102
108
  type: AllowedOperations;
103
109
  url?: string | undefined;
104
110
  waitForResponse?: boolean | undefined;
111
+ headers?: Record<string, string> | undefined;
105
112
  };
106
113
  }>;
107
114
  export { AllowedOperations, toolSchema };
@@ -50,7 +50,8 @@ const toolSchema = zod_1.z.object({
50
50
  type: zod_1.z.nativeEnum(AllowedOperations),
51
51
  // Make url required if operation type is not built-in
52
52
  url: zod_1.z.string().optional(),
53
- waitForResponse: zod_1.z.boolean().optional()
53
+ waitForResponse: zod_1.z.boolean().optional(),
54
+ headers: zod_1.z.record(zod_1.z.string()).optional()
54
55
  })
55
56
  .superRefine(({ url, type }, ctx) => {
56
57
  if (type !== AllowedOperations.BUILT_IN && !url) {
@@ -39,6 +39,7 @@ class ToolsCatalog {
39
39
  method: tool.operation.type,
40
40
  url: tool.operation.url,
41
41
  waitForResponse: tool.operation.waitForResponse,
42
+ headers: tool.operation.headers,
42
43
  body: args
43
44
  });
44
45
  }
@@ -38,6 +38,11 @@ async function sendRequest(input) {
38
38
  else {
39
39
  const response = await fetch(url, options);
40
40
  const data = await response.json();
41
- return responseSchema.parse(data);
41
+ try {
42
+ return responseSchema.parse(data);
43
+ }
44
+ catch (error) {
45
+ throw new Error(`Invalid response: expected ${JSON.stringify(responseSchema, null, 2)}, got ${JSON.stringify(data, null, 2)}`);
46
+ }
42
47
  }
43
48
  }
package/dist/types.d.ts CHANGED
@@ -4,7 +4,8 @@ import { Vad } from "./vad";
4
4
  import { Voice } from "./voice";
5
5
  declare enum LANGUAGE_MODEL_PROVIDER {
6
6
  OPENAI = "openai",
7
- GROQ = "groq"
7
+ GROQ = "groq",
8
+ OLLAMA = "ollama"
8
9
  }
9
10
  type AutopilotParams = {
10
11
  voice: Voice;
package/dist/types.js CHANGED
@@ -5,4 +5,5 @@ var LANGUAGE_MODEL_PROVIDER;
5
5
  (function (LANGUAGE_MODEL_PROVIDER) {
6
6
  LANGUAGE_MODEL_PROVIDER["OPENAI"] = "openai";
7
7
  LANGUAGE_MODEL_PROVIDER["GROQ"] = "groq";
8
+ LANGUAGE_MODEL_PROVIDER["OLLAMA"] = "ollama";
8
9
  })(LANGUAGE_MODEL_PROVIDER || (exports.LANGUAGE_MODEL_PROVIDER = LANGUAGE_MODEL_PROVIDER = {}));
@@ -26,7 +26,7 @@ class SileroVad {
26
26
  this.init();
27
27
  }
28
28
  async init() {
29
- // FIXME: It feels not to do this in the constructor
29
+ // FIXME: It feels strange to do this in the constructor
30
30
  this.vad = await (0, makeVad_1.makeVad)();
31
31
  }
32
32
  processChunk(data, callback) {
@@ -44,9 +44,11 @@ exports.makeVad = makeVad;
44
44
  * limitations under the License.
45
45
  */
46
46
  const path_1 = require("path");
47
+ const logger_1 = require("@fonoster/logger");
47
48
  const ort = __importStar(require("onnxruntime-node"));
48
49
  const chunkToFloat32Array_1 = require("./chunkToFloat32Array");
49
50
  const SileroVadModel_1 = require("./SileroVadModel");
51
+ const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
50
52
  const BUFFER_SIZE = 16000;
51
53
  async function makeVad(pathToModel) {
52
54
  const effectivePath = pathToModel || (0, path_1.join)(__dirname, "..", "..", "silero_vad.onnx");
@@ -62,6 +64,7 @@ async function makeVad(pathToModel) {
62
64
  const audioFrame = buffer.slice(0, BUFFER_SIZE);
63
65
  const remainingBuffer = buffer.slice(BUFFER_SIZE);
64
66
  const result = await silero.process(new Float32Array(audioFrame));
67
+ logger.silly("last vad result", { ...result });
65
68
  if (result.isSpeech > 0.5) {
66
69
  if (!isSpeechActive) {
67
70
  isSpeechActive = true;
@@ -72,6 +75,9 @@ async function makeVad(pathToModel) {
72
75
  else if (isSpeechActive) {
73
76
  isSpeechActive = false;
74
77
  callback("SPEECH_END");
78
+ // WARNING: I'm unsure if this has any effect on the model
79
+ // but it seems to work fine to ensure the model works optimally
80
+ silero.resetState();
75
81
  return processBuffer(remainingBuffer);
76
82
  }
77
83
  return processBuffer(remainingBuffer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fonoster/autopilot",
3
- "version": "0.7.14",
3
+ "version": "0.7.16",
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,13 +35,14 @@
35
35
  "url": "https://github.com/fonoster/fonoster/issues"
36
36
  },
37
37
  "dependencies": {
38
- "@fonoster/common": "^0.7.13",
39
- "@fonoster/logger": "^0.7.13",
40
- "@fonoster/types": "^0.7.13",
41
- "@fonoster/voice": "^0.7.13",
38
+ "@fonoster/common": "^0.7.16",
39
+ "@fonoster/logger": "^0.7.16",
40
+ "@fonoster/types": "^0.7.16",
41
+ "@fonoster/voice": "^0.7.16",
42
42
  "@langchain/community": "^0.2.31",
43
43
  "@langchain/core": "^0.2.32",
44
44
  "@langchain/groq": "^0.0.17",
45
+ "@langchain/ollama": "^0.0.4",
45
46
  "@langchain/openai": "^0.2.10",
46
47
  "cheerio": "^1.0.0",
47
48
  "dotenv": "^16.4.5",
@@ -55,5 +56,5 @@
55
56
  "devDependencies": {
56
57
  "typescript": "^5.5.4"
57
58
  },
58
- "gitHead": "e53cc1ba6d17ce64a9541bd51364ace3dcd43aaa"
59
+ "gitHead": "1d2898f38de4690f0b9c2dac5506c2ddaeebedbb"
59
60
  }