@fonoster/autopilot 0.12.8 → 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.
- package/dist/machine/actions/index.d.ts +0 -2
- package/dist/machine/actions/index.js +1 -5
- package/dist/machine/actions/resetState.js +1 -2
- package/dist/machine/actors/doProcessUserRequest.js +3 -2
- package/dist/machine/context.d.ts +2 -1
- package/dist/machine/context.js +3 -2
- package/dist/machine/guards/index.d.ts +0 -1
- package/dist/machine/guards/index.js +1 -3
- package/dist/machine/machine.d.ts +22 -26
- package/dist/machine/machine.js +26 -20
- package/dist/machine/setup.d.ts +0 -24
- package/dist/machine/setup.js +1 -14
- package/dist/machine/types.d.ts +2 -1
- package/dist/models/AbstractLanguageModel.d.ts +1 -1
- package/dist/models/AbstractLanguageModel.js +8 -1
- package/dist/models/types.d.ts +1 -1
- package/package.json +2 -2
- package/dist/machine/actions/setSpeaking.d.ts +0 -1
- package/dist/machine/actions/setSpeaking.js +0 -29
- package/dist/machine/actions/setSpeakingDone.d.ts +0 -1
- package/dist/machine/actions/setSpeakingDone.js +0 -29
- package/dist/machine/guards/isSpeaking.d.ts +0 -4
- package/dist/machine/guards/isSpeaking.js +0 -30
|
@@ -25,6 +25,4 @@ export { increaseIdleTimeoutCount } from "./increaseIdleTimeoutCount";
|
|
|
25
25
|
export { cleanSpeech } from "./cleanSpeech";
|
|
26
26
|
export { appendSpeech } from "./appendSpeech";
|
|
27
27
|
export { resetIdleTimeoutCount } from "./resetIdleTimeoutCount";
|
|
28
|
-
export { setSpeaking } from "./setSpeaking";
|
|
29
|
-
export { setSpeakingDone } from "./setSpeakingDone";
|
|
30
28
|
export { resetState } from "./resetState";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resetState = exports.
|
|
3
|
+
exports.resetState = exports.resetIdleTimeoutCount = exports.appendSpeech = exports.cleanSpeech = exports.increaseIdleTimeoutCount = exports.announceIdleTimeout = exports.interruptPlayback = exports.announceSystemError = exports.goodbye = exports.greetUser = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
6
6
|
* http://github.com/fonoster/fonoster
|
|
@@ -37,9 +37,5 @@ var appendSpeech_1 = require("./appendSpeech");
|
|
|
37
37
|
Object.defineProperty(exports, "appendSpeech", { enumerable: true, get: function () { return appendSpeech_1.appendSpeech; } });
|
|
38
38
|
var resetIdleTimeoutCount_1 = require("./resetIdleTimeoutCount");
|
|
39
39
|
Object.defineProperty(exports, "resetIdleTimeoutCount", { enumerable: true, get: function () { return resetIdleTimeoutCount_1.resetIdleTimeoutCount; } });
|
|
40
|
-
var setSpeaking_1 = require("./setSpeaking");
|
|
41
|
-
Object.defineProperty(exports, "setSpeaking", { enumerable: true, get: function () { return setSpeaking_1.setSpeaking; } });
|
|
42
|
-
var setSpeakingDone_1 = require("./setSpeakingDone");
|
|
43
|
-
Object.defineProperty(exports, "setSpeakingDone", { enumerable: true, get: function () { return setSpeakingDone_1.setSpeakingDone; } });
|
|
44
40
|
var resetState_1 = require("./resetState");
|
|
45
41
|
Object.defineProperty(exports, "resetState", { enumerable: true, get: function () { return resetState_1.resetState; } });
|
|
@@ -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");
|
|
@@ -42,9 +42,10 @@ declare const context: ({ input }: {
|
|
|
42
42
|
idleTimeoutCount: number;
|
|
43
43
|
maxSpeechWaitTimeout: number;
|
|
44
44
|
allowUserBargeIn: boolean;
|
|
45
|
-
isSpeaking: boolean;
|
|
46
45
|
sessionStartTime: number;
|
|
47
46
|
maxSessionDuration: number;
|
|
48
47
|
initialDtmf: string;
|
|
48
|
+
previousState: any;
|
|
49
|
+
isReentry: boolean;
|
|
49
50
|
};
|
|
50
51
|
export { context };
|
package/dist/machine/context.js
CHANGED
|
@@ -18,9 +18,10 @@ const context = ({ input }) => ({
|
|
|
18
18
|
idleTimeoutCount: 0,
|
|
19
19
|
maxSpeechWaitTimeout: input.conversationSettings.maxSpeechWaitTimeout,
|
|
20
20
|
allowUserBargeIn: input.conversationSettings.allowUserBargeIn,
|
|
21
|
-
isSpeaking: false,
|
|
22
21
|
sessionStartTime: Date.now(),
|
|
23
22
|
maxSessionDuration: input.conversationSettings.maxSessionDuration,
|
|
24
|
-
initialDtmf: input.conversationSettings.initialDtmf
|
|
23
|
+
initialDtmf: input.conversationSettings.initialDtmf,
|
|
24
|
+
previousState: null,
|
|
25
|
+
isReentry: false
|
|
25
26
|
});
|
|
26
27
|
exports.context = context;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.hasSpeechResult = exports.idleTimeoutCountExceedsMax = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
6
6
|
* http://github.com/fonoster/fonoster
|
|
@@ -23,5 +23,3 @@ var idleTimeoutCountExceedsMax_1 = require("./idleTimeoutCountExceedsMax");
|
|
|
23
23
|
Object.defineProperty(exports, "idleTimeoutCountExceedsMax", { enumerable: true, get: function () { return idleTimeoutCountExceedsMax_1.idleTimeoutCountExceedsMax; } });
|
|
24
24
|
var hasSpeechResult_1 = require("./hasSpeechResult");
|
|
25
25
|
Object.defineProperty(exports, "hasSpeechResult", { enumerable: true, get: function () { return hasSpeechResult_1.hasSpeechResult; } });
|
|
26
|
-
var isSpeaking_1 = require("./isSpeaking");
|
|
27
|
-
Object.defineProperty(exports, "isSpeaking", { enumerable: true, get: function () { return isSpeaking_1.isSpeaking; } });
|
|
@@ -29,14 +29,6 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
29
29
|
type: "resetState";
|
|
30
30
|
params: unknown;
|
|
31
31
|
};
|
|
32
|
-
setSpeaking: {
|
|
33
|
-
type: "setSpeaking";
|
|
34
|
-
params: unknown;
|
|
35
|
-
};
|
|
36
|
-
setSpeakingDone: {
|
|
37
|
-
type: "setSpeakingDone";
|
|
38
|
-
params: unknown;
|
|
39
|
-
};
|
|
40
32
|
greetUser: {
|
|
41
33
|
type: "greetUser";
|
|
42
34
|
params: unknown;
|
|
@@ -58,10 +50,6 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
58
50
|
params: unknown;
|
|
59
51
|
};
|
|
60
52
|
}>, import("xstate").Values<{
|
|
61
|
-
isSpeaking: {
|
|
62
|
-
type: "isSpeaking";
|
|
63
|
-
params: unknown;
|
|
64
|
-
};
|
|
65
53
|
idleTimeoutCountExceedsMax: {
|
|
66
54
|
type: "idleTimeoutCountExceedsMax";
|
|
67
55
|
params: unknown;
|
|
@@ -70,12 +58,12 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
70
58
|
type: "hasSpeechResult";
|
|
71
59
|
params: unknown;
|
|
72
60
|
};
|
|
73
|
-
}>, "IDLE_TIMEOUT" | "MAX_SPEECH_WAIT_TIMEOUT" | "MAX_SESSION_DURATION", "hangup" | "greeting" | "idle" | "listeningToUser" | "
|
|
61
|
+
}>, "IDLE_TIMEOUT" | "MAX_SPEECH_WAIT_TIMEOUT" | "MAX_SESSION_DURATION", "hangup" | "greeting" | "idle" | "listeningToUser" | "waitingForSpeechTimeout" | "processingUserRequest", string, {
|
|
74
62
|
conversationSettings: import("..").ConversationSettings;
|
|
75
63
|
languageModel: import("..").LanguageModel;
|
|
76
64
|
voice: import("..").Voice;
|
|
77
65
|
}, {}, import("xstate").EventObject, import("xstate").MetaObject, {
|
|
78
|
-
/** @xstate-layout
|
|
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 */
|
|
79
67
|
readonly context: ({ input }: {
|
|
80
68
|
input: {
|
|
81
69
|
voice: import("..").Voice;
|
|
@@ -99,10 +87,11 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
99
87
|
idleTimeoutCount: number;
|
|
100
88
|
maxSpeechWaitTimeout: number;
|
|
101
89
|
allowUserBargeIn: boolean;
|
|
102
|
-
isSpeaking: boolean;
|
|
103
90
|
sessionStartTime: number;
|
|
104
91
|
maxSessionDuration: number;
|
|
105
92
|
initialDtmf: string;
|
|
93
|
+
previousState: any;
|
|
94
|
+
isReentry: boolean;
|
|
106
95
|
};
|
|
107
96
|
readonly id: "fnAI";
|
|
108
97
|
readonly initial: "greeting";
|
|
@@ -119,8 +108,6 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
119
108
|
readonly idle: {
|
|
120
109
|
readonly entry: readonly [{
|
|
121
110
|
readonly type: "cleanSpeech";
|
|
122
|
-
}, {
|
|
123
|
-
readonly type: "setSpeakingDone";
|
|
124
111
|
}];
|
|
125
112
|
readonly on: {
|
|
126
113
|
readonly SPEECH_START: {
|
|
@@ -139,27 +126,21 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
139
126
|
params: undefined;
|
|
140
127
|
}>;
|
|
141
128
|
}, {
|
|
142
|
-
readonly target: "
|
|
129
|
+
readonly target: "idle";
|
|
143
130
|
readonly actions: readonly [{
|
|
144
131
|
readonly type: "increaseIdleTimeoutCount";
|
|
145
132
|
}, {
|
|
146
133
|
readonly type: "announceIdleTimeout";
|
|
147
134
|
}];
|
|
135
|
+
readonly reenter: true;
|
|
148
136
|
}];
|
|
149
137
|
};
|
|
150
138
|
};
|
|
151
|
-
readonly transitioningToIdle: {
|
|
152
|
-
readonly always: {
|
|
153
|
-
readonly target: "idle";
|
|
154
|
-
};
|
|
155
|
-
};
|
|
156
139
|
readonly listeningToUser: {
|
|
157
140
|
readonly entry: readonly [{
|
|
158
141
|
readonly type: "interruptPlayback";
|
|
159
142
|
}, {
|
|
160
143
|
readonly type: "resetIdleTimeoutCount";
|
|
161
|
-
}, {
|
|
162
|
-
readonly type: "setSpeaking";
|
|
163
144
|
}];
|
|
164
145
|
readonly on: {
|
|
165
146
|
readonly SPEECH_RESULT: {
|
|
@@ -173,7 +154,7 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
173
154
|
};
|
|
174
155
|
readonly after: {
|
|
175
156
|
readonly IDLE_TIMEOUT: readonly [{
|
|
176
|
-
readonly target: "
|
|
157
|
+
readonly target: "idle";
|
|
177
158
|
readonly actions: readonly [{
|
|
178
159
|
readonly type: "increaseIdleTimeoutCount";
|
|
179
160
|
}, {
|
|
@@ -218,6 +199,9 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
218
199
|
readonly guard: ({ context }: import("xstate/dist/declarations/src/guards").GuardArgs<any, {
|
|
219
200
|
type: "SPEECH_START";
|
|
220
201
|
}>) => any;
|
|
202
|
+
readonly actions: readonly [{
|
|
203
|
+
readonly type: "cleanSpeech";
|
|
204
|
+
}];
|
|
221
205
|
};
|
|
222
206
|
readonly SPEECH_RESULT: {
|
|
223
207
|
readonly target: "processingUserRequest";
|
|
@@ -227,6 +211,7 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
227
211
|
}, {
|
|
228
212
|
readonly type: "appendSpeech";
|
|
229
213
|
}];
|
|
214
|
+
readonly reenter: true;
|
|
230
215
|
};
|
|
231
216
|
};
|
|
232
217
|
readonly invoke: {
|
|
@@ -257,5 +242,16 @@ declare const machine: import("xstate").StateMachine<any, import("./types").Auto
|
|
|
257
242
|
};
|
|
258
243
|
};
|
|
259
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
|
+
};
|
|
260
256
|
}>;
|
|
261
257
|
export { machine };
|
package/dist/machine/machine.js
CHANGED
|
@@ -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
|
|
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",
|
|
@@ -38,7 +39,7 @@ const machine = setup_1.machineSetup.createMachine({
|
|
|
38
39
|
}
|
|
39
40
|
},
|
|
40
41
|
idle: {
|
|
41
|
-
entry: [{ type: "cleanSpeech" }
|
|
42
|
+
entry: [{ type: "cleanSpeech" }],
|
|
42
43
|
on: {
|
|
43
44
|
SPEECH_START: {
|
|
44
45
|
target: "listeningToUser",
|
|
@@ -53,29 +54,18 @@ const machine = setup_1.machineSetup.createMachine({
|
|
|
53
54
|
guard: (0, xstate_1.and)(["idleTimeoutCountExceedsMax"])
|
|
54
55
|
},
|
|
55
56
|
{
|
|
56
|
-
target: "
|
|
57
|
+
target: "idle",
|
|
57
58
|
actions: [
|
|
58
59
|
{ type: "increaseIdleTimeoutCount" },
|
|
59
60
|
{ type: "announceIdleTimeout" }
|
|
60
|
-
]
|
|
61
|
+
],
|
|
62
|
+
reenter: true
|
|
61
63
|
}
|
|
62
64
|
]
|
|
63
65
|
}
|
|
64
66
|
},
|
|
65
|
-
transitioningToIdle: {
|
|
66
|
-
// This intermediate state is necessary to ensure the IDLE_TIMEOUT
|
|
67
|
-
// event is properly reset and retriggered when returning to idle.
|
|
68
|
-
// Without it, the timer would not restart correctly.
|
|
69
|
-
always: {
|
|
70
|
-
target: "idle"
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
67
|
listeningToUser: {
|
|
74
|
-
entry: [
|
|
75
|
-
{ type: "interruptPlayback" },
|
|
76
|
-
{ type: "resetIdleTimeoutCount" },
|
|
77
|
-
{ type: "setSpeaking" }
|
|
78
|
-
],
|
|
68
|
+
entry: [{ type: "interruptPlayback" }, { type: "resetIdleTimeoutCount" }],
|
|
79
69
|
on: {
|
|
80
70
|
SPEECH_RESULT: {
|
|
81
71
|
target: "waitingForSpeechTimeout",
|
|
@@ -89,7 +79,7 @@ const machine = setup_1.machineSetup.createMachine({
|
|
|
89
79
|
after: {
|
|
90
80
|
IDLE_TIMEOUT: [
|
|
91
81
|
{
|
|
92
|
-
target: "
|
|
82
|
+
target: "idle",
|
|
93
83
|
actions: [
|
|
94
84
|
{ type: "increaseIdleTimeoutCount" },
|
|
95
85
|
{ type: "announceIdleTimeout" }
|
|
@@ -127,12 +117,17 @@ const machine = setup_1.machineSetup.createMachine({
|
|
|
127
117
|
SPEECH_START: {
|
|
128
118
|
target: "listeningToUser",
|
|
129
119
|
description: "Event from VAD or similar system.",
|
|
130
|
-
guard: ({ context }) => context.allowUserBargeIn
|
|
120
|
+
guard: ({ context }) => context.allowUserBargeIn,
|
|
121
|
+
// We assume that the user wants to steer the conversation
|
|
122
|
+
// back to the agent so we clean the speech buffer
|
|
123
|
+
actions: [{ type: "cleanSpeech" }]
|
|
131
124
|
},
|
|
132
125
|
SPEECH_RESULT: {
|
|
126
|
+
// This makes sure result that
|
|
133
127
|
target: "processingUserRequest",
|
|
134
128
|
description: "Append speech and go back to listening.",
|
|
135
|
-
actions: [{ type: "interruptPlayback" }, { type: "appendSpeech" }]
|
|
129
|
+
actions: [{ type: "interruptPlayback" }, { type: "appendSpeech" }],
|
|
130
|
+
reenter: true
|
|
136
131
|
}
|
|
137
132
|
},
|
|
138
133
|
invoke: {
|
|
@@ -152,6 +147,17 @@ const machine = setup_1.machineSetup.createMachine({
|
|
|
152
147
|
target: ".hangup",
|
|
153
148
|
actions: { type: "goodbye" }
|
|
154
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
|
+
}
|
|
155
161
|
}
|
|
156
162
|
});
|
|
157
163
|
exports.machine = machine;
|
package/dist/machine/setup.d.ts
CHANGED
|
@@ -30,14 +30,6 @@ declare const machineSetup: {
|
|
|
30
30
|
type: "resetState";
|
|
31
31
|
params: unknown;
|
|
32
32
|
};
|
|
33
|
-
setSpeaking: {
|
|
34
|
-
type: "setSpeaking";
|
|
35
|
-
params: unknown;
|
|
36
|
-
};
|
|
37
|
-
setSpeakingDone: {
|
|
38
|
-
type: "setSpeakingDone";
|
|
39
|
-
params: unknown;
|
|
40
|
-
};
|
|
41
33
|
greetUser: {
|
|
42
34
|
type: "greetUser";
|
|
43
35
|
params: unknown;
|
|
@@ -59,10 +51,6 @@ declare const machineSetup: {
|
|
|
59
51
|
params: unknown;
|
|
60
52
|
};
|
|
61
53
|
}>, import("xstate").Values<{
|
|
62
|
-
isSpeaking: {
|
|
63
|
-
type: "isSpeaking";
|
|
64
|
-
params: unknown;
|
|
65
|
-
};
|
|
66
54
|
idleTimeoutCountExceedsMax: {
|
|
67
55
|
type: "idleTimeoutCountExceedsMax";
|
|
68
56
|
params: unknown;
|
|
@@ -106,14 +94,6 @@ declare const machineSetup: {
|
|
|
106
94
|
type: "resetState";
|
|
107
95
|
params: unknown;
|
|
108
96
|
};
|
|
109
|
-
setSpeaking: {
|
|
110
|
-
type: "setSpeaking";
|
|
111
|
-
params: unknown;
|
|
112
|
-
};
|
|
113
|
-
setSpeakingDone: {
|
|
114
|
-
type: "setSpeakingDone";
|
|
115
|
-
params: unknown;
|
|
116
|
-
};
|
|
117
97
|
greetUser: {
|
|
118
98
|
type: "greetUser";
|
|
119
99
|
params: unknown;
|
|
@@ -135,10 +115,6 @@ declare const machineSetup: {
|
|
|
135
115
|
params: unknown;
|
|
136
116
|
};
|
|
137
117
|
}>, import("xstate").Values<{
|
|
138
|
-
isSpeaking: {
|
|
139
|
-
type: "isSpeaking";
|
|
140
|
-
params: unknown;
|
|
141
|
-
};
|
|
142
118
|
idleTimeoutCountExceedsMax: {
|
|
143
119
|
type: "idleTimeoutCountExceedsMax";
|
|
144
120
|
params: unknown;
|
package/dist/machine/setup.js
CHANGED
|
@@ -105,21 +105,8 @@ const machineSetup = (0, xstate_1.setup)({
|
|
|
105
105
|
return {
|
|
106
106
|
...context,
|
|
107
107
|
speechBuffer: "",
|
|
108
|
-
idleTimeoutCount: 0
|
|
109
|
-
isSpeaking: false
|
|
108
|
+
idleTimeoutCount: 0
|
|
110
109
|
};
|
|
111
|
-
}),
|
|
112
|
-
setSpeaking: (0, xstate_1.assign)(({ context }) => {
|
|
113
|
-
logger.verbose("called the setSpeaking action", { isSpeaking: true });
|
|
114
|
-
context.isSpeaking = true;
|
|
115
|
-
return context;
|
|
116
|
-
}),
|
|
117
|
-
setSpeakingDone: (0, xstate_1.assign)(({ context }) => {
|
|
118
|
-
logger.verbose("called the setSpeakingDone action", {
|
|
119
|
-
isSpeaking: false
|
|
120
|
-
});
|
|
121
|
-
context.isSpeaking = false;
|
|
122
|
-
return context;
|
|
123
110
|
})
|
|
124
111
|
},
|
|
125
112
|
guards,
|
package/dist/machine/types.d.ts
CHANGED
|
@@ -35,9 +35,10 @@ type AutopilotContext = {
|
|
|
35
35
|
maxSpeechWaitTimeout: number;
|
|
36
36
|
speechBuffer: string;
|
|
37
37
|
speechResponseTime: number;
|
|
38
|
-
isSpeaking: boolean;
|
|
39
38
|
knowledgeBaseSourceUrl?: string;
|
|
40
39
|
initialDtmf?: string;
|
|
40
|
+
previousState: string | null;
|
|
41
|
+
isReentry: boolean;
|
|
41
42
|
};
|
|
42
43
|
type AutopilotEvents = {
|
|
43
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);
|
package/dist/models/types.d.ts
CHANGED
|
@@ -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.
|
|
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": "
|
|
62
|
+
"gitHead": "c716ab1782c9e0c4034585a162664b026035821b"
|
|
63
63
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const setSpeaking: import("xstate").ActionFunction<import("xstate").MachineContext, import("xstate").AnyEventObject, import("xstate").EventObject, {}, import("xstate").ProvidedActor, never, never, never, never>;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setSpeaking = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Copyright (C) 2025 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 xstate_1 = require("xstate");
|
|
24
|
-
const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
|
|
25
|
-
exports.setSpeaking = (0, xstate_1.assign)(({ context }) => {
|
|
26
|
-
logger.verbose("called the setSpeaking action", { isSpeaking: true });
|
|
27
|
-
context.isSpeaking = true;
|
|
28
|
-
return context;
|
|
29
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const setSpeakingDone: import("xstate").ActionFunction<import("xstate").MachineContext, import("xstate").AnyEventObject, import("xstate").EventObject, {}, import("xstate").ProvidedActor, never, never, never, never>;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setSpeakingDone = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Copyright (C) 2025 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 xstate_1 = require("xstate");
|
|
24
|
-
const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
|
|
25
|
-
exports.setSpeakingDone = (0, xstate_1.assign)(({ context }) => {
|
|
26
|
-
logger.verbose("called the setSpeakingDone action", { isSpeaking: false });
|
|
27
|
-
context.isSpeaking = false;
|
|
28
|
-
return context;
|
|
29
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isSpeaking = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Copyright (C) 2025 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
|
-
const isSpeaking = ({ context }) => {
|
|
25
|
-
logger.verbose("called the isSpeaking guard", {
|
|
26
|
-
isSpeaking: context.isSpeaking
|
|
27
|
-
});
|
|
28
|
-
return context.isSpeaking;
|
|
29
|
-
};
|
|
30
|
-
exports.isSpeaking = isSpeaking;
|