@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.
- package/README.md +15 -52
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -5
- package/dist/knowledge/AbstractKnowledgeBase.d.ts +3 -2
- package/dist/knowledge/AbstractKnowledgeBase.js +2 -7
- package/dist/knowledge/FilesKnowledgeBase.d.ts +1 -1
- package/dist/knowledge/MeteredEmbeddings.d.ts +47 -0
- package/dist/knowledge/MeteredEmbeddings.js +58 -0
- package/dist/knowledge/types.d.ts +1 -1
- package/dist/models/LanguageModelFactory.d.ts +5 -24
- package/dist/models/LanguageModelFactory.js +0 -1
- package/dist/models/createLanguageModel.d.ts +2 -2
- package/dist/models/createLanguageModel.js +2 -2
- package/dist/models/evaluations/createEvalEffectiveConfig.d.ts +10 -106
- package/dist/models/evaluations/createEvalEffectiveConfig.js +47 -7
- package/dist/models/evaluations/createEvaluateIntelligence.d.ts +21 -20
- package/dist/models/evaluations/createEvaluateIntelligence.js +53 -23
- package/dist/models/evaluations/createTestTextSimilarity.d.ts +7 -1
- package/dist/models/evaluations/createTestTextSimilarity.js +19 -1
- package/dist/models/evaluations/evalTestCases.d.ts +2 -2
- package/dist/models/evaluations/evalTestCases.js +7 -7
- package/dist/models/evaluations/evaluateScenario.js +2 -2
- package/dist/models/evaluations/evaluateStep.d.ts +1 -1
- package/dist/models/evaluations/evaluateStep.js +2 -2
- package/dist/models/evaluations/extractAiResponse.d.ts +2 -3
- package/dist/models/evaluations/extractAiResponse.js +3 -3
- package/dist/models/evaluations/index.d.ts +1 -0
- package/dist/models/evaluations/index.js +1 -0
- package/dist/models/evaluations/runEval.d.ts +2 -20
- package/dist/models/evaluations/runEval.js +7 -7
- package/dist/models/evaluations/session/EvalSession.d.ts +73 -0
- package/dist/models/evaluations/session/EvalSession.js +134 -0
- package/dist/models/evaluations/session/evaluateSessionScenario.d.ts +58 -0
- package/dist/models/evaluations/session/evaluateSessionScenario.js +182 -0
- package/dist/{vad → models/evaluations/session}/index.d.ts +3 -2
- package/dist/{vad → models/evaluations/session}/index.js +3 -2
- package/dist/models/evaluations/session/runSessionEval.d.ts +20 -0
- package/dist/models/evaluations/session/runSessionEval.js +59 -0
- package/dist/models/evaluations/textSimilaryPrompt.d.ts +1 -1
- package/dist/models/evaluations/textSimilaryPrompt.js +1 -1
- package/dist/models/evaluations/types.d.ts +7 -6
- package/dist/models/types.d.ts +19 -1
- package/dist/session/Agent.d.ts +173 -0
- package/dist/session/Agent.js +548 -0
- package/dist/{loadAssistantFromAPI.d.ts → session/AsyncQueue.d.ts} +12 -7
- package/dist/session/AsyncQueue.js +67 -0
- package/dist/{machine/guards/index.d.ts → session/config.d.ts} +2 -2
- package/dist/session/config.js +27 -0
- package/dist/session/createAutopilot.d.ts +48 -0
- package/dist/session/createAutopilot.js +151 -0
- package/dist/session/hosted.d.ts +454 -0
- package/dist/session/hosted.js +501 -0
- package/dist/{assistants → session}/index.d.ts +11 -2
- package/dist/{machine/actors → session}/index.js +11 -3
- package/dist/{machine/actions/appendSpeech.js → session/knowledge.d.ts} +14 -17
- package/dist/session/knowledge.js +10 -0
- package/dist/session/llm.d.ts +113 -0
- package/dist/session/llm.js +127 -0
- package/dist/session/machine.d.ts +206 -0
- package/dist/session/machine.js +126 -0
- package/dist/session/main.js +45 -0
- package/dist/session/meteredThink.d.ts +45 -0
- package/dist/session/meteredThink.js +125 -0
- package/dist/session/sentences.d.ts +5 -0
- package/dist/session/sentences.js +53 -0
- package/dist/session/telemetry.d.ts +34 -0
- package/dist/session/telemetry.js +55 -0
- package/dist/{machine/actors/index.d.ts → session/think.d.ts} +2 -3
- package/dist/{machine/actions/announceSystemError.js → session/think.js} +8 -10
- package/dist/session/tools.d.ts +22 -0
- package/dist/session/tools.js +83 -0
- package/dist/tools/builtin/transferToolDefinition.js +1 -1
- package/dist/voice/index.d.ts +0 -1
- package/dist/voice/index.js +0 -1
- package/dist/voice/types.d.ts +5 -18
- package/package.json +15 -16
- package/dist/Autopilot.d.ts +0 -14
- package/dist/Autopilot.js +0 -133
- package/dist/assistants/index.js +0 -36
- package/dist/assistants/loadAndValidateAssistant.d.ts +0 -3
- package/dist/assistants/loadAndValidateAssistant.js +0 -49
- package/dist/assistants/types.d.ts +0 -24
- package/dist/assistants/types.js +0 -2
- package/dist/envs.d.ts +0 -15
- package/dist/envs.js +0 -78
- package/dist/handleVoiceRequest.d.ts +0 -3
- package/dist/handleVoiceRequest.js +0 -167
- package/dist/loadAssistantConfigFromFile.d.ts +0 -3
- package/dist/loadAssistantConfigFromFile.js +0 -68
- package/dist/loadAssistantFromAPI.js +0 -98
- package/dist/machine/actions/announceSystemError.d.ts +0 -4
- package/dist/machine/actions/appendSpeech.d.ts +0 -1
- package/dist/machine/actions/cleanSpeech.d.ts +0 -1
- package/dist/machine/actions/cleanSpeech.js +0 -23
- package/dist/machine/actions/goodbye.d.ts +0 -4
- package/dist/machine/actions/goodbye.js +0 -31
- package/dist/machine/actions/increaseIdleTimeoutCount.d.ts +0 -1
- package/dist/machine/actions/increaseIdleTimeoutCount.js +0 -31
- package/dist/machine/actions/index.d.ts +0 -26
- package/dist/machine/actions/index.js +0 -37
- package/dist/machine/actions/interruptPlayback.d.ts +0 -4
- package/dist/machine/actions/interruptPlayback.js +0 -43
- package/dist/machine/actions/resetIdleTimeoutCount.d.ts +0 -1
- package/dist/machine/actions/resetIdleTimeoutCount.js +0 -31
- package/dist/machine/actions/resetState.d.ts +0 -1
- package/dist/machine/actions/resetState.js +0 -32
- package/dist/machine/actors/doAnnounceIdleTimeout.d.ts +0 -4
- package/dist/machine/actors/doAnnounceIdleTimeout.js +0 -41
- package/dist/machine/actors/doGreetUser.d.ts +0 -4
- package/dist/machine/actors/doGreetUser.js +0 -45
- package/dist/machine/actors/doProcessUserRequest.d.ts +0 -4
- package/dist/machine/actors/doProcessUserRequest.js +0 -75
- package/dist/machine/context.d.ts +0 -52
- package/dist/machine/context.js +0 -28
- package/dist/machine/delays.d.ts +0 -30
- package/dist/machine/delays.js +0 -37
- package/dist/machine/guards/hasSpeechResult.d.ts +0 -4
- package/dist/machine/guards/hasSpeechResult.js +0 -30
- package/dist/machine/guards/idleTimeoutCountExceedsMax.d.ts +0 -4
- package/dist/machine/guards/idleTimeoutCountExceedsMax.js +0 -31
- package/dist/machine/guards/index.js +0 -25
- package/dist/machine/index.d.ts +0 -19
- package/dist/machine/index.js +0 -23
- package/dist/machine/machine.d.ts +0 -408
- package/dist/machine/machine.js +0 -206
- package/dist/machine/setup.d.ts +0 -328
- package/dist/machine/setup.js +0 -116
- package/dist/machine/types.d.ts +0 -54
- package/dist/machine/types.js +0 -2
- package/dist/sendConversationEndedEvent.d.ts +0 -32
- package/dist/sendConversationEndedEvent.js +0 -66
- package/dist/sendConversationStartedEvent.d.ts +0 -6
- package/dist/sendConversationStartedEvent.js +0 -63
- package/dist/server.d.ts +0 -2
- package/dist/server.js +0 -25
- package/dist/types.d.ts +0 -40
- package/dist/types.js +0 -8
- package/dist/vad/SileroVad.d.ts +0 -18
- package/dist/vad/SileroVad.js +0 -40
- package/dist/vad/SileroVadModel.d.ts +0 -14
- package/dist/vad/SileroVadModel.js +0 -83
- package/dist/vad/chunkToFloat32Array.d.ts +0 -20
- package/dist/vad/chunkToFloat32Array.js +0 -34
- package/dist/vad/createVad.d.ts +0 -3
- package/dist/vad/createVad.js +0 -126
- package/dist/vad/types.d.ts +0 -60
- package/dist/vad/types.js +0 -2
- package/dist/vadWorker.js +0 -36
- package/dist/voice/Voice.d.ts +0 -61
- package/dist/voice/Voice.js +0 -96
- package/dist/voiceServerSetup.d.ts +0 -2
- package/dist/voiceServerSetup.js +0 -29
- /package/dist/{vadWorker.d.ts → session/main.d.ts} +0 -0
|
@@ -0,0 +1,501 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FileWorkspaceSecrets = exports.CellSecretCredentials = exports.DatabaseWorkspaceSecrets = exports.PrismaAgentSource = exports.FileAgentSource = exports.AUTOPILOT_CONFIG_DIRS = exports.hostedConfigSchema = void 0;
|
|
37
|
+
exports.findHostedConfig = findHostedConfig;
|
|
38
|
+
exports.loadHostedConfig = loadHostedConfig;
|
|
39
|
+
exports.s3Knowledge = s3Knowledge;
|
|
40
|
+
exports.hostedOptions = hostedOptions;
|
|
41
|
+
exports.eagerKnowledge = eagerKnowledge;
|
|
42
|
+
exports.signedWorkspaceOnly = signedWorkspaceOnly;
|
|
43
|
+
exports.startHostedAutopilot = startHostedAutopilot;
|
|
44
|
+
/**
|
|
45
|
+
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
46
|
+
* http://github.com/fonoster/fonoster
|
|
47
|
+
*
|
|
48
|
+
* This file is part of Fonoster
|
|
49
|
+
*
|
|
50
|
+
* Licensed under the MIT License (the "License");
|
|
51
|
+
* you may not use this file except in compliance with
|
|
52
|
+
* the License. You may obtain a copy of the License at
|
|
53
|
+
*
|
|
54
|
+
* https://opensource.org/licenses/MIT
|
|
55
|
+
*
|
|
56
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
57
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
58
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
59
|
+
* See the License for the specific language governing permissions and
|
|
60
|
+
* limitations under the License.
|
|
61
|
+
*/
|
|
62
|
+
const fs = __importStar(require("fs"));
|
|
63
|
+
const path = __importStar(require("path"));
|
|
64
|
+
const common_1 = require("@fonoster/common");
|
|
65
|
+
const logger_1 = require("@fonoster/logger");
|
|
66
|
+
const voice_1 = require("@fonoster/voice");
|
|
67
|
+
const yaml = __importStar(require("js-yaml"));
|
|
68
|
+
const zod_1 = require("zod");
|
|
69
|
+
const MeteredEmbeddings_1 = require("../knowledge/MeteredEmbeddings");
|
|
70
|
+
const createAutopilot_1 = require("./createAutopilot");
|
|
71
|
+
const knowledge_1 = require("./knowledge");
|
|
72
|
+
const llm_1 = require("./llm");
|
|
73
|
+
// The hosted Autopilot (rework-autopilot A2, task 4.3): an ordinary VoiceServer that AppBridge
|
|
74
|
+
// dials like any app. Everything it needs comes from one operator config file; no vendor key is
|
|
75
|
+
// read from Autopilot's environment by name (A8, A11), only through credential refs.
|
|
76
|
+
const logger = (0, logger_1.getLogger)({ service: "autopilot", filePath: __filename });
|
|
77
|
+
const secretRef = zod_1.z.union([
|
|
78
|
+
zod_1.z.object({ env: zod_1.z.string() }).strict(),
|
|
79
|
+
zod_1.z.object({ value: zod_1.z.string() }).strict()
|
|
80
|
+
]);
|
|
81
|
+
const wsUrl = zod_1.z.string().regex(/^wss?:\/\//, "must be a ws:// or wss:// URL");
|
|
82
|
+
exports.hostedConfigSchema = zod_1.z
|
|
83
|
+
.object({
|
|
84
|
+
host: zod_1.z.string().default("0.0.0.0"),
|
|
85
|
+
port: zod_1.z.number().int().nonnegative().default(50061),
|
|
86
|
+
/**
|
|
87
|
+
* Private destinations HTTP tools may call (host names, IPs, CIDRs; RV-B2); defaults to
|
|
88
|
+
* FONOSTER_ALLOWED_DESTINATIONS.
|
|
89
|
+
*/
|
|
90
|
+
allowedDestinations: zod_1.z.array(zod_1.z.string()).optional(),
|
|
91
|
+
/** The secret AppBridge signs Autopilot sessions with (one for every Autopilot app). */
|
|
92
|
+
signingSecret: secretRef,
|
|
93
|
+
/**
|
|
94
|
+
* The URL Autopilot apps point to, exactly as the apps have it (the apiserver's
|
|
95
|
+
* `apps.autopilotUrl`, e.g. ws://autopilot:3000), or several. Signatures are checked against
|
|
96
|
+
* it, never against the request's Host header.
|
|
97
|
+
*/
|
|
98
|
+
publicUrl: zod_1.z.union([wsUrl, zod_1.z.array(wsUrl).min(1)], {
|
|
99
|
+
errorMap: (issue, ctx) => ({
|
|
100
|
+
message: issue.code !== "invalid_union"
|
|
101
|
+
? ctx.defaultError
|
|
102
|
+
: ctx.data === undefined
|
|
103
|
+
? "is required: the URL Autopilot apps point to (the apiserver's apps.autopilotUrl)"
|
|
104
|
+
: "must be a ws:// or wss:// URL, or a list of them"
|
|
105
|
+
})
|
|
106
|
+
}),
|
|
107
|
+
/**
|
|
108
|
+
* Apps and their agents: a file `{apps: {<appRef>: {workspaceRef?, agent}}}` (JSON or
|
|
109
|
+
* YAML), or `database`: the apps' Intelligence rows, cached for `cacheMs` (CP-B11).
|
|
110
|
+
*/
|
|
111
|
+
agents: zod_1.z.union([
|
|
112
|
+
zod_1.z.object({ file: zod_1.z.string() }).strict(),
|
|
113
|
+
zod_1.z
|
|
114
|
+
.object({
|
|
115
|
+
source: zod_1.z.literal("database"),
|
|
116
|
+
cacheMs: zod_1.z.number().int().nonnegative().default(5000)
|
|
117
|
+
})
|
|
118
|
+
.strict()
|
|
119
|
+
]),
|
|
120
|
+
/** The provider registry's catalog: the JSON file fonoster-registry writes, or the tables. */
|
|
121
|
+
registry: zod_1.z.union([
|
|
122
|
+
zod_1.z.object({ file: zod_1.z.string() }).strict(),
|
|
123
|
+
zod_1.z
|
|
124
|
+
.object({
|
|
125
|
+
source: zod_1.z.literal("database"),
|
|
126
|
+
refreshMs: zod_1.z.number().int().positive().default(30000)
|
|
127
|
+
})
|
|
128
|
+
.strict()
|
|
129
|
+
]),
|
|
130
|
+
/** Platform keys by credentialRef. */
|
|
131
|
+
credentials: zod_1.z.record(secretRef).default({}),
|
|
132
|
+
/**
|
|
133
|
+
* Workspace Secrets (bring your own key): a JSON file by workspace and credentialRef, or
|
|
134
|
+
* `database`: the workspace's vendor keys (workspace_provider_keys).
|
|
135
|
+
*/
|
|
136
|
+
workspaceSecrets: zod_1.z
|
|
137
|
+
.union([
|
|
138
|
+
zod_1.z.object({ file: zod_1.z.string() }).strict(),
|
|
139
|
+
zod_1.z.object({ source: zod_1.z.literal("database") }).strict(),
|
|
140
|
+
// A private region's cell secrets (add-private-regions PR-4, PR-9): by credentialRef or
|
|
141
|
+
// provider id, set on the cell with `fonoster-region secrets set <name>`.
|
|
142
|
+
zod_1.z
|
|
143
|
+
.object({
|
|
144
|
+
cellSecrets: zod_1.z
|
|
145
|
+
.object({
|
|
146
|
+
file: zod_1.z.string().optional(),
|
|
147
|
+
dir: zod_1.z.string().optional(),
|
|
148
|
+
keyEnv: zod_1.z.string().optional()
|
|
149
|
+
})
|
|
150
|
+
.strict()
|
|
151
|
+
})
|
|
152
|
+
.strict()
|
|
153
|
+
])
|
|
154
|
+
.optional(),
|
|
155
|
+
/**
|
|
156
|
+
* The control-plane database (the apiserver's), for any `source: database`. The URL comes
|
|
157
|
+
* from this file only, usually as a placeholder: `url: "${APISERVER_DATABASE_URL}"`.
|
|
158
|
+
*/
|
|
159
|
+
database: zod_1.z
|
|
160
|
+
.object({
|
|
161
|
+
url: zod_1.z.string().min(1),
|
|
162
|
+
/** A client generated from the apiserver schema (default `@prisma/client`). */
|
|
163
|
+
clientModule: zod_1.z.string().optional()
|
|
164
|
+
})
|
|
165
|
+
.strict()
|
|
166
|
+
.optional(),
|
|
167
|
+
/** Endpoint overrides by provider or adapter id (e.g. a local ollama); the catalog's otherwise. */
|
|
168
|
+
endpoints: zod_1.z.record(zod_1.z.string()).default({}),
|
|
169
|
+
/** The S3 + Unstructured knowledge bases; keys by credentialRef (task 4.1). */
|
|
170
|
+
knowledge: zod_1.z
|
|
171
|
+
.object({
|
|
172
|
+
s3: zod_1.z.object({
|
|
173
|
+
endpoint: zod_1.z.string(),
|
|
174
|
+
region: zod_1.z.string().default("us-east-1"),
|
|
175
|
+
accessKeyIdRef: zod_1.z.string(),
|
|
176
|
+
secretAccessKeyRef: zod_1.z.string()
|
|
177
|
+
}),
|
|
178
|
+
unstructured: zod_1.z.object({ url: zod_1.z.string(), apiKeyRef: zod_1.z.string() }),
|
|
179
|
+
embeddings: zod_1.z.object({ apiKeyRef: zod_1.z.string() })
|
|
180
|
+
})
|
|
181
|
+
.optional(),
|
|
182
|
+
/**
|
|
183
|
+
* The apiserver's encryption key (fonoster.yaml `encryption.key`; vendor keys are encrypted
|
|
184
|
+
* Secrets). Usually "${ENCRYPTION_KEY}".
|
|
185
|
+
*/
|
|
186
|
+
encryption: zod_1.z
|
|
187
|
+
.object({ key: zod_1.z.string().min(1) })
|
|
188
|
+
.strict()
|
|
189
|
+
.optional(),
|
|
190
|
+
/** OTLP export (empty = off): `otlpEndpoint: "${OTEL_EXPORTER_OTLP_ENDPOINT:-}"`. */
|
|
191
|
+
telemetry: common_1.telemetrySchema
|
|
192
|
+
})
|
|
193
|
+
.strict();
|
|
194
|
+
function readStructured(file) {
|
|
195
|
+
const text = fs.readFileSync(file, "utf8");
|
|
196
|
+
return /\.ya?ml$/.test(file) ? yaml.load(text) : JSON.parse(text);
|
|
197
|
+
}
|
|
198
|
+
/** Where Autopilot looks for its file when none is named (autopilot.yaml, then the older name). */
|
|
199
|
+
exports.AUTOPILOT_CONFIG_DIRS = ["/config", "/etc/fonoster", "./config"];
|
|
200
|
+
/** The file `loadHostedConfig` reads without `--config`: the first one found, or undefined. */
|
|
201
|
+
function findHostedConfig() {
|
|
202
|
+
for (const base of ["autopilot", "autopilot-session"]) {
|
|
203
|
+
const found = (0, common_1.resolveConfigFile)(base, [], exports.AUTOPILOT_CONFIG_DIRS);
|
|
204
|
+
if (found.path)
|
|
205
|
+
return found.path;
|
|
206
|
+
}
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Loads the hosted Autopilot's file the apiserver's way (unify-config-placeholders): `${VAR}`
|
|
211
|
+
* placeholders from the container environment, `secret://` references, strict validation.
|
|
212
|
+
*/
|
|
213
|
+
function loadHostedConfig(file, env = process.env) {
|
|
214
|
+
const config = (0, common_1.loadServiceConfig)({
|
|
215
|
+
service: "autopilot",
|
|
216
|
+
schema: exports.hostedConfigSchema,
|
|
217
|
+
argv: ["--config", file],
|
|
218
|
+
env,
|
|
219
|
+
interpolatePaths: ["*"]
|
|
220
|
+
});
|
|
221
|
+
const dir = path.dirname(file);
|
|
222
|
+
const rel = (p) => (path.isAbsolute(p) ? p : path.join(dir, p));
|
|
223
|
+
const withFile = (c) => "file" in c ? { ...c, file: rel(c.file) } : c;
|
|
224
|
+
const needsDb = !("file" in config.agents) ||
|
|
225
|
+
!("file" in config.registry) ||
|
|
226
|
+
(config.workspaceSecrets &&
|
|
227
|
+
"source" in config.workspaceSecrets &&
|
|
228
|
+
config.workspaceSecrets.source === "database");
|
|
229
|
+
if (needsDb && !config.database)
|
|
230
|
+
throw new Error("source: database needs a database section");
|
|
231
|
+
return {
|
|
232
|
+
...config,
|
|
233
|
+
agents: withFile(config.agents),
|
|
234
|
+
registry: withFile(config.registry),
|
|
235
|
+
...(config.workspaceSecrets
|
|
236
|
+
? { workspaceSecrets: withFile(config.workspaceSecrets) }
|
|
237
|
+
: {})
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const resolveSecret = (s) => "value" in s && s.value !== undefined ? s.value : process.env[s.env ?? ""];
|
|
241
|
+
/** Apps and agents from a file (a stand-in until agents come from the control plane). */
|
|
242
|
+
class FileAgentSource {
|
|
243
|
+
constructor(file) {
|
|
244
|
+
this.file = file;
|
|
245
|
+
}
|
|
246
|
+
async get(appRef) {
|
|
247
|
+
const data = readStructured(this.file);
|
|
248
|
+
const app = data.apps?.[appRef];
|
|
249
|
+
return app
|
|
250
|
+
? { agent: app.agent, workspaceRef: app.workspaceRef }
|
|
251
|
+
: undefined;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
exports.FileAgentSource = FileAgentSource;
|
|
255
|
+
/**
|
|
256
|
+
* Agents from the control plane: an Autopilot app's Intelligence row holds its agent
|
|
257
|
+
* (CP-B3). Each app is cached for `cacheMs` (misses too), so edits show up within seconds.
|
|
258
|
+
*/
|
|
259
|
+
class PrismaAgentSource {
|
|
260
|
+
constructor(
|
|
261
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
262
|
+
prisma, options = {}) {
|
|
263
|
+
this.prisma = prisma;
|
|
264
|
+
this.options = options;
|
|
265
|
+
this.cache = new Map();
|
|
266
|
+
}
|
|
267
|
+
async get(appRef) {
|
|
268
|
+
const now = this.options.now?.() ?? Date.now();
|
|
269
|
+
const hit = this.cache.get(appRef);
|
|
270
|
+
if (hit && now - hit.at < (this.options.cacheMs ?? 5000))
|
|
271
|
+
return hit.value;
|
|
272
|
+
const row = await this.prisma.application.findUnique({
|
|
273
|
+
where: { ref: appRef },
|
|
274
|
+
include: { intelligence: true }
|
|
275
|
+
});
|
|
276
|
+
const value = row && row.type === "AUTOPILOT" && row.intelligence?.config
|
|
277
|
+
? { agent: row.intelligence.config, workspaceRef: row.accessKeyId }
|
|
278
|
+
: undefined;
|
|
279
|
+
this.cache.set(appRef, { at: now, value });
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
exports.PrismaAgentSource = PrismaAgentSource;
|
|
284
|
+
/** Workspace vendor keys from the database, looked up by the credentialRef's providers. */
|
|
285
|
+
class DatabaseWorkspaceSecrets {
|
|
286
|
+
constructor(keys, providers) {
|
|
287
|
+
this.keys = keys;
|
|
288
|
+
this.providers = providers;
|
|
289
|
+
}
|
|
290
|
+
get(ref, scope) {
|
|
291
|
+
if (!scope.workspaceRef)
|
|
292
|
+
return undefined;
|
|
293
|
+
return this.keys.forCredentialRef(scope.workspaceRef, ref, this.providers());
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
exports.DatabaseWorkspaceSecrets = DatabaseWorkspaceSecrets;
|
|
297
|
+
/** A private region's cell secrets (PR-4): keys never leave the cell. */
|
|
298
|
+
class CellSecretCredentials {
|
|
299
|
+
constructor(keys, providers) {
|
|
300
|
+
this.keys = keys;
|
|
301
|
+
this.providers = providers;
|
|
302
|
+
}
|
|
303
|
+
get(ref) {
|
|
304
|
+
return this.keys.forCredentialRef(ref, this.providers());
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
exports.CellSecretCredentials = CellSecretCredentials;
|
|
308
|
+
/** Workspace Secrets from a JSON file: `{<workspaceRef>: {<credentialRef>: value}}`. */
|
|
309
|
+
class FileWorkspaceSecrets {
|
|
310
|
+
constructor(file) {
|
|
311
|
+
this.file = file;
|
|
312
|
+
}
|
|
313
|
+
get(ref, scope) {
|
|
314
|
+
if (!scope.workspaceRef)
|
|
315
|
+
return undefined;
|
|
316
|
+
const data = readStructured(this.file);
|
|
317
|
+
return data[scope.workspaceRef]?.[ref];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
exports.FileWorkspaceSecrets = FileWorkspaceSecrets;
|
|
321
|
+
/**
|
|
322
|
+
* Builds the knowledge port for an agent from the operator's S3 + Unstructured settings,
|
|
323
|
+
* with keys from the credential source (never Autopilot's environment). The bucket is the
|
|
324
|
+
* workspace's, as today. `make` is the knowledge base constructor (the S3 one by default).
|
|
325
|
+
*/
|
|
326
|
+
function s3Knowledge(config, credentials, make) {
|
|
327
|
+
return async (agent, scope, usage) => {
|
|
328
|
+
const documents = agent.languageModel.knowledgeBase.map((d) => d.document);
|
|
329
|
+
if (!documents.length || !scope.workspaceRef)
|
|
330
|
+
return undefined;
|
|
331
|
+
const key = (ref) => credentials.get(ref, scope);
|
|
332
|
+
const [accessKeyId, secretAccessKey, unstructuredKey, embeddingsKey] = await Promise.all([
|
|
333
|
+
key(config.s3.accessKeyIdRef),
|
|
334
|
+
key(config.s3.secretAccessKeyRef),
|
|
335
|
+
key(config.unstructured.apiKeyRef),
|
|
336
|
+
(0, llm_1.resolveCredential)(credentials, config.embeddings.apiKeyRef, scope)
|
|
337
|
+
]);
|
|
338
|
+
const params = {
|
|
339
|
+
bucket: scope.workspaceRef.toLowerCase(),
|
|
340
|
+
documents,
|
|
341
|
+
s3Config: {
|
|
342
|
+
endpoint: config.s3.endpoint,
|
|
343
|
+
region: config.s3.region,
|
|
344
|
+
credentials: {
|
|
345
|
+
accessKeyId: accessKeyId ?? "",
|
|
346
|
+
secretAccessKey: secretAccessKey ?? ""
|
|
347
|
+
},
|
|
348
|
+
forcePathStyle: true
|
|
349
|
+
},
|
|
350
|
+
unstructuredAPIURL: config.unstructured.url,
|
|
351
|
+
unstructuredAPIKey: unstructuredKey ?? "",
|
|
352
|
+
embeddingsApiKey: embeddingsKey?.key ?? "",
|
|
353
|
+
embeddingsKeySource: embeddingsKey?.source ?? "platform",
|
|
354
|
+
usage
|
|
355
|
+
};
|
|
356
|
+
const kb = (make ?? defaultKnowledgeBase)(params);
|
|
357
|
+
kb.load().catch((e) => logger.warn(`knowledge base did not load: ${e.message}`));
|
|
358
|
+
return (0, knowledge_1.fromKnowledgeBase)(kb);
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
function defaultKnowledgeBase(params) {
|
|
362
|
+
// Loaded lazily: the S3 loader and embeddings pull in LangChain, which only the knowledge
|
|
363
|
+
// port still uses.
|
|
364
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
365
|
+
const { S3KnowledgeBase } = require("../knowledge/S3KnowledgeBase");
|
|
366
|
+
return new S3KnowledgeBase({
|
|
367
|
+
...params,
|
|
368
|
+
// Metered: the vendor's token usage reaches the call (add-usage-metering).
|
|
369
|
+
embeddings: new MeteredEmbeddings_1.MeteredEmbeddings({
|
|
370
|
+
apiKey: String(params.embeddingsApiKey ?? ""),
|
|
371
|
+
keySource: params.embeddingsKeySource,
|
|
372
|
+
sink: params.usage
|
|
373
|
+
})
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
/** Opens the control-plane database named in the config (once). */
|
|
377
|
+
function databaseOf(config) {
|
|
378
|
+
const d = config.database;
|
|
379
|
+
return common_1.Registry.openPrismaClient({
|
|
380
|
+
url: d.url,
|
|
381
|
+
encryptionKey: config.encryption?.key,
|
|
382
|
+
clientModule: d.clientModule
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/** The registry store: the file, or the tables refreshed every `refreshMs`. */
|
|
386
|
+
function registryStore(config,
|
|
387
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
388
|
+
db) {
|
|
389
|
+
if ("file" in config.registry)
|
|
390
|
+
return new common_1.Registry.FileRegistryStore(config.registry.file);
|
|
391
|
+
const store = new common_1.Registry.MemoryRegistryStore();
|
|
392
|
+
const every = config.registry.refreshMs ?? 30000;
|
|
393
|
+
const load = () => common_1.Registry.PrismaRegistryStore.open(db())
|
|
394
|
+
.then((loaded) => {
|
|
395
|
+
for (const e of loaded.all())
|
|
396
|
+
store.put(e);
|
|
397
|
+
})
|
|
398
|
+
.catch((e) => logger.warn(`registry refresh failed, keeping the last: ${e.message}`));
|
|
399
|
+
void load();
|
|
400
|
+
setInterval(load, every).unref();
|
|
401
|
+
return store;
|
|
402
|
+
}
|
|
403
|
+
/** The handler options the hosted Autopilot runs with, built from its config. */
|
|
404
|
+
function hostedOptions(config,
|
|
405
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
406
|
+
deps = {}) {
|
|
407
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
408
|
+
let prisma = deps.prisma;
|
|
409
|
+
const db = () => (prisma ?? (prisma = databaseOf(config)));
|
|
410
|
+
const store = registryStore(config, db);
|
|
411
|
+
const registry = new common_1.Registry.Registry({ store });
|
|
412
|
+
const providers = () => store
|
|
413
|
+
.all()
|
|
414
|
+
.filter((e) => e.kind === "provider" && Boolean(e.credentialRef))
|
|
415
|
+
.map((e) => ({ id: e.id, credentialRef: e.credentialRef }));
|
|
416
|
+
const workspace = config.workspaceSecrets;
|
|
417
|
+
const credentials = new llm_1.LayeredCredentials([
|
|
418
|
+
...(workspace
|
|
419
|
+
? [
|
|
420
|
+
"file" in workspace
|
|
421
|
+
? new FileWorkspaceSecrets(workspace.file)
|
|
422
|
+
: "cellSecrets" in workspace
|
|
423
|
+
? new CellSecretCredentials(new common_1.CellSecrets.CellSecretKeys(common_1.CellSecrets.openCellSecrets(workspace.cellSecrets)), providers)
|
|
424
|
+
: new DatabaseWorkspaceSecrets(new common_1.Registry.PrismaWorkspaceKeys(db()), providers)
|
|
425
|
+
]
|
|
426
|
+
: []),
|
|
427
|
+
new llm_1.ConfigCredentials(config.credentials)
|
|
428
|
+
]);
|
|
429
|
+
const agents = "file" in config.agents
|
|
430
|
+
? new FileAgentSource(config.agents.file)
|
|
431
|
+
: new PrismaAgentSource(db(), {
|
|
432
|
+
cacheMs: config.agents.cacheMs
|
|
433
|
+
});
|
|
434
|
+
const knowledge = config.knowledge
|
|
435
|
+
? s3Knowledge(config.knowledge, credentials)
|
|
436
|
+
: undefined;
|
|
437
|
+
return {
|
|
438
|
+
load: async (session) => signedWorkspaceOnly(session, await agents.get(session.appRef)),
|
|
439
|
+
allowedDestinations: config.allowedDestinations,
|
|
440
|
+
llm: new llm_1.RegistryLlmResolver({
|
|
441
|
+
registry,
|
|
442
|
+
credentials,
|
|
443
|
+
endpoints: config.endpoints
|
|
444
|
+
}),
|
|
445
|
+
knowledgeFor: knowledge ? eagerKnowledge(knowledge) : undefined
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* One knowledge port per call, built eagerly; a lookup waits for it (and gives up after 800 ms
|
|
450
|
+
* like any). A port that fails to build is logged and answers nothing: the eager promise always
|
|
451
|
+
* has a handler, so a failure never becomes an unhandled rejection (RV-B5).
|
|
452
|
+
*/
|
|
453
|
+
function eagerKnowledge(build) {
|
|
454
|
+
return (agent, scope, usage) => {
|
|
455
|
+
const port = Promise.resolve()
|
|
456
|
+
.then(() => build(agent, scope, usage))
|
|
457
|
+
.catch((e) => {
|
|
458
|
+
logger.warn(`knowledge port unavailable: ${e?.message ?? e}`);
|
|
459
|
+
return undefined;
|
|
460
|
+
});
|
|
461
|
+
return {
|
|
462
|
+
find: async (question, signal) => {
|
|
463
|
+
const p = await port;
|
|
464
|
+
return p ? p.find(question, signal) : "";
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* The app's agent only when the app belongs to the workspace AppBridge signed for: one
|
|
471
|
+
* secret serves every Autopilot app, so a session is bound to its app and workspace
|
|
472
|
+
* (voice-session, "Connection requests are bound to the app").
|
|
473
|
+
*/
|
|
474
|
+
function signedWorkspaceOnly(session, loaded) {
|
|
475
|
+
const signed = session.signedFor;
|
|
476
|
+
if (!loaded || !signed || loaded.workspaceRef === undefined)
|
|
477
|
+
return loaded;
|
|
478
|
+
if (signed.workspaceRef === loaded.workspaceRef)
|
|
479
|
+
return loaded;
|
|
480
|
+
logger.warn("refused a session: the app is not in the signed workspace", {
|
|
481
|
+
appRef: session.appRef
|
|
482
|
+
});
|
|
483
|
+
return undefined;
|
|
484
|
+
}
|
|
485
|
+
/** Starts the hosted Autopilot. */
|
|
486
|
+
async function startHostedAutopilot(config) {
|
|
487
|
+
const secret = resolveSecret(config.signingSecret);
|
|
488
|
+
if (!secret)
|
|
489
|
+
throw new Error("signingSecret resolves to nothing");
|
|
490
|
+
const server = await new voice_1.VoiceServer({
|
|
491
|
+
host: config.host,
|
|
492
|
+
port: config.port,
|
|
493
|
+
signingSecret: secret,
|
|
494
|
+
// Every Autopilot app shares this secret: check the configured URL only (never Host) and
|
|
495
|
+
// require the signature bound to the app and workspace.
|
|
496
|
+
publicUrl: config.publicUrl,
|
|
497
|
+
requireAppBinding: true
|
|
498
|
+
}).listen((0, createAutopilot_1.createAutopilotHandler)(hostedOptions(config)));
|
|
499
|
+
logger.info(`hosted autopilot listening on ${config.host}:${server.port}`);
|
|
500
|
+
return server;
|
|
501
|
+
}
|
|
@@ -16,5 +16,14 @@
|
|
|
16
16
|
* See the License for the specific language governing permissions and
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
|
-
export * from "./
|
|
20
|
-
export * from "./
|
|
19
|
+
export * from "./Agent";
|
|
20
|
+
export * from "./config";
|
|
21
|
+
export * from "./createAutopilot";
|
|
22
|
+
export * from "./hosted";
|
|
23
|
+
export * from "./knowledge";
|
|
24
|
+
export * from "./llm";
|
|
25
|
+
export * from "./machine";
|
|
26
|
+
export * from "./sentences";
|
|
27
|
+
export * from "./telemetry";
|
|
28
|
+
export * from "./think";
|
|
29
|
+
export * from "./tools";
|
|
@@ -32,6 +32,14 @@ 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("./
|
|
36
|
-
__exportStar(require("./
|
|
37
|
-
__exportStar(require("./
|
|
35
|
+
__exportStar(require("./Agent"), exports);
|
|
36
|
+
__exportStar(require("./config"), exports);
|
|
37
|
+
__exportStar(require("./createAutopilot"), exports);
|
|
38
|
+
__exportStar(require("./hosted"), exports);
|
|
39
|
+
__exportStar(require("./knowledge"), exports);
|
|
40
|
+
__exportStar(require("./llm"), exports);
|
|
41
|
+
__exportStar(require("./machine"), exports);
|
|
42
|
+
__exportStar(require("./sentences"), exports);
|
|
43
|
+
__exportStar(require("./telemetry"), exports);
|
|
44
|
+
__exportStar(require("./think"), exports);
|
|
45
|
+
__exportStar(require("./tools"), exports);
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.appendSpeech = void 0;
|
|
4
1
|
/**
|
|
5
2
|
* Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
|
|
6
3
|
* http://github.com/fonoster/fonoster
|
|
@@ -19,17 +16,17 @@ exports.appendSpeech = void 0;
|
|
|
19
16
|
* See the License for the specific language governing permissions and
|
|
20
17
|
* limitations under the License.
|
|
21
18
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
19
|
+
/**
|
|
20
|
+
* The knowledge port (rework-autopilot A8): one operation, find what is relevant to a question.
|
|
21
|
+
* Implementations (S3 + Unstructured today) are wired by the operator; their keys never live in
|
|
22
|
+
* the agent config.
|
|
23
|
+
*/
|
|
24
|
+
export interface KnowledgePort {
|
|
25
|
+
find(question: string, signal: AbortSignal): Promise<string>;
|
|
26
|
+
}
|
|
27
|
+
/** Knowledge lookups never hold a reply back longer than this. */
|
|
28
|
+
export declare const KNOWLEDGE_TIMEOUT_MS = 800;
|
|
29
|
+
/** Adapts the current knowledge bases (mods/autopilot/src/knowledge) to the port. */
|
|
30
|
+
export declare function fromKnowledgeBase(kb: {
|
|
31
|
+
queryKnowledgeBase(query: string, k?: number): Promise<string>;
|
|
32
|
+
}): KnowledgePort;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KNOWLEDGE_TIMEOUT_MS = void 0;
|
|
4
|
+
exports.fromKnowledgeBase = fromKnowledgeBase;
|
|
5
|
+
/** Knowledge lookups never hold a reply back longer than this. */
|
|
6
|
+
exports.KNOWLEDGE_TIMEOUT_MS = 800;
|
|
7
|
+
/** Adapts the current knowledge bases (mods/autopilot/src/knowledge) to the port. */
|
|
8
|
+
function fromKnowledgeBase(kb) {
|
|
9
|
+
return { find: (question) => kb.queryKnowledgeBase(question) };
|
|
10
|
+
}
|