@fonoster/autopilot 0.27.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/README.md +15 -52
  2. package/dist/index.d.ts +0 -5
  3. package/dist/index.js +0 -5
  4. package/dist/knowledge/AbstractKnowledgeBase.d.ts +3 -2
  5. package/dist/knowledge/AbstractKnowledgeBase.js +2 -7
  6. package/dist/knowledge/FilesKnowledgeBase.d.ts +1 -1
  7. package/dist/knowledge/MeteredEmbeddings.d.ts +47 -0
  8. package/dist/knowledge/MeteredEmbeddings.js +58 -0
  9. package/dist/knowledge/types.d.ts +1 -1
  10. package/dist/models/LanguageModelFactory.d.ts +5 -24
  11. package/dist/models/LanguageModelFactory.js +0 -1
  12. package/dist/models/createLanguageModel.d.ts +2 -2
  13. package/dist/models/createLanguageModel.js +2 -2
  14. package/dist/models/evaluations/createEvalEffectiveConfig.d.ts +10 -106
  15. package/dist/models/evaluations/createEvalEffectiveConfig.js +47 -7
  16. package/dist/models/evaluations/createEvaluateIntelligence.d.ts +21 -20
  17. package/dist/models/evaluations/createEvaluateIntelligence.js +53 -23
  18. package/dist/models/evaluations/createTestTextSimilarity.d.ts +7 -1
  19. package/dist/models/evaluations/createTestTextSimilarity.js +19 -1
  20. package/dist/models/evaluations/evalTestCases.d.ts +2 -2
  21. package/dist/models/evaluations/evalTestCases.js +7 -7
  22. package/dist/models/evaluations/evaluateScenario.js +2 -2
  23. package/dist/models/evaluations/evaluateStep.d.ts +1 -1
  24. package/dist/models/evaluations/evaluateStep.js +2 -2
  25. package/dist/models/evaluations/extractAiResponse.d.ts +2 -3
  26. package/dist/models/evaluations/extractAiResponse.js +3 -3
  27. package/dist/models/evaluations/index.d.ts +1 -0
  28. package/dist/models/evaluations/index.js +1 -0
  29. package/dist/models/evaluations/runEval.d.ts +2 -20
  30. package/dist/models/evaluations/runEval.js +7 -7
  31. package/dist/models/evaluations/session/EvalSession.d.ts +73 -0
  32. package/dist/models/evaluations/session/EvalSession.js +134 -0
  33. package/dist/models/evaluations/session/evaluateSessionScenario.d.ts +58 -0
  34. package/dist/models/evaluations/session/evaluateSessionScenario.js +182 -0
  35. package/dist/{vad → models/evaluations/session}/index.d.ts +3 -2
  36. package/dist/{vad → models/evaluations/session}/index.js +3 -2
  37. package/dist/models/evaluations/session/runSessionEval.d.ts +20 -0
  38. package/dist/models/evaluations/session/runSessionEval.js +59 -0
  39. package/dist/models/evaluations/textSimilaryPrompt.d.ts +1 -1
  40. package/dist/models/evaluations/textSimilaryPrompt.js +1 -1
  41. package/dist/models/evaluations/types.d.ts +7 -6
  42. package/dist/models/types.d.ts +19 -1
  43. package/dist/session/Agent.d.ts +173 -0
  44. package/dist/session/Agent.js +548 -0
  45. package/dist/{loadAssistantFromAPI.d.ts → session/AsyncQueue.d.ts} +12 -7
  46. package/dist/session/AsyncQueue.js +67 -0
  47. package/dist/{machine/guards/index.d.ts → session/config.d.ts} +2 -2
  48. package/dist/session/config.js +27 -0
  49. package/dist/session/createAutopilot.d.ts +48 -0
  50. package/dist/session/createAutopilot.js +151 -0
  51. package/dist/session/hosted.d.ts +454 -0
  52. package/dist/session/hosted.js +501 -0
  53. package/dist/{assistants → session}/index.d.ts +11 -2
  54. package/dist/{machine/actors → session}/index.js +11 -3
  55. package/dist/{machine/actions/appendSpeech.js → session/knowledge.d.ts} +14 -17
  56. package/dist/session/knowledge.js +10 -0
  57. package/dist/session/llm.d.ts +113 -0
  58. package/dist/session/llm.js +127 -0
  59. package/dist/session/machine.d.ts +206 -0
  60. package/dist/session/machine.js +126 -0
  61. package/dist/session/main.js +45 -0
  62. package/dist/session/meteredThink.d.ts +45 -0
  63. package/dist/session/meteredThink.js +125 -0
  64. package/dist/session/sentences.d.ts +5 -0
  65. package/dist/session/sentences.js +53 -0
  66. package/dist/session/telemetry.d.ts +34 -0
  67. package/dist/session/telemetry.js +55 -0
  68. package/dist/{machine/actors/index.d.ts → session/think.d.ts} +2 -3
  69. package/dist/{machine/actions/announceSystemError.js → session/think.js} +8 -10
  70. package/dist/session/tools.d.ts +22 -0
  71. package/dist/session/tools.js +83 -0
  72. package/dist/tools/builtin/transferToolDefinition.js +1 -1
  73. package/dist/voice/index.d.ts +0 -1
  74. package/dist/voice/index.js +0 -1
  75. package/dist/voice/types.d.ts +5 -18
  76. package/package.json +15 -16
  77. package/dist/Autopilot.d.ts +0 -14
  78. package/dist/Autopilot.js +0 -133
  79. package/dist/assistants/index.js +0 -36
  80. package/dist/assistants/loadAndValidateAssistant.d.ts +0 -3
  81. package/dist/assistants/loadAndValidateAssistant.js +0 -49
  82. package/dist/assistants/types.d.ts +0 -24
  83. package/dist/assistants/types.js +0 -2
  84. package/dist/envs.d.ts +0 -15
  85. package/dist/envs.js +0 -78
  86. package/dist/handleVoiceRequest.d.ts +0 -3
  87. package/dist/handleVoiceRequest.js +0 -167
  88. package/dist/loadAssistantConfigFromFile.d.ts +0 -3
  89. package/dist/loadAssistantConfigFromFile.js +0 -68
  90. package/dist/loadAssistantFromAPI.js +0 -98
  91. package/dist/machine/actions/announceSystemError.d.ts +0 -4
  92. package/dist/machine/actions/appendSpeech.d.ts +0 -1
  93. package/dist/machine/actions/cleanSpeech.d.ts +0 -1
  94. package/dist/machine/actions/cleanSpeech.js +0 -23
  95. package/dist/machine/actions/goodbye.d.ts +0 -4
  96. package/dist/machine/actions/goodbye.js +0 -31
  97. package/dist/machine/actions/increaseIdleTimeoutCount.d.ts +0 -1
  98. package/dist/machine/actions/increaseIdleTimeoutCount.js +0 -31
  99. package/dist/machine/actions/index.d.ts +0 -26
  100. package/dist/machine/actions/index.js +0 -37
  101. package/dist/machine/actions/interruptPlayback.d.ts +0 -4
  102. package/dist/machine/actions/interruptPlayback.js +0 -43
  103. package/dist/machine/actions/resetIdleTimeoutCount.d.ts +0 -1
  104. package/dist/machine/actions/resetIdleTimeoutCount.js +0 -31
  105. package/dist/machine/actions/resetState.d.ts +0 -1
  106. package/dist/machine/actions/resetState.js +0 -32
  107. package/dist/machine/actors/doAnnounceIdleTimeout.d.ts +0 -4
  108. package/dist/machine/actors/doAnnounceIdleTimeout.js +0 -41
  109. package/dist/machine/actors/doGreetUser.d.ts +0 -4
  110. package/dist/machine/actors/doGreetUser.js +0 -45
  111. package/dist/machine/actors/doProcessUserRequest.d.ts +0 -4
  112. package/dist/machine/actors/doProcessUserRequest.js +0 -75
  113. package/dist/machine/context.d.ts +0 -52
  114. package/dist/machine/context.js +0 -28
  115. package/dist/machine/delays.d.ts +0 -30
  116. package/dist/machine/delays.js +0 -37
  117. package/dist/machine/guards/hasSpeechResult.d.ts +0 -4
  118. package/dist/machine/guards/hasSpeechResult.js +0 -30
  119. package/dist/machine/guards/idleTimeoutCountExceedsMax.d.ts +0 -4
  120. package/dist/machine/guards/idleTimeoutCountExceedsMax.js +0 -31
  121. package/dist/machine/guards/index.js +0 -25
  122. package/dist/machine/index.d.ts +0 -19
  123. package/dist/machine/index.js +0 -23
  124. package/dist/machine/machine.d.ts +0 -408
  125. package/dist/machine/machine.js +0 -206
  126. package/dist/machine/setup.d.ts +0 -328
  127. package/dist/machine/setup.js +0 -116
  128. package/dist/machine/types.d.ts +0 -54
  129. package/dist/machine/types.js +0 -2
  130. package/dist/sendConversationEndedEvent.d.ts +0 -32
  131. package/dist/sendConversationEndedEvent.js +0 -66
  132. package/dist/sendConversationStartedEvent.d.ts +0 -6
  133. package/dist/sendConversationStartedEvent.js +0 -63
  134. package/dist/server.d.ts +0 -2
  135. package/dist/server.js +0 -25
  136. package/dist/types.d.ts +0 -40
  137. package/dist/types.js +0 -8
  138. package/dist/vad/SileroVad.d.ts +0 -18
  139. package/dist/vad/SileroVad.js +0 -40
  140. package/dist/vad/SileroVadModel.d.ts +0 -14
  141. package/dist/vad/SileroVadModel.js +0 -83
  142. package/dist/vad/chunkToFloat32Array.d.ts +0 -20
  143. package/dist/vad/chunkToFloat32Array.js +0 -34
  144. package/dist/vad/createVad.d.ts +0 -3
  145. package/dist/vad/createVad.js +0 -126
  146. package/dist/vad/types.d.ts +0 -60
  147. package/dist/vad/types.js +0 -2
  148. package/dist/vadWorker.js +0 -36
  149. package/dist/voice/Voice.d.ts +0 -61
  150. package/dist/voice/Voice.js +0 -96
  151. package/dist/voiceServerSetup.d.ts +0 -2
  152. package/dist/voiceServerSetup.js +0 -29
  153. /package/dist/{vadWorker.d.ts → session/main.d.ts} +0 -0
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.evalToolPort = void 0;
4
+ exports.evaluateSessionScenario = evaluateSessionScenario;
5
+ const createAutopilot_1 = require("../../../session/createAutopilot");
6
+ const evaluateTextResponse_1 = require("../evaluateTextResponse");
7
+ const evaluateToolCalls_1 = require("../evaluateToolCalls");
8
+ const EvalSession_1 = require("./EvalSession");
9
+ /** The default eval tool port: records nothing, calls nothing, every tool succeeds. */
10
+ exports.evalToolPort = {
11
+ run: async () => ({
12
+ ok: true,
13
+ result: { status: "ok" }
14
+ })
15
+ };
16
+ const SETTLE_POLL_MS = 10;
17
+ /** Resolves once the session has had no new output and no say in flight for two polls. */
18
+ async function settle(session) {
19
+ let seen = -1;
20
+ let quiet = 0;
21
+ while (quiet < 2) {
22
+ await new Promise((r) => setTimeout(r, SETTLE_POLL_MS));
23
+ if (!session.busy && session.outputs.length === seen)
24
+ quiet++;
25
+ else
26
+ quiet = 0;
27
+ seen = session.outputs.length;
28
+ }
29
+ }
30
+ function parseArgs(call) {
31
+ try {
32
+ return call.arguments ? JSON.parse(call.arguments) : {};
33
+ }
34
+ catch {
35
+ return {};
36
+ }
37
+ }
38
+ /**
39
+ * Runs one test-case scenario through the session engine (rework-autopilot 1.4): the real state
40
+ * machine and Agent on an in-memory session, replies streamed sentence by sentence, tool calls
41
+ * read back from the structured tool messages in the history.
42
+ */
43
+ async function evaluateSessionScenario(options, scenario, onStepResult) {
44
+ const { agent: agentConfig, testTextSimilarity } = options;
45
+ const stepTimeoutMs = options.stepTimeoutMs ?? 60000;
46
+ const session = new EvalSession_1.EvalSession(scenario.telephonyContext);
47
+ let agent;
48
+ let signal;
49
+ let thinkError;
50
+ const traces = [];
51
+ // Think errors are swallowed by the engine (it apologises); keep them for the report.
52
+ const think = {
53
+ stream: (messages, tools, abort) => (async function* () {
54
+ try {
55
+ yield* options.think.stream(messages, tools, abort);
56
+ }
57
+ catch (e) {
58
+ if (!abort.aborted) {
59
+ thinkError = e;
60
+ signal?.();
61
+ }
62
+ throw e;
63
+ }
64
+ })()
65
+ };
66
+ const handler = (0, createAutopilot_1.createAutopilotHandler)({
67
+ agent: { ...agentConfig, testCases: undefined },
68
+ think,
69
+ tools: options.tools ?? exports.evalToolPort,
70
+ recorder: {
71
+ turn: (t) => {
72
+ traces.push(t);
73
+ signal?.();
74
+ },
75
+ note: () => undefined
76
+ },
77
+ onAgent: (a) => (agent = a)
78
+ });
79
+ session.onOutput((o) => {
80
+ if (o.kind === "hangup" || o.kind === "transfer")
81
+ signal?.();
82
+ });
83
+ const running = handler(session);
84
+ const results = [];
85
+ try {
86
+ await settle(session); // greeting
87
+ for (const step of scenario.conversation) {
88
+ const type = step.expected.text.type;
89
+ const report = {
90
+ humanInput: step.userInput,
91
+ expectedResponse: step.expected.text.response,
92
+ aiResponse: "",
93
+ evaluationType: type,
94
+ passed: true,
95
+ streaming: { pieces: [] },
96
+ toolMessages: []
97
+ };
98
+ results.push(report);
99
+ if (session.ended) {
100
+ report.passed = false;
101
+ report.errorMessage = `The call had already ended before "${step.userInput}".`;
102
+ if (onStepResult)
103
+ await onStepResult(scenario.ref, report);
104
+ continue;
105
+ }
106
+ const outputsFrom = session.outputs.length;
107
+ const historyFrom = agent?.history.length ?? 0;
108
+ const tracesFrom = traces.length;
109
+ thinkError = undefined;
110
+ let timer;
111
+ const done = new Promise((resolve) => {
112
+ signal = () => resolve(true);
113
+ timer = setTimeout(() => resolve(false), stepTimeoutMs);
114
+ });
115
+ session.turn(step.userInput);
116
+ const finished = await done;
117
+ clearTimeout(timer);
118
+ signal = undefined;
119
+ await settle(session);
120
+ const outputs = session.outputs.slice(outputsFrom);
121
+ const says = outputs.filter((o) => o.kind === "say");
122
+ const reply = says.filter((s) => s.streamed);
123
+ const history = agent?.history.slice(historyFrom) ?? [];
124
+ const toolCalls = history.flatMap((m) => m.role === "assistant" ? (m.tool_calls ?? []) : []);
125
+ const builtIn = toolCalls.find((c) => c.name === "hangup" || c.name === "transfer");
126
+ const trace = traces[tracesFrom];
127
+ report.streaming = {
128
+ pieces: reply.flatMap((s) => s.pieces),
129
+ firstTokenMs: trace?.firstTokenMs,
130
+ firstSpeakMs: trace?.firstSpeakMs
131
+ };
132
+ report.toolMessages = history.filter((m) => m.role === "tool" || (m.role === "assistant" && m.tool_calls));
133
+ // What the caller hears: the streamed reply; for hangup or transfer, the message the
134
+ // engine says for it (as the legacy evals compared).
135
+ report.aiResponse = builtIn
136
+ ? builtIn.name === "hangup"
137
+ ? agentConfig.conversationSettings.goodbyeMessage
138
+ : (agentConfig.conversationSettings.transferOptions?.message ?? "")
139
+ : reply
140
+ .map((s) => s.text)
141
+ .join("")
142
+ .trim();
143
+ if (thinkError) {
144
+ report.passed = false;
145
+ report.aiResponse = says.map((s) => s.text).join(" ");
146
+ report.errorMessage = `Language model error for input "${step.userInput}": ${thinkError.message}`;
147
+ }
148
+ else if (!finished) {
149
+ report.passed = false;
150
+ report.errorMessage = `No reply within ${stepTimeoutMs} ms for "${step.userInput}".`;
151
+ }
152
+ else {
153
+ const text = await (0, evaluateTextResponse_1.evaluateTextResponse)({ type, response: step.expected.text.response }, report.aiResponse, testTextSimilarity);
154
+ if (!text.passed) {
155
+ report.passed = false;
156
+ report.errorMessage = text.errorMessage;
157
+ }
158
+ if (step.expected.tools && step.expected.tools.length > 0) {
159
+ const tools = (0, evaluateToolCalls_1.evaluateToolCalls)(step.expected.tools, toolCalls.map((c) => ({ name: c.name, args: parseArgs(c) })));
160
+ report.toolEvaluations = tools.evaluations;
161
+ if (!tools.passed) {
162
+ report.passed = false;
163
+ report.errorMessage = report.errorMessage
164
+ ? `${report.errorMessage} ${tools.errorMessage}`
165
+ : tools.errorMessage;
166
+ }
167
+ }
168
+ }
169
+ if (onStepResult)
170
+ await onStepResult(scenario.ref, report);
171
+ }
172
+ }
173
+ finally {
174
+ session.end();
175
+ await running.catch(() => undefined);
176
+ }
177
+ return {
178
+ scenarioRef: scenario.ref,
179
+ overallPassed: results.every((s) => s.passed),
180
+ steps: results
181
+ };
182
+ }
@@ -16,5 +16,6 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
- export * from "./SileroVad";
20
- export * from "./types";
19
+ export * from "./EvalSession";
20
+ export * from "./evaluateSessionScenario";
21
+ export * from "./runSessionEval";
@@ -32,5 +32,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
32
32
  * See the License for the specific language governing permissions and
33
33
  * limitations under the License.
34
34
  */
35
- __exportStar(require("./SileroVad"), exports);
36
- __exportStar(require("./types"), exports);
35
+ __exportStar(require("./EvalSession"), exports);
36
+ __exportStar(require("./evaluateSessionScenario"), exports);
37
+ __exportStar(require("./runSessionEval"), exports);
@@ -0,0 +1,20 @@
1
+ import { SessionAgent } from "../../../session/config";
2
+ import { Think } from "../../../session/think";
3
+ import { createTestTextSimilarity } from "../createTestTextSimilarity";
4
+ import { RunEvalCallbacks } from "../types";
5
+ import { SessionEvalOptions, SessionScenarioReport } from "./evaluateSessionScenario";
6
+ export type RunSessionEvalOptions = Omit<SessionEvalOptions, "testTextSimilarity"> & {
7
+ /** Defaults to the OpenAI similarity judge from the agent's testCases. */
8
+ testTextSimilarity?: SessionEvalOptions["testTextSimilarity"];
9
+ /** The judge's key (the testCases model is always OpenAI). */
10
+ evaluationApiKey?: string;
11
+ /** Meters the judge's tokens (add-usage-metering). */
12
+ judgeUsage?: Parameters<typeof createTestTextSimilarity>[2];
13
+ };
14
+ /**
15
+ * The session-engine Think for an agent whose catalog provider speaks OpenAI-compatible Chat
16
+ * Completions with a known endpoint (openai, groq, ollama); undefined otherwise.
17
+ */
18
+ export declare function sessionThinkFor(agent: SessionAgent, apiKey: string | undefined): Think | undefined;
19
+ /** Runs every test-case scenario through the session engine, streaming results. */
20
+ export declare function runSessionEval(options: RunSessionEvalOptions, callbacks?: Partial<RunEvalCallbacks>): Promise<SessionScenarioReport[]>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sessionThinkFor = sessionThinkFor;
4
+ exports.runSessionEval = runSessionEval;
5
+ /**
6
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
7
+ * http://github.com/fonoster/fonoster
8
+ *
9
+ * This file is part of Fonoster
10
+ *
11
+ * Licensed under the MIT License (the "License");
12
+ * you may not use this file except in compliance with
13
+ * the License. You may obtain a copy of the License at
14
+ *
15
+ * https://opensource.org/licenses/MIT
16
+ *
17
+ * Unless required by applicable law or agreed to in writing, software
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ * See the License for the specific language governing permissions and
21
+ * limitations under the License.
22
+ */
23
+ const common_1 = require("@fonoster/common");
24
+ const openai_1 = require("@fonoster/community/openai");
25
+ const createTestTextSimilarity_1 = require("../createTestTextSimilarity");
26
+ const textSimilaryPrompt_1 = require("../textSimilaryPrompt");
27
+ const evaluateSessionScenario_1 = require("./evaluateSessionScenario");
28
+ /**
29
+ * The session-engine Think for an agent whose catalog provider speaks OpenAI-compatible Chat
30
+ * Completions with a known endpoint (openai, groq, ollama); undefined otherwise.
31
+ */
32
+ function sessionThinkFor(agent, apiKey) {
33
+ const id = agent.languageModel.model;
34
+ const slash = id.indexOf("/");
35
+ const baseUrl = openai_1.OPENAI_COMPATIBLE[id.slice(0, slash)];
36
+ if (!baseUrl)
37
+ return undefined;
38
+ return new openai_1.OpenAiCompatibleThink({ baseUrl, apiKey }, id.slice(slash + 1), {
39
+ temperature: agent.languageModel.temperature,
40
+ maxTokens: agent.languageModel.maxTokens
41
+ });
42
+ }
43
+ /** Runs every test-case scenario through the session engine, streaming results. */
44
+ async function runSessionEval(options, callbacks) {
45
+ const testCases = common_1.testCasesSchema.parse(options.agent.testCases);
46
+ const testTextSimilarity = options.testTextSimilarity ??
47
+ (0, createTestTextSimilarity_1.createTestTextSimilarity)({
48
+ provider: testCases.evalsLanguageModel.provider,
49
+ model: testCases.evalsLanguageModel.model,
50
+ apiKey: options.evaluationApiKey ?? testCases.evalsLanguageModel.apiKey
51
+ }, testCases.evalsSystemPrompt || textSimilaryPrompt_1.textSimilaryPrompt, options.judgeUsage);
52
+ const reports = [];
53
+ for (const scenario of testCases.scenarios) {
54
+ const report = await (0, evaluateSessionScenario_1.evaluateSessionScenario)({ ...options, testTextSimilarity }, scenario, callbacks?.onStepResult);
55
+ reports.push(report);
56
+ await callbacks?.onScenarioComplete?.(report.scenarioRef, report.overallPassed);
57
+ }
58
+ return reports;
59
+ }
@@ -16,4 +16,4 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
- export declare const textSimilaryPrompt = "\nYou are a text similarity evaluator for a Voice Assistant application. \n\nGive Text1 and Text2, you use the following process to evaluate the similarity between the two texts:\n\n- Take the first text and determmine the intent of the text.\n- Take the second text and determine the intent of the text.\n- Compare the intents of the two texts ignoring the actual text content, the entities, and length of the text.\n\n## Example 1\n\nText1: \"You're welcome. Have a great day!\"\nText2: \"You're welcome [name]. Your appointment is confirmed. Goodbye!\"\n\nAnswer: true\n\n=== \n\nAre the intents of the two texts the same? Respond with true.\n";
19
+ export declare const textSimilaryPrompt = "\nYou are a text similarity evaluator for a Voice Agent application. \n\nGive Text1 and Text2, you use the following process to evaluate the similarity between the two texts:\n\n- Take the first text and determmine the intent of the text.\n- Take the second text and determine the intent of the text.\n- Compare the intents of the two texts ignoring the actual text content, the entities, and length of the text.\n\n## Example 1\n\nText1: \"You're welcome. Have a great day!\"\nText2: \"You're welcome [name]. Your appointment is confirmed. Goodbye!\"\n\nAnswer: true\n\n=== \n\nAre the intents of the two texts the same? Respond with true.\n";
@@ -20,7 +20,7 @@ exports.textSimilaryPrompt = void 0;
20
20
  * limitations under the License.
21
21
  */
22
22
  exports.textSimilaryPrompt = `
23
- You are a text similarity evaluator for a Voice Assistant application.
23
+ You are a text similarity evaluator for a Voice Agent application.
24
24
 
25
25
  Give Text1 and Text2, you use the following process to evaluate the similarity between the two texts:
26
26
 
@@ -17,8 +17,7 @@
17
17
  * limitations under the License.
18
18
  */
19
19
  import { StepEvaluationReport } from "@fonoster/types";
20
- import { AssistantConfig } from "../../assistants";
21
- import { LanguageModel } from "../types";
20
+ import { EvalAgent, LanguageModel } from "../types";
22
21
  type EvalExpectedTool = {
23
22
  tool: string;
24
23
  parameters?: Record<string, unknown>;
@@ -46,18 +45,20 @@ type EvalScenario = {
46
45
  };
47
46
  type EvaluateIntelligenceRequest = {
48
47
  intelligence: {
49
- productRef: string;
50
- config: AssistantConfig;
48
+ /** Ignored: the agent's catalog id names the provider. */
49
+ productRef?: string;
50
+ /** A session agent (with testCases), as a protobuf Struct. */
51
+ config: unknown;
51
52
  };
52
53
  };
53
54
  type EvaluateStepParams = {
54
55
  step: EvalConversationStep;
55
56
  languageModel: LanguageModel;
56
57
  testTextSimilarity: (text1: string, text2: string) => Promise<boolean>;
57
- assistantConfig: AssistantConfig;
58
+ agentConfig: EvalAgent;
58
59
  };
59
60
  type ScenarioEvaluationRequest = {
60
- assistantConfig: AssistantConfig;
61
+ agentConfig: EvalAgent;
61
62
  scenario: EvalScenario;
62
63
  languageModel: LanguageModel;
63
64
  testTextSimilarity: (text1: string, text2: string) => Promise<boolean>;
@@ -16,11 +16,29 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
+ import { SessionConversationSettings, SessionLanguageModel, testCasesSchema } from "@fonoster/common";
19
20
  import { CallDirection } from "@fonoster/types";
20
21
  import { BaseChatModel } from "@langchain/core/language_models/chat_models";
21
22
  import { ToolCall } from "@langchain/core/messages/tool";
23
+ import { z } from "zod";
22
24
  import { KnowledgeBase } from "../knowledge";
23
25
  import { Tool } from "../tools/types";
26
+ /** The language model vendors the LangChain models (used by the evaluations only) implement. */
27
+ type LlmProvider = "openai" | "groq" | "ollama" | "google" | "anthropic";
28
+ /**
29
+ * A session agent as the evaluations run it (rework-autopilot 8.2): the catalog id split into
30
+ * provider and model, and the keys the control plane resolved for this run. Never stored.
31
+ */
32
+ type EvalAgent = {
33
+ conversationSettings: SessionConversationSettings;
34
+ languageModel: Omit<SessionLanguageModel, "model" | "provider" | "apiKey" | "baseUrl"> & {
35
+ provider: LlmProvider;
36
+ model: string;
37
+ apiKey?: string;
38
+ baseUrl?: string;
39
+ };
40
+ testCases?: z.infer<typeof testCasesSchema>;
41
+ };
24
42
  type LanguageModel = {
25
43
  invoke: (text: string, isReentry?: boolean) => Promise<InvocationResult>;
26
44
  };
@@ -49,4 +67,4 @@ type TelephonyContext = {
49
67
  callerNumber: string;
50
68
  metadata?: Record<string, string>;
51
69
  };
52
- export { BaseModelParams, InvocationResult, LanguageModel, LanguageModelParams, TelephonyContext };
70
+ export { BaseModelParams, EvalAgent, LlmProvider, InvocationResult, LanguageModel, LanguageModelParams, TelephonyContext };
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
3
+ * http://github.com/fonoster/fonoster
4
+ *
5
+ * This file is part of Fonoster
6
+ *
7
+ * Licensed under the MIT License (the "License");
8
+ * you may not use this file except in compliance with
9
+ * the License. You may obtain a copy of the License at
10
+ *
11
+ * https://opensource.org/licenses/MIT
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ import { Usage } from "@fonoster/common";
20
+ import { SessionAgent } from "./config";
21
+ import { KnowledgePort } from "./knowledge";
22
+ import { ChatMessage, Think } from "./think";
23
+ import { ToolPort } from "./tools";
24
+ import type { Session } from "@fonoster/voice";
25
+ /** What Autopilot says when a transfer fails and the agent sets no `failedMessage`. */
26
+ export declare const DEFAULT_TRANSFER_FAILED_MESSAGE = "Sorry, I couldn't connect you. How else can I help?";
27
+ export type SpokenSource = "greeting" | "reply" | "idle" | "error";
28
+ export type AgentEvent = {
29
+ type: "TURN_USER_STARTED";
30
+ } | {
31
+ type: "TURN_LIKELY_ENDED";
32
+ text: string;
33
+ } | {
34
+ type: "TURN_RESUMED";
35
+ } | {
36
+ type: "TURN_ENDED";
37
+ text: string;
38
+ } | {
39
+ type: "TURN_BACKCHANNEL";
40
+ } | {
41
+ type: "REPLY_SPEAKING";
42
+ }
43
+ /** An output finished; `source` says which, so stale events from an earlier phase are ignored. */
44
+ | {
45
+ type: "SPOKEN";
46
+ source: SpokenSource;
47
+ } | {
48
+ type: "IDLE";
49
+ } | {
50
+ type: "MAX_DURATION";
51
+ } | {
52
+ type: "HANGUP_REQUESTED";
53
+ } | {
54
+ type: "TRANSFER_REQUESTED";
55
+ } | {
56
+ type: "SESSION_END";
57
+ };
58
+ /** One turn's trace for the call record (rework-autopilot A10). */
59
+ export type TurnTrace = {
60
+ userText: string;
61
+ replyText: string;
62
+ heardText: string;
63
+ interrupted: boolean;
64
+ toolCalls: {
65
+ name: string;
66
+ ok: boolean;
67
+ }[];
68
+ /** ms from turn.ended to the first token, and to the first speak sent. */
69
+ firstTokenMs?: number;
70
+ firstSpeakMs?: number;
71
+ };
72
+ export interface Recorder {
73
+ turn(trace: TurnTrace): void;
74
+ note(event: Record<string, unknown>): void;
75
+ /** Model token usage for the call (usage.report); absent where there is no call. */
76
+ usage?(lines: Usage.UsageLine[]): void;
77
+ }
78
+ /** Writes turn traces and notes to the call record through the session (record.note). */
79
+ export declare function sessionRecorder(session: Session): Recorder;
80
+ export declare const logRecorder: Recorder;
81
+ /** The side effects of Autopilot: everything the state machine asks it to do on the session. */
82
+ export declare class Agent {
83
+ private readonly session;
84
+ private readonly agent;
85
+ private readonly think;
86
+ private readonly tools;
87
+ private readonly recorder;
88
+ private readonly knowledge?;
89
+ readonly history: ChatMessage[];
90
+ private reply?;
91
+ private inflight?;
92
+ private prepared?;
93
+ private idleTimer?;
94
+ /** The model's `transfer` tool call, answered in the history if the transfer fails. */
95
+ private transferCallId?;
96
+ private maxTimer?;
97
+ private idleCount;
98
+ private resumes;
99
+ /** Whether a reply is prepared on turn.likely_ended (off at high patience or once adapted). */
100
+ private prepareEarly;
101
+ private stopped;
102
+ send: (event: AgentEvent) => void;
103
+ constructor(session: Session, agent: SessionAgent, think: Think, tools: ToolPort, recorder?: Recorder, knowledge?: KnowledgePort);
104
+ get settings(): {
105
+ firstMessage?: string;
106
+ systemPrompt?: string;
107
+ goodbyeMessage?: string;
108
+ systemErrorMessage?: string;
109
+ initialDtmf?: string;
110
+ maxSessionDuration?: number;
111
+ transferOptions?: {
112
+ message?: string;
113
+ phoneNumber?: string;
114
+ failedMessage?: string;
115
+ };
116
+ idleOptions?: {
117
+ message?: string;
118
+ timeout?: number;
119
+ maxTimeoutCount?: number;
120
+ };
121
+ allowUserBargeIn?: boolean;
122
+ patience?: "low" | "normal" | "high";
123
+ hints?: string[];
124
+ filler?: {
125
+ url?: string;
126
+ };
127
+ voice?: string;
128
+ language?: string;
129
+ vad?: any;
130
+ maxSpeechWaitTimeout?: any;
131
+ };
132
+ /** Greeting: subscribe to the estimate, send initial DTMF, speak the first message. */
133
+ greet(): Promise<void>;
134
+ stop(): void;
135
+ armIdle(): void;
136
+ disarmIdle(): void;
137
+ /** The next idle timeout ends the call (the goodbye counts as the last announcement). */
138
+ idleExhausted(): boolean;
139
+ sayIdle(): Promise<void>;
140
+ /** turn.likely_ended: start generating silently (when preparing early). */
141
+ prepare(text: string): void;
142
+ /** turn.resumed: the caller kept talking; the prepared reply is dropped. */
143
+ resumed(): void;
144
+ clear(): Promise<void>;
145
+ abortReply(): void;
146
+ /** turn.ended: answer the caller, streaming sentences into one speak id. */
147
+ answer(text: string): Promise<void>;
148
+ /** One turn (STT final, LLM, TTS) as an autopilot.turn span. */
149
+ private respond;
150
+ private respondTurn;
151
+ private speakRound;
152
+ private runTools;
153
+ goodbye(): Promise<void>;
154
+ transfer(): Promise<void>;
155
+ /**
156
+ * The transfer failed: say so and keep helping (autopilot "Transfer fails"). The model learns
157
+ * the outcome as its transfer call's result, and the machine returns to listening.
158
+ */
159
+ private transferFailed;
160
+ private messages;
161
+ /** Knowledge for this turn, as a system message for the request only (never in history). */
162
+ private contextFor;
163
+ private toolSpecs;
164
+ private startStream;
165
+ /** think.stream inside an autopilot.llm.request span, with request and latency metrics. */
166
+ private traced;
167
+ private takePrepared;
168
+ private discardPrepared;
169
+ private pump;
170
+ private speechOptions;
171
+ /** Runs session work; a session that has ended stops everything quietly. */
172
+ private safely;
173
+ }