@fonoster/autopilot 0.12.9 → 0.12.10

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.
@@ -25,13 +25,14 @@ const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filen
25
25
  exports.doProcessUserRequest = (0, xstate_1.fromPromise)(async ({ input }) => {
26
26
  const { context } = input;
27
27
  logger.verbose("called processUserRequest actor", {
28
- speechBuffer: context.speechBuffer
28
+ speechBuffer: context.speechBuffer,
29
+ isReentry: context.isReentry
29
30
  });
30
31
  // Stop any speech that might be playing
31
32
  await context.voice.stopSpeech();
32
33
  const languageModel = context.languageModel;
33
34
  const speech = context.speechBuffer.trim();
34
- const response = await languageModel.invoke(speech);
35
+ const response = await languageModel.invoke(speech, context.isReentry);
35
36
  try {
36
37
  if (response.type === "say" && !response.content) {
37
38
  logger.warn("ignoring say response with no content");
@@ -45,5 +45,7 @@ declare const context: ({ input }: {
45
45
  sessionStartTime: number;
46
46
  maxSessionDuration: number;
47
47
  initialDtmf: string;
48
+ previousState: any;
49
+ isReentry: boolean;
48
50
  };
49
51
  export { context };
@@ -20,6 +20,8 @@ const context = ({ input }) => ({
20
20
  allowUserBargeIn: input.conversationSettings.allowUserBargeIn,
21
21
  sessionStartTime: Date.now(),
22
22
  maxSessionDuration: input.conversationSettings.maxSessionDuration,
23
- initialDtmf: input.conversationSettings.initialDtmf
23
+ initialDtmf: input.conversationSettings.initialDtmf,
24
+ previousState: null,
25
+ isReentry: false
24
26
  });
25
27
  exports.context = context;
@@ -63,7 +63,7 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
63
63
  languageModel: import("..").LanguageModel;
64
64
  voice: import("..").Voice;
65
65
  }, {}, import("xstate").EventObject, import("xstate").MetaObject, {
66
- /** @xstate-layout N4IgpgJg5mDOIC5QDMB2BBAkgYgB6wBcBDAsAOiOVICcAKAWXQA0B9AZQFE23MB5AORYARAKoAldABU+-AJTY0WANoAGALqJQABwD2sAJYF9O1JpC5EAWgDMADgDsZFQDYATAFYAnLevuAjPYALIF+ADQgAJ6IHoFkrp5B9s6ezn6pzu7uAL5Z4YqYZFDUYGBGqFDYqhpIILoGRiZmFgh+tn5k1vYp9tauti7Obc7hUQievmQJzm5efq6uvvY5eRgF+hAANmDYbAAKHBwAwgAS7JLoYpJVZnWGxqY1zZ4qjrbuC-Z9gT3O9vYjiHstlckxcnXsKlaXUCrmWIHyZHWWzwhBI5EoNFomCEABkOCxpPQOLwRJJ5AikWBrjVbg0HqBmu5AipJu42t5PM8VNYMgCWtY-O05p4-F5XMyVIF3NY4RTNtt8MRSBQqGA6Ni8QTMESSWSFKtEfKlH5qto9HdGo9ENZArYyAF-P5fra+q4+YKFmQgv13EF-DypbKDRt9IQwKh9OVJDoRLA1Tt9kdTmIuCIcVd1DdzXSmohnLayLZnNZPIFi5zkkE+TyWZz7Ez4ipJX5mTLcvDg6HSBGozG49QUUr0ar1bj8YTiaTyZ2wz2oNHY2rqWb6vdcy1BXa-r5gYFnh56+6VMCvX4VF5uf7Pm2VlgyAB3Ih3coAMR01DYWhKAGMABaSfQAFswB0ABXAgEwOE4zguDNTVqbM1ytFoIQ6ZsgU5BZXC6YZIkQLx3ELIJXBUV0-kCIM70fZ8oDfD8vzAP8AOAsCIL2KDk1TdNlwQ1dLQZKwpUmOxviSFxmUFdw+Q+JxvilWw90WB1KIKaiylo99Px-f8gJA8DBzRFVMUYVh2KTFgAHUsEkLUdSnfUqKfdS6K0xidJY8CeNpJCBI3Wwtw+NJxl+YE3TwhBxRBbxbG8dxpji7xWhUsgtGoHRvzgAxykXagxDAABHUC4AgiATHISMADcdAAa3IBFUvSzLIygHK8sK4qEEq9KSHuKovMQ-jzEQOZ3g6QY-HGc9xjaPkLzIZk+m3ToQiCZKGoy2Aspa-s2qKwhIPMthzkufq+PpIb+R5e1rDsYtRR6SVPD5DCyCdYJnEhSFkgo9t6rSjattagq9rYxNoJTNg0zgrMzvXAIFK9CFBlLcTj2rPd7WvTpOm8Y9SxydtUB0CA4DMfIYYtc7mksQIJhcDxvF8AJgjCcKW08V65Old4eWdG8OzvIoSnUimc2QyxfjiSsSJLEii0GPlPFcZx5r+JXJW5etfGSylRZ8i7fRBVI0niVJgghaxFeV1WuhI1steyX6Z27ZqF37PXBuaBwWXZaxzwFYtMkCWbUkLfpjx5aa2WStTmpchimN01iPap4bJdSIs+g+5Wy2D8KSw5z4QmV8Z7DPX5HdvApfyIcpQK0FP10sEjCLcAURVIxIwtGPwbvaXxDdtOKEp+quUv+prsp24Hisb5DRWlMbBSBDJSJu2aHDDpsFJ5aUlaWAmgA */
66
+ /** @xstate-layout N4IgpgJg5mDOIC5QDMB2BBAkgYgFQG0AGAXUVAAcB7WASwBcbLUyQAPRAWgFYBmARgB0ADi58A7CMIA2HgBYuATj4AaEAE9EPAEwDZYsQqljZQnoT18pUgL7XVaLNlaw6AQzpgBr5B4BOACgBZdAANAH0AZQBRCIjMAHkAOTCAEQBVACV0ABUExIBKbAdMIlIkECpaBiYWdgQOHiExAWktRVNRY1kVdUQ22QEtBWMxKUNLSy4uW3sMTAEoXzAwBlQobFKWSvpGZnK6viFBHgMjbSFpKSOpVQ0EBR4uAWGrNqUtLUexGZBigRoIAAbMDYCIABSiUQAwgAJSLZdAZbKbcrbap7UB1BSEZoiT5iLRCPQ8IxiW6ICQ6bEyfSEQ4GWRaH5-AHApwudyebx+fyYFIAGSiYVygSi8TS2UKLKBYBRFGoOxq+0QXFkhGeXCOCiECmxhBJXHJCD4-EEfCGfEUWjV5l4zLm-xl7LcHi8PjAAT5guFmFF4slRQdrNlfDK8qqu1qmhMAnEolERhMhK0Rr45p4AmMFy4xlEJPk9qwAkBNBcYFQNDW2UoaVgHtBEOhcIyMTS-ORJC2CvRUYQUhjQhkClkQ8Mw1kRpJ6t1YlVQ0I5j4ap4hfmJbLFarNbrvmdnLdPK9QpFYolUod648m6g1drHrlFW7keVxrTQkzYkeQmt2Las9ThDfpmfCEIo+p5gSK52L8DoAO6uDsawAGKUL4ETkMsADGAAW2Q0AAtmAlAAK50A2kKwvCiIdmGj4RkqmKIOI6pmN0Ei6p8WinEaihPE0jKEMm+iyKuAjwYhUAoWhGFgDheGESRZHghRzatu2D5os+jH1PIzyNHoozSGqaaGr0CD4i0ejyESDw5nGoniaskmoehWG4QRRGkXurrch6QShJEjaUQA6lg2Q+n6Z6BkWjmVs50lufJnl0BpT4MWwTGHO+kFiJYDxGN+KZmdaVJCDqIhWFwYxHEIonkL4lCYXAtBrHevgZGAACOxFwGREBMJ4lYAG6UAA1p4fz1Y1zVxW1HXdb1CDDY17i7KUqX0RiGXGm0OgklqZiKI0PR3GBuiCU0n4nGxInQZNDVNbALVQHNXU9S45FNlRSIbYqW0HDwJKxoDg78DmrEKEa7ECAmsgjnSdJjLdsxFlNj3Pa9C0fcpX0thEbY0V2m29uIRIftIOpqv2gGTrICixpBJwnNqgHDrY0GoJQEBwCwxRE39vYcLIjwtFIbwdOIcMnUxdMw1ZVxDDqXD6qJizLE5-M9i+HBGIMYwEvqChaIBVhCEaRtSLo+hG+Y+qzo8onBprWnbTmOhSGmYvjHDYj6ubWiWwZNvLvb0x3RepZXnFt47s76V1E06oHaB-AyFME5mVVghlQuphjI0moOQhTlSa5snuQppFx-9TG6x7g6ElIgn9v2k66pm1rmvnuXSLOonYa4azEeQ1eC8bTxi-wSiCSMRV3Ca-ACI8bsmFVVVs+HqMPTNrU7vN710KPL6WrwS8e6TUjK58PA8U0wgXIBwuXzwRvfOzQA */
67
67
  readonly context: ({ input }: {
68
68
  input: {
69
69
  voice: import("..").Voice;
@@ -90,6 +90,8 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
90
90
  sessionStartTime: number;
91
91
  maxSessionDuration: number;
92
92
  initialDtmf: string;
93
+ previousState: any;
94
+ isReentry: boolean;
93
95
  };
94
96
  readonly id: "fnAI";
95
97
  readonly initial: "greeting";
@@ -240,5 +242,16 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
240
242
  };
241
243
  };
242
244
  };
245
+ readonly on: {
246
+ readonly "*": {
247
+ readonly actions: import("xstate").ActionFunction<any, import("./types").AutopilotEvents, import("./types").AutopilotEvents, undefined, {
248
+ src: "doProcessUserRequest";
249
+ logic: import("xstate").PromiseActorLogic<void, {
250
+ context: import("./types").AutopilotContext;
251
+ }, import("xstate").EventObject>;
252
+ id: string;
253
+ }, never, never, never, never>;
254
+ };
255
+ };
243
256
  }>;
244
257
  export { machine };
@@ -20,10 +20,11 @@ exports.machine = void 0;
20
20
  * limitations under the License.
21
21
  */
22
22
  const xstate_1 = require("xstate");
23
+ const xstate_2 = require("xstate");
23
24
  const context_1 = require("./context");
24
25
  const setup_1 = require("./setup");
25
26
  const machine = setup_1.machineSetup.createMachine({
26
- /** @xstate-layout N4IgpgJg5mDOIC5QDMB2BBAkgYgB6wBcBDAsAOiOVICcAKAWXQA0B9AZQFE23MB5AORYARAKoAldABU+-AJTY0WANoAGALqJQABwD2sAJYF9O1JpC5EAWgDMADgDsZFQDYATAFYAnLevuAjPYALIF+ADQgAJ6IHoFkrp5B9s6ezn6pzu7uAL5Z4YqYZFDUYGBGqFDYqhpIILoGRiZmFgh+tn5k1vYp9tauti7Obc7hUQievmQJzm5efq6uvvY5eRgF+hAANmDYbAAKHBwAwgAS7JLoYpJVZnWGxqY1zZ4qjrbuC-Z9gT3O9vYjiHstlckxcnXsKlaXUCrmWIHyZHWWzwhBI5EoNFomCEABkOCxpPQOLwRJJ5AikWBrjVbg0HqBmu5AipJu42t5PM8VNYMgCWtY-O05p4-F5XMyVIF3NY4RTNtt8MRSBQqGA6Ni8QTMESSWSFKtEfKlH5qto9HdGo9ENZArYyAF-P5fra+q4+YKFmQgv13EF-DypbKDRt9IQwKh9OVJDoRLA1Tt9kdTmIuCIcVd1DdzXSmohnLayLZnNZPIFi5zkkE+TyWZz7Ez4ipJX5mTLcvDg6HSBGozG49QUUr0ar1bj8YTiaTyZ2wz2oNHY2rqWb6vdcy1BXa-r5gYFnh56+6VMCvX4VF5uf7Pm2VlgyAB3Ih3coAMR01DYWhKAGMABaSfQAFswB0ABXAgEwOE4zguDNTVqbM1ytFoIQ6ZsgU5BZXC6YZIkQLx3ELIJXBUV0-kCIM70fZ8oDfD8vzAP8AOAsCIL2KDk1TdNlwQ1dLQZKwpUmOxviSFxmUFdw+Q+JxvilWw90WB1KIKaiylo99Px-f8gJA8DBzRFVMUYVh2KTFgAHUsEkLUdSnfUqKfdS6K0xidJY8CeNpJCBI3Wwtw+NJxl+YE3TwhBxRBbxbG8dxpji7xWhUsgtGoHRvzgAxykXagxDAABHUC4AgiATHISMADcdAAa3IBFUvSzLIygHK8sK4qEEq9KSHuKovMQ-jzEQOZ3g6QY-HGc9xjaPkLzIZk+m3ToQiCZKGoy2Aspa-s2qKwhIPMthzkufq+PpIb+R5e1rDsYtRR6SVPD5DCyCdYJnEhSFkgo9t6rSjattagq9rYxNoJTNg0zgrMzvXAIFK9CFBlLcTj2rPd7WvTpOm8Y9SxydtUB0CA4DMfIYYtc7mksQIJhcDxvF8AJgjCcKW08V65Old4eWdG8OzvIoSnUimc2QyxfjiSsSJLEii0GPlPFcZx5r+JXJW5etfGSylRZ8i7fRBVI0niVJgghaxFeV1WuhI1steyX6Z27ZqF37PXBuaBwWXZaxzwFYtMkCWbUkLfpjx5aa2WStTmpchimN01iPap4bJdSIs+g+5Wy2D8KSw5z4QmV8Z7DPX5HdvApfyIcpQK0FP10sEjCLcAURVIxIwtGPwbvaXxDdtOKEp+quUv+prsp24Hisb5DRWlMbBSBDJSJu2aHDDpsFJ5aUlaWAmgA */
27
+ /** @xstate-layout N4IgpgJg5mDOIC5QDMB2BBAkgYgFQG0AGAXUVAAcB7WASwBcbLUyQAPRAWgFYBmARgB0ADi58A7CMIA2HgBYuATj4AaEAE9EPAEwDZYsQqljZQnoT18pUgL7XVaLNlaw6AQzpgBr5B4BOACgBZdAANAH0AZQBRCIjMAHkAOTCAEQBVACV0ABUExIBKbAdMIlIkECpaBiYWdgQOHiExAWktRVNRY1kVdUQ22QEtBWMxKUNLSy4uW3sMTAEoXzAwBlQobFKWSvpGZnK6viFBHgMjbSFpKSOpVQ0EBR4uAWGrNqUtLUexGZBigRoIAAbMDYCIABSiUQAwgAJSLZdAZbKbcrbap7UB1BSEZoiT5iLRCPQ8IxiW6ICQ6bEyfSEQ4GWRaH5-AHApwudyebx+fyYFIAGSiYVygSi8TS2UKLKBYBRFGoOxq+0QXFkhGeXCOCiECmxhBJXHJCD4-EEfCGfEUWjV5l4zLm-xl7LcHi8PjAAT5guFmFF4slRQdrNlfDK8qqu1qmhMAnEolERhMhK0Rr45p4AmMFy4xlEJPk9qwAkBNBcYFQNDW2UoaVgHtBEOhcIyMTS-ORJC2CvRUYQUhjQhkClkQ8Mw1kRpJ6t1YlVQ0I5j4ap4hfmJbLFarNbrvmdnLdPK9QpFYolUod648m6g1drHrlFW7keVxrTQkzYkeQmt2Las9ThDfpmfCEIo+p5gSK52L8DoAO6uDsawAGKUL4ETkMsADGAAW2Q0AAtmAlAAK50A2kKwvCiIdmGj4RkqmKIOI6pmN0Ei6p8WinEaihPE0jKEMm+iyKuAjwYhUAoWhGFgDheGESRZHghRzatu2D5os+jH1PIzyNHoozSGqaaGr0CD4i0ejyESDw5nGoniaskmoehWG4QRRGkXurrch6QShJEjaUQA6lg2Q+n6Z6BkWjmVs50lufJnl0BpT4MWwTGHO+kFiJYDxGN+KZmdaVJCDqIhWFwYxHEIonkL4lCYXAtBrHevgZGAACOxFwGREBMJ4lYAG6UAA1p4fz1Y1zVxW1HXdb1CDDY17i7KUqX0RiGXGm0OgklqZiKI0PR3GBuiCU0n4nGxInQZNDVNbALVQHNXU9S45FNlRSIbYqW0HDwJKxoDg78DmrEKEa7ECAmsgjnSdJjLdsxFlNj3Pa9C0fcpX0thEbY0V2m29uIRIftIOpqv2gGTrICixpBJwnNqgHDrY0GoJQEBwCwxRE39vYcLIjwtFIbwdOIcMnUxdMw1ZVxDDqXD6qJizLE5-M9i+HBGIMYwEvqChaIBVhCEaRtSLo+hG+Y+qzo8onBprWnbTmOhSGmYvjHDYj6ubWiWwZNvLvb0x3RepZXnFt47s76V1E06oHaB-AyFME5mVVghlQuphjI0moOQhTlSa5snuQppFx-9TG6x7g6ElIgn9v2k66pm1rmvnuXSLOonYa4azEeQ1eC8bTxi-wSiCSMRV3Ca-ACI8bsmFVVVs+HqMPTNrU7vN710KPL6WrwS8e6TUjK58PA8U0wgXIBwuXzwRvfOzQA */
27
28
  context: context_1.context,
28
29
  id: "fnAI",
29
30
  initial: "greeting",
@@ -146,6 +147,17 @@ const machine = setup_1.machineSetup.createMachine({
146
147
  target: ".hangup",
147
148
  actions: { type: "goodbye" }
148
149
  }
150
+ },
151
+ on: {
152
+ "*": {
153
+ actions: (0, xstate_2.assign)(({ context, self }) => {
154
+ const isReentry = self.getSnapshot().value === context.previousState;
155
+ return {
156
+ previousState: self.getSnapshot().value,
157
+ isReentry
158
+ };
159
+ })
160
+ }
149
161
  }
150
162
  });
151
163
  exports.machine = machine;
@@ -37,6 +37,8 @@ type AutopilotContext = {
37
37
  speechResponseTime: number;
38
38
  knowledgeBaseSourceUrl?: string;
39
39
  initialDtmf?: string;
40
+ previousState: string | null;
41
+ isReentry: boolean;
40
42
  };
41
43
  type AutopilotEvents = {
42
44
  type: "SPEECH_START";
@@ -9,7 +9,7 @@ declare abstract class AbstractLanguageModel implements LanguageModel {
9
9
  private readonly firstMessage;
10
10
  private readonly transferOptions;
11
11
  constructor(params: LanguageModelParams, voice: Voice, telephonyContext: TelephonyContext);
12
- invoke(text: string): Promise<InvocationResult>;
12
+ invoke(text: string, isReentry: boolean): Promise<InvocationResult>;
13
13
  getChatHistoryMessages(): Promise<import("@langchain/core/messages").BaseMessage[]>;
14
14
  }
15
15
  export { AbstractLanguageModel };
@@ -41,7 +41,7 @@ class AbstractLanguageModel {
41
41
  });
42
42
  this.chain = (0, createChain_1.createChain)(model, knowledgeBase, promptTemplate, this.chatHistory);
43
43
  }
44
- async invoke(text) {
44
+ async invoke(text, isReentry) {
45
45
  const { chain, chatHistory, toolsCatalog } = this;
46
46
  const response = (await chain.invoke({ text }));
47
47
  let isFirstTool = true;
@@ -51,6 +51,13 @@ class AbstractLanguageModel {
51
51
  hasTools: (response.tool_calls?.length ?? 0) > 0,
52
52
  tools: response.tool_calls?.map((tool) => tool.name)
53
53
  });
54
+ // This handles late speech recognition
55
+ if (isReentry) {
56
+ logger.verbose("xxx reentry detected, discarding last conversation turn");
57
+ const messages = await chatHistory.getMessages();
58
+ messages.pop(); // Last AI message
59
+ messages.pop(); // Last user message
60
+ }
54
61
  // Begin the conversation with the first message
55
62
  if ((await chatHistory.getMessages()).length === 0 && this.firstMessage) {
56
63
  await chatHistory.addAIMessage(this.firstMessage);
@@ -22,7 +22,7 @@ import { ToolCall } from "@langchain/core/messages/tool";
22
22
  import { KnowledgeBase } from "../knowledge";
23
23
  import { Tool } from "../tools/types";
24
24
  type LanguageModel = {
25
- invoke: (text: string) => Promise<InvocationResult>;
25
+ invoke: (text: string, isReentry?: boolean) => Promise<InvocationResult>;
26
26
  };
27
27
  type BaseModelParams = {
28
28
  firstMessage?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fonoster/autopilot",
3
- "version": "0.12.9",
3
+ "version": "0.12.10",
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",
@@ -59,5 +59,5 @@
59
59
  "xstate": "^5.17.3",
60
60
  "zod": "^3.23.8"
61
61
  },
62
- "gitHead": "082170cc2626a2c21ce1b2d657203aef88e7f043"
62
+ "gitHead": "c716ab1782c9e0c4034585a162664b026035821b"
63
63
  }